Last active
March 11, 2016 18:11
-
-
Save SpotlightKid/aae3293f1a30ee21f04c to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
# ntppeerstats.py | |
# | |
# Copyright 2016 Christopher Arndt <chris- at- chrisarndt -dot- de> | |
# | |
"""Get NTP daemon peer statistics and graph time offsets. | |
Documentation of the file format: | |
http://doc.ntp.org/current-stable/monopt.html | |
Documentation about the Modified Julian Date used there: | |
http://tycho.usno.navy.mil/mjd.html | |
To prepare the peerstats files as written out by the NTP server | |
and and left by logrotation to one big input file for this script: | |
$ rsync -rv --update example.com:/var/log/ntpstats/ . | |
$ zcat peerstats.*.gz | cat - peerstats.???????? peerstats | \ | |
sort -n > peerstats-all | |
""" | |
from __future__ import print_function, unicode_literals | |
import argparse | |
import logging | |
import sys | |
import time | |
from collections import namedtuple | |
from datetime import datetime, timedelta | |
import pandas as pd | |
from matplotlib import pyplot as pl | |
# https://gist.github.com/jiffyclub/1294443 | |
from jdutil import mjd_to_jd, jd_to_date | |
log = logging.getLogger('ntppeerstats') | |
Peerstat = namedtuple("Peerstat", | |
"timestamp day seconds address status offset delay dispersion skew") | |
types = (int, float, str, lambda x: int(x, 16), float, float, float, float) | |
def mjd_seconds_to_dt(mjd, seconds): | |
year, month, day = jd_to_date(mjd_to_jd(mjd)) | |
return (datetime(year, month, int(day)) + timedelta(seconds=seconds)) | |
def read_peerstats(filename): | |
with open(filename) as fp: | |
for lineno, line in enumerate(fp): | |
values = [f(x) for f, x in zip(types, line.strip().split())] | |
try: | |
timestamp = mjd_seconds_to_dt(values[0], values[1]) | |
except: | |
log.exception("Could not parse date on line %i: day=%i, " | |
"seconds=%f", lineno, values[0], values[1]) | |
timestamp = None | |
stat = Peerstat(*[timestamp] + values) | |
yield stat | |
def main(args=None): | |
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) | |
ap.add_argument('-v', '--verbose', action="store_true", | |
help="Be verbose") | |
ap.add_argument('peerstats', default="/var/log/ntpstats/peerstats", | |
help="Path of peerstats file") | |
args = ap.parse_args(args if args is not None else sys.argv[1:]) | |
logging.basicConfig(format="%(levelname)s: %(message)s", | |
level=logging.DEBUG if args.verbose else logging.INFO) | |
s = time.time() | |
peerstats = read_peerstats(args.peerstats) | |
ps = pd.DataFrame.from_records(peerstats, columns=Peerstat._fields) | |
d = time.time() - s | |
log.debug("Read peerstats in %0.4f sec." % d) | |
#ps.info() | |
#print() | |
print(ps[['offset', 'delay', 'dispersion', 'skew']].describe()) | |
ax = pl.gca() | |
for _, group in ps.groupby('address'): | |
group.plot(x='timestamp', y='offset', ax=ax) | |
pl.show() | |
if __name__ == '__main__': | |
sys.exit(main(sys.argv[1:]) or 0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment