squid.chart.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. # -*- coding: utf-8 -*-
  2. # Description: squid netdata python.d module
  3. # Author: Pawel Krupa (paulfantom)
  4. # SPDX-License-Identifier: GPL-3.0-or-later
  5. from bases.FrameworkServices.SocketService import SocketService
  6. ORDER = [
  7. 'clients_net',
  8. 'clients_requests',
  9. 'servers_net',
  10. 'servers_requests',
  11. ]
  12. CHARTS = {
  13. 'clients_net': {
  14. 'options': [None, 'Squid Client Bandwidth', 'kilobits/s', 'clients', 'squid.clients_net', 'area'],
  15. 'lines': [
  16. ['client_http_kbytes_in', 'in', 'incremental', 8, 1],
  17. ['client_http_kbytes_out', 'out', 'incremental', -8, 1],
  18. ['client_http_hit_kbytes_out', 'hits', 'incremental', -8, 1]
  19. ]
  20. },
  21. 'clients_requests': {
  22. 'options': [None, 'Squid Client Requests', 'requests/s', 'clients', 'squid.clients_requests', 'line'],
  23. 'lines': [
  24. ['client_http_requests', 'requests', 'incremental'],
  25. ['client_http_hits', 'hits', 'incremental'],
  26. ['client_http_errors', 'errors', 'incremental', -1, 1]
  27. ]
  28. },
  29. 'servers_net': {
  30. 'options': [None, 'Squid Server Bandwidth', 'kilobits/s', 'servers', 'squid.servers_net', 'area'],
  31. 'lines': [
  32. ['server_all_kbytes_in', 'in', 'incremental', 8, 1],
  33. ['server_all_kbytes_out', 'out', 'incremental', -8, 1]
  34. ]
  35. },
  36. 'servers_requests': {
  37. 'options': [None, 'Squid Server Requests', 'requests/s', 'servers', 'squid.servers_requests', 'line'],
  38. 'lines': [
  39. ['server_all_requests', 'requests', 'incremental'],
  40. ['server_all_errors', 'errors', 'incremental', -1, 1]
  41. ]
  42. }
  43. }
  44. class Service(SocketService):
  45. def __init__(self, configuration=None, name=None):
  46. SocketService.__init__(self, configuration=configuration, name=name)
  47. self._keep_alive = True
  48. self.request = ''
  49. self.host = 'localhost'
  50. self.port = 3128
  51. self.order = ORDER
  52. self.definitions = CHARTS
  53. def _get_data(self):
  54. """
  55. Get data via http request
  56. :return: dict
  57. """
  58. response = self._get_raw_data()
  59. data = dict()
  60. try:
  61. raw = ''
  62. for tmp in response.split('\r\n'):
  63. if tmp.startswith('sample_time'):
  64. raw = tmp
  65. break
  66. if raw.startswith('<'):
  67. self.error('invalid data received')
  68. return None
  69. for row in raw.split('\n'):
  70. if row.startswith(('client', 'server.all')):
  71. tmp = row.split('=')
  72. data[tmp[0].replace('.', '_').strip(' ')] = int(tmp[1])
  73. except (ValueError, AttributeError, TypeError):
  74. self.error('invalid data received')
  75. return None
  76. if not data:
  77. self.error('no data received')
  78. return None
  79. return data
  80. def _check_raw_data(self, data):
  81. header = data[:1024].lower()
  82. if 'connection: keep-alive' in header:
  83. self._keep_alive = True
  84. else:
  85. self._keep_alive = False
  86. if data[-7:] == '\r\n0\r\n\r\n' and 'transfer-encoding: chunked' in header: # HTTP/1.1 response
  87. self.debug('received full response from squid')
  88. return True
  89. self.debug('waiting more data from squid')
  90. return False
  91. def check(self):
  92. """
  93. Parse essential configuration, autodetect squid configuration (if needed), and check if data is available
  94. :return: boolean
  95. """
  96. self._parse_config()
  97. # format request
  98. req = self.request.decode()
  99. if not req.startswith('GET'):
  100. req = 'GET ' + req
  101. if not req.endswith(' HTTP/1.1\r\n\r\n'):
  102. req += ' HTTP/1.1\r\n\r\n'
  103. self.request = req.encode()
  104. if self._get_data() is not None:
  105. return True
  106. else:
  107. return False