chrony.chart.py 3.5 KB

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