Created
January 29, 2019 12:32
-
-
Save akiross/dfd03416bcb8e12f990354a069be0b57 to your computer and use it in GitHub Desktop.
A simple bokeh app to plot ping to some hosts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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