Statistics for precision of local chrony
Dominik Schloesser committed
Aug 27, 2017 at 18:27 UTC
244918fa4659082141ada17f799f708fad71c625
2 files changed
+166
conf.d/python.d/chrony.conf
new
+72
@@ -0,0 +1,72 @@
1
+# netdata python.d.plugin configuration for chrony
2
+#
3
+# This file is in YaML format. Generally the format is:
4
+#
5
+# name: value
6
+#
7
+# There are 2 sections:
8
+# - global variables
9
+# - one or more JOBS
10
+#
11
+# JOBS allow you to collect values from multiple sources.
12
+# Each source will have its own set of charts.
13
+#
14
+# JOB parameters have to be indented (using spaces only, example below).
15
+
16
+# ----------------------------------------------------------------------
17
+# Global Variables
18
+# These variables set the defaults for all JOBs, however each JOB
19
+# may define its own, overriding the defaults.
20
+
21
+# update_every sets the default data collection frequency.
22
+# If unset, the python.d.plugin default is used.
23
+update_every: 1
24
+
25
+# priority controls the order of charts at the netdata dashboard.
26
+# Lower numbers move the charts towards the top of the page.
27
+# If unset, the default for python.d.plugin is used.
28
+# priority: 60000
29
+
30
+# retries sets the number of retries to be made in case of failures.
31
+# If unset, the default for python.d.plugin is used.
32
+# Attempts to restore the service are made once every update_every
33
+# and only if the module has collected values in the past.
34
+# retries: 5
35
+
36
+# ----------------------------------------------------------------------
37
+# JOBS (data collection sources)
38
+#
39
+# The default JOBS share the same *name*. JOBS with the same name
40
+# are mutually exclusive. Only one of them will be allowed running at
41
+# any time. This allows autodetection to try several alternatives and
42
+# pick the one that works.
43
+#
44
+# Any number of jobs is supported.
45
+#
46
+# All python.d.plugin JOBS (for all its modules) support a set of
47
+# predefined parameters. These are:
48
+#
49
+# job_name:
50
+# name: myname # the JOB's name as it will appear at the
51
+# # dashboard (by default is the job_name)
52
+# # JOBs sharing a name are mutually exclusive
53
+# update_every: 1 # the JOB's data collection frequency
54
+# priority: 60000 # the JOB's order on the dashboard
55
+# retries: 5 # the JOB's number of restoration attempts
56
+#
57
+# Additionally to the above, chrony also supports the following:
58
+#
59
+# command: 'chrony tracking' # the command to run
60
+#
61
+
62
+# ----------------------------------------------------------------------
63
+# REQUIRED chrony CONFIGURATION
64
+#
65
+# netdata will query chrony as user netdata.
66
+# verify that user netdata is allowed to call 'chronyc tracking'
67
+# Check cmdallow in chrony.conf
68
+# ----------------------------------------------------------------------
69
+# AUTO-DETECTION JOBS
70
+
71
+local:
72
+ command: 'chronyc -n tracking'
python.d/chrony.chart.py
new
+94
@@ -0,0 +1,94 @@
1
+# -*- coding: utf-8 -*-
2
+# Description: chrony netdata python.d module
3
+# Author: Dominik Schloesser (domschl)
4
+
5
+from base import ExecutableService
6
+
7
+# default module values (can be overridden per job in `config`)
8
+# update_every = 10
9
+priority = 60000
10
+retries = 10
11
+
12
+# charts order (can be overridden if you want less charts, or different order)
13
+ORDER = ['timediff', 'lastoffset', 'rmsoffset', 'rootdelay',
14
+ 'rootdispersion', 'skew', 'frequency', 'residualfreq']
15
+
16
+CHARTS = {
17
+ # id: {
18
+ # 'options': [name, title, units, family, context, charttype],
19
+ # 'lines': [
20
+ # [unique_dimension_name, name, algorithm, multiplier, divisor]
21
+ # ]}
22
+ 'timediff': {
23
+ 'options': [None, "Difference system time to NTP", "us", 'chrony', 'chrony.timediff', 'line'],
24
+ 'lines': [
25
+ ['timediff', None, 'absolute', 1, 1000]
26
+ ]},
27
+ 'lastoffset': {
28
+ 'options': [None, "Last offset", "us", 'chrony', 'chrony.lastoffset', 'line'],
29
+ 'lines': [
30
+ ['lastoffset', None, 'absolute', 1, 1000]
31
+ ]},
32
+ 'rmsoffset': {
33
+ 'options': [None, "RMS offset", "us", 'chrony', 'chrony.rmsoffset', 'line'],
34
+ 'lines': [
35
+ ['rmsoffset', None, 'absolute', 1, 1000]
36
+ ]},
37
+ 'rootdelay': {
38
+ 'options': [None, "Root delay", "us", 'chrony', 'chrony.rootdelay', 'line'],
39
+ 'lines': [
40
+ ['rootdelay', None, 'absolute', 1, 1000]
41
+ ]},
42
+ 'rootdispersion': {
43
+ 'options': [None, "Root dispersion", "us", 'chrony', 'chrony.rootdispersion', 'line'],
44
+ 'lines': [
45
+ ['rootdispersion', None, 'absolute', 1, 1000]
46
+ ]},
47
+ 'skew': {
48
+ 'options': [None, "Skew, error bound on frequency", "ppm", 'chrony', 'chrony.skew', 'line'],
49
+ 'lines': [
50
+ ['skew', None, 'absolute', 1, 1000]
51
+ ]},
52
+ 'frequency': {
53
+ 'options': [None, "Frequency", "ppm", 'chrony', 'chrony.frequency', 'line'],
54
+ 'lines': [
55
+ ['frequency', None, 'absolute', 1, 1000]
56
+ ]},
57
+ 'residualfreq': {
58
+ 'options': [None, "Residual frequency", "ppm", 'chrony', 'chrony.residualfreq', 'line'],
59
+ 'lines': [
60
+ ['residualfreq', None, 'absolute', 1, 1000]
61
+ ]}
62
+}
63
+
64
+
65
+class Service(ExecutableService):
66
+ def __init__(self, configuration=None, name=None):
67
+ ExecutableService.__init__(
68
+ self, configuration=configuration, name=name)
69
+ self.command = "chronyc -n tracking"
70
+ self.order = ORDER
71
+ self.definitions = CHARTS
72
+ self.error("Chrony netdata started")
73
+
74
+ def _get_data(self):
75
+ """
76
+ Format data received from shell command
77
+ :return: dict
78
+ """
79
+ try:
80
+ # self.error("Chrony:" + self._get_raw_data())
81
+ chrony_dict = {ln.split(':', 1)[0].strip(): ln.split(':', 1)[1].strip().split(' ')[0]
82
+ for ln in self._get_raw_data()[1:]}
83
+ return {'timediff': int(float(chrony_dict['System time']) * 1e9),
84
+ 'lastoffset': int(float(chrony_dict['Last offset']) * 1e9),
85
+ 'rmsoffset': int(float(chrony_dict['RMS offset']) * 1e9),
86
+ 'rootdelay': int(float(chrony_dict['Root delay']) * 1e9),
87
+ 'rootdispersion': int(float(chrony_dict['Root dispersion']) * 1e9),
88
+ 'skew': int(float(chrony_dict['Skew']) * 1e3),
89
+ 'frequency': int(float(chrony_dict['Frequency']) * 1e3),
90
+ 'residualfreq': int(float(chrony_dict['Residual freq']) * 1e3)
91
+ }
92
+ except (ValueError, AttributeError):
93
+ self.error("Chrony parser exception")
94
+ return None