Skip to main content

TUI monitor of latency and availability to servers by country

Project description

pingmon

A full-featured terminal UI for monitoring latency and availability to servers in different countries. Built with Textual.

It continuously TCP-pings a set of targets (one or more reachable hosts per country), and shows a live, colour-coded dashboard with per-target latency, average, jitter, packet loss, a status indicator, and an animated trend graph.

pingmon screenshot

Features

  • Live dashboard — sortable table of targets with status dot, latency, average, loss and an inline coloured sparkline trend.
  • Detail panel — for the selected target: live latency graph, quality gauge, min / max / avg / jitter / loss, MOS call-quality score, resolved IP, GeoIP city / region and the hosting network (ASN + ISP), sample count.
  • ★ Region Advisor (unique) — ranks regions by a composite 0–100 score under a chosen use-case profile (VoIP / Gaming / Web / Bulk) and highlights the best region to pick right now. Press g. See below.
  • MOS / R-factor — turns latency + jitter + loss into the single VoIP call-quality number (ITU-T E-model), the same metric paid monitoring suites charge for.
  • Threshold alerts — fire when a target stays slow or lossy for N samples: terminal bell, an in-app toast, an OS desktop notification, and a blinking row marker. Auto-clears on recovery.
  • Traceroute drill-down — press Enter (or click) on a row for an mtr-style hop-by-hop path with per-hop loss and per-probe timings, plus GeoIP per hop (country code, city and ASN) so you can see which countries and networks the traffic crosses.
  • Per-country set, ready to go — the Netherlands, Germany, United Kingdom, France, Cyprus, Italy, Spain, Greece, Sweden, Ireland and the United States are pre-configured with reachable hosts.
  • Editable targets — add (a), edit (E) and delete (d) targets right inside the TUI, or edit the TOML config by hand; reset stats with r. In-app changes are saved to the config immediately.
  • GeoIP auto-detect & enrichment — every target is looked up via ip-api.com: the detail panel shows its city, region and hosting network (ASN + ISP), and when you add a target with country/code left blank they are filled in automatically.
  • Works in every terminal — each country is shown as its two-letter code (NL, DE, US), not a flag emoji. Many terminals (iTerm2 among them) can't render regional-indicator flags and fall back to two boxed letters; the code is always legible.
  • Show filter — flip the table between all, mine only (targets you added) and others only (the built-in set) with f.
  • No root required — uses TCP connect timing (port 443/80), so it works without raw-socket / ICMP privileges and measures real service latency.
  • Modern terminal UX — truecolor, mouse support, zebra-striped table, a live "heartbeat" spinner, keyboard and mouse navigation, sort modes and modal dialogs.
Region Advisor Traceroute drill-down
advisor traceroute

Requirements

  • Python 3.11+ (not needed for the standalone binary below)
  • textual >= 0.80 (installed automatically)

Install as a system command

Use it like htop — install once, run pingmon from anywhere.

pipx / uv (recommended, Linux + macOS)

pipx install pingmonitor                 # from PyPI
pipx install .                           # or from a checkout of this repo
pipx install git+https://github.com/kottot13/pingmon
# uv works the same:  uv tool install pingmonitor   /   uvx --from pingmonitor pingmon

The PyPI package is pingmonitor; it installs the pingmon command. pipx keeps it in its own isolated environment and puts pingmon on your PATH. Then just run pingmon.

Homebrew (macOS / Linuxbrew)

A formula skeleton lives in packaging/pingmon.rb. Publish to PyPI, fill in the sdist URL + brew update-python-resources, then:

brew install kottot13/tap/pingmon

Standalone binary (no Python on the target)

The most htop-like option — a single executable built with PyInstaller (packaging/pingmon.spec):

pip install pyinstaller
pyinstaller packaging/pingmon.spec
sudo cp dist/pingmon /usr/local/bin/     # macOS
cp dist/pingmon ~/.local/bin/            # Linux

Build once per OS/architecture (PyInstaller does not cross-compile).

From source (development)

./run.sh                # makes a local venv, installs Textual, launches
# or
python3 -m venv .venv && .venv/bin/pip install -e . && .venv/bin/pingmon

Config lives at ~/.config/pingmon/config.toml by default (or a local ./config.toml if present, or $PINGMON_CONFIG). Run pingmon --help for the CLI flags (-V/--version, -c/--config PATH).

Keys

Key Action
↑ / ↓, j/k Move selection
Enter Traceroute drill-down for the selected target
g Open the Region Advisor ([ ] / p switch profile inside)
p Cycle the Advisor profile (VoIP / Gaming / Web / Bulk)
f Cycle the show filter (all / mine only / others only)
space Pause / resume probing
m / M Sort by latency (ms); press again to flip fastest ⇄ slowest first
s Cycle sort (country / latency / loss / jitter)
a Add a target
E Edit the selected target (form pre-filled)
A Toggle the alert system on / off
d Delete the selected target
r Reset all statistics
e Show the config file path
q Quit

