pandas.chart.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # -*- coding: utf-8 -*-
  2. # Description: pandas netdata python.d module
  3. # Author: Andrew Maguire (andrewm4894)
  4. # SPDX-License-Identifier: GPL-3.0-or-later
  5. import os
  6. import pandas as pd
  7. try:
  8. import requests
  9. HAS_REQUESTS = True
  10. except ImportError:
  11. HAS_REQUESTS = False
  12. try:
  13. from sqlalchemy import create_engine
  14. HAS_SQLALCHEMY = True
  15. except ImportError:
  16. HAS_SQLALCHEMY = False
  17. from bases.FrameworkServices.SimpleService import SimpleService
  18. ORDER = []
  19. CHARTS = {}
  20. class Service(SimpleService):
  21. def __init__(self, configuration=None, name=None):
  22. SimpleService.__init__(self, configuration=configuration, name=name)
  23. self.order = ORDER
  24. self.definitions = CHARTS
  25. self.chart_configs = self.configuration.get('chart_configs', None)
  26. self.line_sep = self.configuration.get('line_sep', ';')
  27. def run_code(self, df_steps):
  28. """eval() each line of code and ensure the result is a pandas dataframe"""
  29. # process each line of code
  30. lines = df_steps.split(self.line_sep)
  31. for line in lines:
  32. line_clean = line.strip('\n').strip(' ')
  33. if line_clean != '' and line_clean[0] != '#':
  34. df = eval(line_clean)
  35. assert isinstance(df, pd.DataFrame), 'The result of each evaluated line of `df_steps` must be of type `pd.DataFrame`'
  36. # take top row of final df as data to be collected by netdata
  37. data = df.to_dict(orient='records')[0]
  38. return data
  39. def check(self):
  40. """ensure charts and dims all configured and that we can get data"""
  41. if not HAS_REQUESTS:
  42. self.warning('requests library could not be imported')
  43. if not HAS_SQLALCHEMY:
  44. self.warning('sqlalchemy library could not be imported')
  45. if not self.chart_configs:
  46. self.error('chart_configs must be defined')
  47. data = dict()
  48. # add each chart as defined by the config
  49. for chart_config in self.chart_configs:
  50. if chart_config['name'] not in self.charts:
  51. chart_template = {
  52. 'options': [
  53. chart_config['name'],
  54. chart_config['title'],
  55. chart_config['units'],
  56. chart_config['family'],
  57. chart_config['context'],
  58. chart_config['type']
  59. ],
  60. 'lines': []
  61. }
  62. self.charts.add_chart([chart_config['name']] + chart_template['options'])
  63. data_tmp = self.run_code(chart_config['df_steps'])
  64. data.update(data_tmp)
  65. for dim in data_tmp:
  66. self.charts[chart_config['name']].add_dimension([dim, dim, 'absolute', 1, 1])
  67. return True
  68. def get_data(self):
  69. """get data for each chart config"""
  70. data = dict()
  71. for chart_config in self.chart_configs:
  72. data_tmp = self.run_code(chart_config['df_steps'])
  73. data.update(data_tmp)
  74. return data