beanstalk.chart.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. # -*- coding: utf-8 -*-
  2. # Description: beanstalk netdata python.d module
  3. # Author: ilyam8
  4. # SPDX-License-Identifier: GPL-3.0-or-later
  5. try:
  6. import beanstalkc
  7. BEANSTALKC = True
  8. except ImportError:
  9. BEANSTALKC = False
  10. from bases.FrameworkServices.SimpleService import SimpleService
  11. from bases.loaders import load_yaml
  12. ORDER = [
  13. 'cpu_usage',
  14. 'jobs_rate',
  15. 'connections_rate',
  16. 'commands_rate',
  17. 'current_tubes',
  18. 'current_jobs',
  19. 'current_connections',
  20. 'binlog',
  21. 'uptime',
  22. ]
  23. CHARTS = {
  24. 'cpu_usage': {
  25. 'options': [None, 'Cpu Usage', 'cpu time', 'server statistics', 'beanstalk.cpu_usage', 'area'],
  26. 'lines': [
  27. ['rusage-utime', 'user', 'incremental'],
  28. ['rusage-stime', 'system', 'incremental']
  29. ]
  30. },
  31. 'jobs_rate': {
  32. 'options': [None, 'Jobs Rate', 'jobs/s', 'server statistics', 'beanstalk.jobs_rate', 'line'],
  33. 'lines': [
  34. ['total-jobs', 'total', 'incremental'],
  35. ['job-timeouts', 'timeouts', 'incremental']
  36. ]
  37. },
  38. 'connections_rate': {
  39. 'options': [None, 'Connections Rate', 'connections/s', 'server statistics', 'beanstalk.connections_rate',
  40. 'area'],
  41. 'lines': [
  42. ['total-connections', 'connections', 'incremental']
  43. ]
  44. },
  45. 'commands_rate': {
  46. 'options': [None, 'Commands Rate', 'commands/s', 'server statistics', 'beanstalk.commands_rate', 'stacked'],
  47. 'lines': [
  48. ['cmd-put', 'put', 'incremental'],
  49. ['cmd-peek', 'peek', 'incremental'],
  50. ['cmd-peek-ready', 'peek-ready', 'incremental'],
  51. ['cmd-peek-delayed', 'peek-delayed', 'incremental'],
  52. ['cmd-peek-buried', 'peek-buried', 'incremental'],
  53. ['cmd-reserve', 'reserve', 'incremental'],
  54. ['cmd-use', 'use', 'incremental'],
  55. ['cmd-watch', 'watch', 'incremental'],
  56. ['cmd-ignore', 'ignore', 'incremental'],
  57. ['cmd-delete', 'delete', 'incremental'],
  58. ['cmd-release', 'release', 'incremental'],
  59. ['cmd-bury', 'bury', 'incremental'],
  60. ['cmd-kick', 'kick', 'incremental'],
  61. ['cmd-stats', 'stats', 'incremental'],
  62. ['cmd-stats-job', 'stats-job', 'incremental'],
  63. ['cmd-stats-tube', 'stats-tube', 'incremental'],
  64. ['cmd-list-tubes', 'list-tubes', 'incremental'],
  65. ['cmd-list-tube-used', 'list-tube-used', 'incremental'],
  66. ['cmd-list-tubes-watched', 'list-tubes-watched', 'incremental'],
  67. ['cmd-pause-tube', 'pause-tube', 'incremental']
  68. ]
  69. },
  70. 'current_tubes': {
  71. 'options': [None, 'Current Tubes', 'tubes', 'server statistics', 'beanstalk.current_tubes', 'area'],
  72. 'lines': [
  73. ['current-tubes', 'tubes']
  74. ]
  75. },
  76. 'current_jobs': {
  77. 'options': [None, 'Current Jobs', 'jobs', 'server statistics', 'beanstalk.current_jobs', 'stacked'],
  78. 'lines': [
  79. ['current-jobs-urgent', 'urgent'],
  80. ['current-jobs-ready', 'ready'],
  81. ['current-jobs-reserved', 'reserved'],
  82. ['current-jobs-delayed', 'delayed'],
  83. ['current-jobs-buried', 'buried']
  84. ]
  85. },
  86. 'current_connections': {
  87. 'options': [None, 'Current Connections', 'connections', 'server statistics',
  88. 'beanstalk.current_connections', 'line'],
  89. 'lines': [
  90. ['current-connections', 'written'],
  91. ['current-producers', 'producers'],
  92. ['current-workers', 'workers'],
  93. ['current-waiting', 'waiting']
  94. ]
  95. },
  96. 'binlog': {
  97. 'options': [None, 'Binlog', 'records/s', 'server statistics', 'beanstalk.binlog', 'line'],
  98. 'lines': [
  99. ['binlog-records-written', 'written', 'incremental'],
  100. ['binlog-records-migrated', 'migrated', 'incremental']
  101. ]
  102. },
  103. 'uptime': {
  104. 'options': [None, 'Uptime', 'seconds', 'server statistics', 'beanstalk.uptime', 'line'],
  105. 'lines': [
  106. ['uptime'],
  107. ]
  108. }
  109. }
  110. def tube_chart_template(name):
  111. order = [
  112. '{0}_jobs_rate'.format(name),
  113. '{0}_jobs'.format(name),
  114. '{0}_connections'.format(name),
  115. '{0}_commands'.format(name),
  116. '{0}_pause'.format(name)
  117. ]
  118. family = 'tube {0}'.format(name)
  119. charts = {
  120. order[0]: {
  121. 'options': [None, 'Job Rate', 'jobs/s', family, 'beanstalk.jobs_rate', 'area'],
  122. 'lines': [
  123. ['_'.join([name, 'total-jobs']), 'jobs', 'incremental']
  124. ]
  125. },
  126. order[1]: {
  127. 'options': [None, 'Jobs', 'jobs', family, 'beanstalk.jobs', 'stacked'],
  128. 'lines': [
  129. ['_'.join([name, 'current-jobs-urgent']), 'urgent'],
  130. ['_'.join([name, 'current-jobs-ready']), 'ready'],
  131. ['_'.join([name, 'current-jobs-reserved']), 'reserved'],
  132. ['_'.join([name, 'current-jobs-delayed']), 'delayed'],
  133. ['_'.join([name, 'current-jobs-buried']), 'buried']
  134. ]
  135. },
  136. order[2]: {
  137. 'options': [None, 'Connections', 'connections', family, 'beanstalk.connections', 'stacked'],
  138. 'lines': [
  139. ['_'.join([name, 'current-using']), 'using'],
  140. ['_'.join([name, 'current-waiting']), 'waiting'],
  141. ['_'.join([name, 'current-watching']), 'watching']
  142. ]
  143. },
  144. order[3]: {
  145. 'options': [None, 'Commands', 'commands/s', family, 'beanstalk.commands', 'stacked'],
  146. 'lines': [
  147. ['_'.join([name, 'cmd-delete']), 'deletes', 'incremental'],
  148. ['_'.join([name, 'cmd-pause-tube']), 'pauses', 'incremental']
  149. ]
  150. },
  151. order[4]: {
  152. 'options': [None, 'Pause', 'seconds', family, 'beanstalk.pause', 'stacked'],
  153. 'lines': [
  154. ['_'.join([name, 'pause']), 'since'],
  155. ['_'.join([name, 'pause-time-left']), 'left']
  156. ]
  157. }
  158. }
  159. return order, charts
  160. class Service(SimpleService):
  161. def __init__(self, configuration=None, name=None):
  162. SimpleService.__init__(self, configuration=configuration, name=name)
  163. self.configuration = configuration
  164. self.order = list(ORDER)
  165. self.definitions = dict(CHARTS)
  166. self.conn = None
  167. self.alive = True
  168. def check(self):
  169. if not BEANSTALKC:
  170. self.error("'beanstalkc' module is needed to use beanstalk.chart.py")
  171. return False
  172. self.conn = self.connect()
  173. return True if self.conn else False
  174. def get_data(self):
  175. """
  176. :return: dict
  177. """
  178. if not self.is_alive():
  179. return None
  180. active_charts = self.charts.active_charts()
  181. data = dict()
  182. try:
  183. data.update(self.conn.stats())
  184. for tube in self.conn.tubes():
  185. stats = self.conn.stats_tube(tube)
  186. if tube + '_jobs_rate' not in active_charts:
  187. self.create_new_tube_charts(tube)
  188. for stat in stats:
  189. data['_'.join([tube, stat])] = stats[stat]
  190. except beanstalkc.SocketError:
  191. self.alive = False
  192. return None
  193. return data or None
  194. def create_new_tube_charts(self, tube):
  195. order, charts = tube_chart_template(tube)
  196. for chart_name in order:
  197. params = [chart_name] + charts[chart_name]['options']
  198. dimensions = charts[chart_name]['lines']
  199. new_chart = self.charts.add_chart(params)
  200. for dimension in dimensions:
  201. new_chart.add_dimension(dimension)
  202. def connect(self):
  203. host = self.configuration.get('host', '127.0.0.1')
  204. port = self.configuration.get('port', 11300)
  205. timeout = self.configuration.get('timeout', 1)
  206. try:
  207. return beanstalkc.Connection(host=host,
  208. port=port,
  209. connect_timeout=timeout,
  210. parse_yaml=load_yaml)
  211. except beanstalkc.SocketError as error:
  212. self.error('Connection to {0}:{1} failed: {2}'.format(host, port, error))
  213. return None
  214. def reconnect(self):
  215. try:
  216. self.conn.reconnect()
  217. self.alive = True
  218. return True
  219. except beanstalkc.SocketError:
  220. return False
  221. def is_alive(self):
  222. if not self.alive:
  223. return self.reconnect()
  224. return True