Region Advisor

The Advisor (g) answers the question the tool was born from — which region should I actually pick right now? It computes a 0–100 score per region from latency, jitter and loss, under a selectable profile:

Profile What it optimises for
VoIP / Video call jitter & loss dominate; driven by the MOS / E-model score
Gaming raw latency + jitter, loss punished hard
Web / API latency-led, mild loss penalty
Bulk / Backup loss-led, tolerant of high latency

Regions are ranked best-first with the #1 pick highlighted, each with a score bar, a letter grade (A–F) and a one-line reason. Switch profile with [ / ], p or Tab; close with Esc.

Alerts

A target enters alert state when, for alert_window consecutive samples, it is unreachable, slower than alert_latency ms, or its recent loss exceeds alert_loss %. On entry pingmon rings the terminal bell, shows a toast, raises an OS desktop notification (macOS osascript / Linux notify-send, toggle with desktop_notify) and blinks the row's status marker; it auto-clears with a "Recovered" toast. Press A to switch the whole alert system off or on at any time (the banner shows ⚲ alerts off while disabled); tune or permanently disable the triggers in config.toml.

Status colours

Status Meaning (last sample)
EXCELLENT < 40 ms
GOOD < 90 ms
FAIR < 180 ms
POOR < 350 ms / ≥ 350 ms
UNSTABLE loss ≥ 20% or a recent drop
DOWN 3+ consecutive failures
PENDING no samples yet

Configuration

On first run a config.toml is created at ~/.config/pingmon/config.toml (or wherever $PINGMON_CONFIG / --config points). The location does not depend on your current directory, so targets you add in-app are always reloaded from the same file no matter where you launch pingmon. It is plain TOML and meant to be hand-edited:

interval = 2.0        # poll period per target, seconds
timeout  = 2.0        # TCP connect timeout, seconds
history  = 90         # samples kept in memory for the graph

alert_latency = 300.0 # alert if latency stays above this (ms); 0 disables
alert_loss    = 20.0  # alert if recent loss exceeds this (%); 0 disables
alert_window  = 3     # consecutive bad samples before an alert fires
desktop_notify = true # also raise an OS desktop notification on alert

[[targets]]
country = "Netherlands"
flag = "🇳🇱"
host = "speedtest.ams1.nl.leaseweb.net"
port = 80
source = "builtin"   # "builtin" (shipped) or "user" (added in-app) — drives the `f` filter

[[targets]]
country = "United States"
flag = "🇺🇸"
host = "speedtest.newark.linode.com"
port = 443
source = "builtin"

Add as many [[targets]] blocks as you like; any host or IP works, and the port is per-target. source is optional — if omitted it is inferred (hosts in the built-in set are builtin, everything else user). flag is optional too: the UI shows the two-letter country code derived from it, so you can leave it out and let GeoIP fill it in. When adding a target in-app, the country field accepts a plain code like PL.

How latency is measured

pingmon opens a TCP connection to host:port and times the round-trip of the connection handshake (SYN → SYN/ACK). That is close to true network RTT and, unlike ICMP, needs no elevated privileges and reflects whether the service port is actually answering. Failed or timed-out connects count as packet loss.

Project layout

pingmon/
  app.py      # Textual app: table, detail panel, graphs, advisor, alerts, actions
  pinger.py   # async TCP ping + DNS resolve
  stats.py    # rolling per-target stats (latency, jitter, loss, MOS, status)
  scoring.py  # Region Advisor: composite score + use-case profiles
  netutil.py  # async traceroute + OS desktop notifications
  render.py   # colours, status meta, text sparklines
  config.py   # TOML load/save + built-in per-country target set
  app.tcss    # dark theme / layout

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pingmonitor-1.1.0.tar.gz (58.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pingmonitor-1.1.0-py3-none-any.whl (28.3 kB view details)

Uploaded Python 3

File details

Details for the file pingmonitor-1.1.0.tar.gz.

File metadata

  • Download URL: pingmonitor-1.1.0.tar.gz
  • Upload date:
  • Size: 58.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for pingmonitor-1.1.0.tar.gz
Algorithm Hash digest
SHA256 252fd1f90c083865dc2af20fb064a211ecc6d1d62d706ae1e6e303f391fa36a3
MD5 6e6eb1faa3efc04c6e8888a40c2de542
BLAKE2b-256 6af1d62f9998714768a527d7e82b7dda9df23866bcdacff9156a0bda4fbf86f5

See more details on using hashes here.

File details

Details for the file pingmonitor-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: pingmonitor-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 28.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for pingmonitor-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 122e54d90c858ce1695ecd591fb39e360320875fcee4338558ad09465671a096
MD5 2fa4c8dc1790ffa9e36c7fb5ad254c86
BLAKE2b-256 5ec2856299292b130796be962632ba688783b58bdbd97cef7d5a53e3acb80b89

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page