chrony.chart.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # -*- coding: utf-8 -*-
  2. # Description: chrony netdata python.d module
  3. # Author: Dominik Schloesser (domschl)
  4. # SPDX-License-Identifier: GPL-3.0-or-later
  5. from bases.FrameworkServices.ExecutableService import ExecutableService
  6. # default module values (can be overridden per job in `config`)
  7. update_every = 5
  8. priority = 60000
  9. # charts order (can be overridden if you want less charts, or different order)
  10. ORDER = ['system', 'offsets', 'stratum', 'root', 'frequency', 'residualfreq', 'skew']
  11. CHARTS = {
  12. 'system': {
  13. 'options': [None, 'Chrony System Time Deltas', 'microseconds', 'system', 'chrony.system', 'area'],
  14. 'lines': [
  15. ['timediff', 'system time', 'absolute', 1, 1000]
  16. ]
  17. },
  18. 'offsets': {
  19. 'options': [None, 'Chrony System Time Offsets', 'microseconds', 'system', 'chrony.offsets', 'area'],
  20. 'lines': [
  21. ['lastoffset', 'last offset', 'absolute', 1, 1000],
  22. ['rmsoffset', 'RMS offset', 'absolute', 1, 1000]
  23. ]
  24. },
  25. 'stratum': {
  26. 'options': [None, 'Chrony Stratum', 'stratum', 'root', 'chrony.stratum', 'line'],
  27. 'lines': [
  28. ['stratum', None, 'absolute', 1, 1]
  29. ]
  30. },
  31. 'root': {
  32. 'options': [None, 'Chrony Root Delays', 'milliseconds', 'root', 'chrony.root', 'line'],
  33. 'lines': [
  34. ['rootdelay', 'delay', 'absolute', 1, 1000000],
  35. ['rootdispersion', 'dispersion', 'absolute', 1, 1000000]
  36. ]
  37. },
  38. 'frequency': {
  39. 'options': [None, 'Chrony Frequency', 'ppm', 'frequencies', 'chrony.frequency', 'area'],
  40. 'lines': [
  41. ['frequency', None, 'absolute', 1, 1000]
  42. ]
  43. },
  44. 'residualfreq': {
  45. 'options': [None, 'Chrony Residual frequency', 'ppm', 'frequencies', 'chrony.residualfreq', 'area'],
  46. 'lines': [
  47. ['residualfreq', 'residual frequency', 'absolute', 1, 1000]
  48. ]
  49. },
  50. 'skew': {
  51. 'options': [None, 'Chrony Skew, error bound on frequency', 'ppm', 'frequencies', 'chrony.skew', 'area'],
  52. 'lines': [
  53. ['skew', None, 'absolute', 1, 1000]
  54. ]
  55. }
  56. }
  57. CHRONY = [
  58. ('Frequency', 'frequency', 1e3),
  59. ('Last offset', 'lastoffset', 1e9),
  60. ('RMS offset', 'rmsoffset', 1e9),
  61. ('Residual freq', 'residualfreq', 1e3),
  62. ('Root delay', 'rootdelay', 1e9),
  63. ('Root dispersion', 'rootdispersion', 1e9),
  64. ('Skew', 'skew', 1e3),
  65. ('Stratum', 'stratum', 1),
  66. ('System time', 'timediff', 1e9)
  67. ]
  68. class Service(ExecutableService):
  69. def __init__(self, configuration=None, name=None):
  70. ExecutableService.__init__(
  71. self, configuration=configuration, name=name)
  72. self.command = 'chronyc -n tracking'
  73. self.order = ORDER
  74. self.definitions = CHARTS
  75. def _get_data(self):
  76. """
  77. Format data received from shell command
  78. :return: dict
  79. """
  80. raw_data = self._get_raw_data()
  81. if not raw_data:
  82. return None
  83. raw_data = (line.split(':', 1) for line in raw_data)
  84. parsed, data = dict(), dict()
  85. for line in raw_data:
  86. try:
  87. key, value = (l.strip() for l in line)
  88. except ValueError:
  89. continue
  90. if value:
  91. parsed[key] = value.split()[0]
  92. for key, dim_id, multiplier in CHRONY:
  93. try:
  94. data[dim_id] = int(float(parsed[key]) * multiplier)
  95. except (KeyError, ValueError):
  96. continue
  97. return data or None