Skip to content

Instantly share code, notes, and snippets.

@akiross
Created January 29, 2019 12:32
Show Gist options
  • Save akiross/dfd03416bcb8e12f990354a069be0b57 to your computer and use it in GitHub Desktop.
Save akiross/dfd03416bcb8e12f990354a069be0b57 to your computer and use it in GitHub Desktop.
A simple bokeh app to plot ping to some hosts
#!/bin/env python3
# A simple bokeh app to plot ping to some hosts
# Run this program with:
# bokeh server --show minimon.py --args host1 host2 host3
# MIT Licensed
import re
import time
import select
import argparse
import itertools
import subprocess
from bokeh.core.properties import value
from bokeh.plotting import figure, show, curdoc
from bokeh.palettes import Dark2_5 as palette
from bokeh.models import ColumnDataSource
def setup_args():
parser = argparse.ArgumentParser()
parser.add_argument('hosts', nargs='+', help='Hosts to ping')
return parser.parse_args()
def main():
args = setup_args()
data = {'tick': []}
reads = {}
hosts = set()
for host in args.hosts:
# -n numeric only: no DNS lookup
proc = subprocess.Popen(['ping', '-n', host], stdout=subprocess.PIPE)
fd = proc.stdout.fileno()
reads[fd] = (host, proc)
data[host] = [] # Setup initial data for this host
# Setup plot
src = ColumnDataSource(data=data)
p = figure()
colors = itertools.cycle(palette)
for host, col in zip(args.hosts, colors):
p.line(x='tick', y=host, legend=value(host), color=col, source=src)
p.legend.location = 'top_left'
p.legend.click_policy = 'hide'
# Add plot to current root
curdoc().add_root(p)
# Conversion table for time units
timeunit = {
'ms': 1,
'msec': 1,
's': 1000,
'sec': 1000,
}
ticks = 0
def update():
nonlocal ticks, reads
hosts = set(args.hosts)
# Updated data
data = {'tick': [ticks]}
# Get ready read descriptors
readable, _, _ = select.select(reads.keys(), [], [])
read = set()
for fd in readable:
host, proc = reads[fd]
row = proc.stdout.readline().decode()
if row.startswith('PING'):
continue
read.add(host)
# icmp_seq = re.search(r'icmp_seq=(\d+)', row).group(1)
time = re.search(r'time=(\d+\.\d+|\d+)\s+(ms|s)$', row)
time = time.group(1) * timeunit[time.group(2)]
#src.stream({'icmp_seq': [icmp_seq], host: [time]})
data[host] = [time]
# Set data for missing hosts
for host in hosts - read:
data[host] = [-1]
src.stream(data)
ticks += 1
return update
update = main()
curdoc().add_periodic_callback(update, 1000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment