ovpn_status_log.chart.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. # -*- coding: utf-8 -*-
  2. # Description: openvpn status log netdata python.d module
  3. # Author: l2isbad
  4. from re import compile as r_compile
  5. from bases.FrameworkServices.SimpleService import SimpleService
  6. priority = 60000
  7. retries = 60
  8. update_every = 10
  9. ORDER = ['users', 'traffic']
  10. CHARTS = {
  11. 'users': {
  12. 'options': [None, 'OpenVPN Active Users', 'active users', 'users', 'openvpn_status.users', 'line'],
  13. 'lines': [
  14. ['users', None, 'absolute'],
  15. ]},
  16. 'traffic': {
  17. 'options': [None, 'OpenVPN Traffic', 'KB/s', 'traffic', 'openvpn_status.traffic', 'area'],
  18. 'lines': [
  19. ['bytes_in', 'in', 'incremental', 1, 1 << 10], ['bytes_out', 'out', 'incremental', 1, -1 << 10]
  20. ]},
  21. }
  22. class Service(SimpleService):
  23. def __init__(self, configuration=None, name=None):
  24. SimpleService.__init__(self, configuration=configuration, name=name)
  25. self.order = ORDER
  26. self.definitions = CHARTS
  27. self.log_path = self.configuration.get('log_path')
  28. self.regex = dict(tls=r_compile(r'\d{1,3}(?:\.\d{1,3}){3}(?::\d+)? (?P<bytes_in>\d+) (?P<bytes_out>\d+)'),
  29. static_key=r_compile(r'TCP/[A-Z]+ (?P<direction>(?:read|write)) bytes,(?P<bytes>\d+)'))
  30. def check(self):
  31. if not (self.log_path and isinstance(self.log_path, str)):
  32. self.error("'log_path' is not defined")
  33. return False
  34. data = self._get_raw_data()
  35. if not data:
  36. self.error('Make sure that the openvpn status log file exists and netdata has permission to read it')
  37. return None
  38. found = None
  39. for row in data:
  40. if 'ROUTING' in row:
  41. self.get_data = self.get_data_tls
  42. found = True
  43. break
  44. elif 'STATISTICS' in row:
  45. self.get_data = self.get_data_static_key
  46. found = True
  47. break
  48. if found:
  49. return True
  50. self.error("Failed to parse ovpenvpn log file")
  51. return False
  52. def _get_raw_data(self):
  53. """
  54. Open log file
  55. :return: str
  56. """
  57. try:
  58. with open(self.log_path) as log:
  59. raw_data = log.readlines() or None
  60. except OSError:
  61. return None
  62. else:
  63. return raw_data
  64. def get_data_static_key(self):
  65. """
  66. Parse openvpn-status log file.
  67. """
  68. raw_data = self._get_raw_data()
  69. if not raw_data:
  70. return None
  71. data = dict(bytes_in=0, bytes_out=0)
  72. for row in raw_data:
  73. match = self.regex['static_key'].search(row)
  74. if match:
  75. match = match.groupdict()
  76. if match['direction'] == 'read':
  77. data['bytes_in'] += int(match['bytes'])
  78. else:
  79. data['bytes_out'] += int(match['bytes'])
  80. return data or None
  81. def get_data_tls(self):
  82. """
  83. Parse openvpn-status log file.
  84. """
  85. raw_data = self._get_raw_data()
  86. if not raw_data:
  87. return None
  88. data = dict(users=0, bytes_in=0, bytes_out=0)
  89. for row in raw_data:
  90. row = ' '.join(row.split(',')) if ',' in row else ' '.join(row.split())
  91. match = self.regex['tls'].search(row)
  92. if match:
  93. match = match.groupdict()
  94. data['users'] += 1
  95. data['bytes_in'] += int(match['bytes_in'])
  96. data['bytes_out'] += int(match['bytes_out'])
  97. return data or None