chrony.chart.py 3.6 KB

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