Skip to main content

Multi-host ping monitor with a rich static HTML report.

Project description

emping

Ping many hosts at once and produce a rich, self-contained HTML report, all built to deliver a nice report and a clean, reusable Python API.

emping is both:

  • a library you can drop into other projects (from emping import Monitor), and
  • a CLI app (emping 8.8.8.8 1.1.1.1 -c 10).

Highlights

  • Auto-selecting ping backend. Uses unprivileged ICMP datagram sockets when the OS allows (macOS, modern Linux) for precise RTT/TTL, and falls back to the system ping command otherwise (Windows, locked-down Linux). No root required in the common case. IPv4 and IPv6 are supported.
  • Continuous or fixed-count monitoring, on a steady cadence. Built for network migrations where minutes or hours of downtime needs to be monitored and recorded.
  • A report that's clear: summary cards (up/degraded/down, overall loss, average & slowest host), click-to-sort columns (numeric-aware), a live text filter, color-coded health, per-host latency sparklines with packet-loss ticks, and light/dark themes. All grafted into a single .html file that works offline and is easy to distribute.

Install

pip install emping

Or from a checkout of this repository:

pip install -e .          # editable install, from this directory

CLI usage

# Fixed count: 5 pings per host, then write the report and exit
emping 8.8.8.8 1.1.1.1 9.9.9.9 -c 5 -o report.html

# Continuous monitoring until Ctrl-C, updating the report as it goes
emping -f hosts.json --interval 2 -o report.html --open

# Read targets (with descriptions) from a file, auto-refresh the report in-browser
emping -f hosts.json --refresh 5 -o report.html

Without installing, use python -m emping ….

Key options

Option Meaning Default
hosts … targets to ping (positional)
-f, --file read targets from a JSON file
-i, --interval seconds between rounds 1.0
-c, --count pings per host; 0 = continuous until Ctrl-C 0
-t, --timeout per-ping timeout (seconds) 1.0
-o, --output HTML report path ping_report.html
--backend auto | socket | subprocess auto
--refresh embed an auto-refresh (seconds) in the report 0 (off)
--report-every min seconds between report writes while running 2.0
--workers max concurrent pings min(hosts, 64)
--open open the report in a browser after first write off
-q, --quiet suppress per-round console output off

Targets file format

-f/--file reads targets from a JSON file:

{
  "hosts": [
    { "host": "8.8.8.8", "description": "Google DNS" },
    { "host": "192.0.2.1", "description": "Lab gateway", "site": "sto1" },
    "one.one.one.one"
  ]
}

Schema:

top level an object with a hosts array, or the array on its own
entry a string (the host), or an object
host required, string — address or DNS name
description optional, string — shown in the report (default "")
other keys ignored, so the file can double as an inventory carrying site, owner, ticket refs, etc.

Anything malformed — bad JSON, a missing host, a non-string value — exits 2 with a message naming the offending entry, e.g. hosts[3]: object entry is missing the required 'host' key. A full example is in hosts.example.json.

Run mode is chosen with -c: give a count for a batch run, or omit it (or pass 0) for continuous monitoring. Continuous runs update the report periodically and always write a final report on Ctrl-C.

Library usage

from emping import Monitor, Host, write_report, ReportMeta

monitor = Monitor(
    [Host("8.8.8.8", "Google DNS"), Host("1.1.1.1", "Cloudflare")],
    interval=1.0,
    count=10,          # 0 for continuous; call monitor.stop() from another thread
    timeout=1.0,
)
snapshots = monitor.run()                       # blocks; returns list[HostSnapshot]
write_report("report.html", snapshots, ReportMeta(title="My Report"))

For live/streaming use, pass callbacks:

def on_round(round_num, snapshots):
    write_report("report.html", snapshots)      # atomic write, safe to re-read live

Monitor(hosts, count=0, on_round=on_round,
        on_result=lambda i, r: print(r.host, r.rtt_ms)).run()

Targets files are loadable directly, without going through the CLI:

from emping import load_hosts, HostFileError

try:
    hosts = load_hosts("hosts.json")        # -> list[Host]; fmt="json"|"text" to force
except HostFileError as exc:
    ...                                     # malformed file; OSError if unreadable

Lower-level pieces are exported too: get_pinger(), PingResult, HostStats, render_report(), build_sparkline(), parse_hosts_json().

How pinging works (and privileges)

get_pinger(backend="auto") probes for an unprivileged ICMP datagram socket:

  • socket backendSOCK_DGRAM + IPPROTO_ICMP/IPPROTO_ICMPV6. Precise RTT and TTL. Works without root on macOS/BSD and on Linux where net.ipv4.ping_group_range permits it. Reply parsing is platform-aware (macOS includes the IP header, Linux strips it; TTL comes from the header or recvmsg ancillary data).
  • subprocess backend — shells out to the system ping. The portable fallback (Windows, locked-down Linux). TTL/reply-IP are parsed from the output.

Force one with --backend socket / --backend subprocess.

Known limitation

On macOS, the kernel does not deliver loopback (127.0.0.1 / ::1) ICMP replies to unprivileged datagram sockets — even the system ping shows no reply line. Loopback isn't a realistic monitoring target, but if you must ping it on macOS, use --backend subprocess (which still returns exit status) or expect it to read as "down". Remote hosts are unaffected.

Testing

The package uses a src/ layout, so install it before running the tests — pytest from the repository root will not otherwise find it.

pip install -e ".[dev]"
pytest -q          # run unit tests (stats, report, parsing, checksum)

Building a release

pip install build twine
python -m build            # writes dist/*.whl and dist/*.tar.gz
twine check dist/*

Project layout

pyproject.toml
LICENSE
README.md
src/emping/
  pinger.py    # ICMP datagram + subprocess backends, auto-selection
  stats.py     # HostStats accumulator + immutable HostSnapshot
  hosts.py     # JSON targets file loading + validation
  monitor.py   # fixed-cadence, concurrent multi-host ping loop
  report.py    # self-contained HTML rendering (Jinja2), atomic writes
  cli.py       # argparse CLI
  templates/report.html.j2
tests/test_emping.py

License

MIT.

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

emping-0.1.0.tar.gz (28.2 kB view details)

Uploaded Source

Built Distribution

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

emping-0.1.0-py3-none-any.whl (25.9 kB view details)

Uploaded Python 3

File details

Details for the file emping-0.1.0.tar.gz.

File metadata

  • Download URL: emping-0.1.0.tar.gz
  • Upload date:
  • Size: 28.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for emping-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2596d644dd058e22fa9de6b4b7dbbbf117aac3f4056022d4d6d7f5c0561eab74
MD5 48af1e0ca913fc4af44d2ddd43c5eadb
BLAKE2b-256 ea5c7df2c5381dbed020a82bcc77a6cfddeec4d0cbb51f6de047c396fb6df03b

See more details on using hashes here.

File details

Details for the file emping-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: emping-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for emping-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0ae70b2896e397248bfd8afe5588b3ef4d179326dde922972e5d5c81e93fb7e9
MD5 fad5e598623864056767d3cac483b6aa
BLAKE2b-256 39bf1f431837c50b39e328c8125a33ec22d79b7548717893e4af21ad09736553

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