123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- #!@PYSHEBANG@
- # @GENERATED@
- #
- # This file is Copyright 2010 by the GPSD project
- # SPDX-License-Identifier: BSD-2-clause
- #
- # This code runs compatibly under Python 2 and 3.x for x >= 2.
- # Preserve this property!
- # Codacy D203 and D211 conflict, I choose D203
- # Codacy D212 and D213 conflict, I choose D212
- """
- ntpshmviz - graph the drift of NTP servers
- Written by Keane Wolter <daemoneye2@gmail.com>
- """
- #
- # To do:
- #
- # 1. Add exit button so the user does not need to do <Ctrl>-w
- # 2. Allow for a continuous stream of data to be graphed
- from __future__ import absolute_import, print_function, division
- import argparse
- import sys
- try:
- import matplotlib.pyplot as PLT
- except ImportError:
- print("Please make sure matplotlib is installed properly:",
- sys.exc_info()[0])
- sys.exit(1)
- gps_version = '@VERSION@'
- ns_per_s = 1e9
- class ntpOffset(object):
- """The master Class."""
- def __init__(self, stream):
- """Initialize class ntpOffset."""
- # get the data
- self.read_data(stream)
- # display the data
- self.display()
- def display(self):
- """Display the graphs."""
- # Alert the user that closing the graphs can be done with "Ctrl-w"
- print("Please note that the graph can be closed with the "
- "key combination of <Ctrl-w>")
- PLT.figure()
- subplot_value = 211
- for ntp_item in self.ntp_data:
- # create the subplot for the data
- PLT.subplot(subplot_value)
- # setup and create the vlines graph
- t = range(0, self.line_counts[ntp_item], 1)
- PLT.vlines(t, 0, self.ntp_data[ntp_item], color='r')
- # add labels
- PLT.title("NTP drift for " + ntp_item)
- PLT.xlabel('sample')
- PLT.ylabel('drift')
- # increment the subplot by 1.
- # this allows for each data group to have it's own graph
- subplot_value += 1
- # make sure there is no graph or data overlapping each other and
- # display the graph
- PLT.tight_layout()
- PLT.show()
- def read_data(self, stream):
- """Read data from a ntp log file."""
- # Layout is:
- #
- # - The keyword "sample"
- # - The NTP unit from which it was collected.
- # - Collection time of day, expressed in seconds
- # - Receiver time of day, expressed in seconds
- # - Clock time of day, expressed in seconds
- # - Leep-second notification status
- # - Source precision (log(2) of source jitter)
- self.ntp_data = {} # data sets for each ntp unit
- self.line_counts = {} # Count of total lines for each ntp unit
- record = [] # A single record in the file or data stream
- offset = 0 # offset value to add to the array
- self.lines = 0 # width of graph
- for line in stream:
- line = line.lstrip()
- record = line.split()
- if len(record) > 6 and line[0] != '#':
- try:
- then = record[3].split('.')
- nows = record[4].split('.')
- offset = (int(then[0]) - int(nows[0])) * ns_per_s
- offset += (int(then[1]) - int(nows[1]))
- offset /= float(ns_per_s)
- except Exception:
- print("Invalid data: ", sys.exc_info()[0],
- ". Data was: ", line)
- continue
- # If the NTP unit is in the dictionary
- # append the offset to the list
- # Otherwise, create a new list in the dictionary
- # and add the offset.
- if record[1] not in self.ntp_data:
- self.ntp_data[record[1]] = []
- self.line_counts[record[1]] = 0
- self.ntp_data[record[1]].append(offset)
- self.line_counts[record[1]] += 1
- stream.close()
- def args():
- """Handle command line args."""
- parser = argparse.ArgumentParser(description='NTP drift visualizer')
- parser.add_argument('-V', '--version',
- action='version',
- help='Get version of GPS project',
- version="ntpshmviz: version"+str(gps_version))
- return parser.parse_args()
- if __name__ == "__main__":
- if len(sys.argv) >= 2:
- arguments = args()
- ntpOffset(sys.stdin)
- sys.exit()
|