summaryrefslogtreecommitdiffstats
path: root/src/collectors/python.d.plugin/pandas/pandas.chart.py
blob: 7977bcb3687a37936afb077bd87bda1aa6bcab75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# -*- coding: utf-8 -*-
# Description: pandas netdata python.d module
# Author: Andrew Maguire (andrewm4894)
# SPDX-License-Identifier: GPL-3.0-or-later

import os
import pandas as pd

try:
    import requests
    HAS_REQUESTS = True
except ImportError:
    HAS_REQUESTS = False

try:
    from sqlalchemy import create_engine
    HAS_SQLALCHEMY = True
except ImportError:
    HAS_SQLALCHEMY = False

from bases.FrameworkServices.SimpleService import SimpleService

ORDER = []

CHARTS = {}


class Service(SimpleService):
    def __init__(self, configuration=None, name=None):
        SimpleService.__init__(self, configuration=configuration, name=name)
        self.order = ORDER
        self.definitions = CHARTS
        self.chart_configs = self.configuration.get('chart_configs', None)
        self.line_sep = self.configuration.get('line_sep', ';')

    def run_code(self, df_steps):
        """eval() each line of code and ensure the result is a pandas dataframe"""

        # process each line of code
        lines = df_steps.split(self.line_sep)
        for line in lines:
            line_clean = line.strip('\n').strip(' ')
            if line_clean != '' and line_clean[0] != '#':
                df = eval(line_clean)
                assert isinstance(df, pd.DataFrame), 'The result of each evaluated line of `df_steps` must be of type `pd.DataFrame`'

        # take top row of final df as data to be collected by netdata
        data = df.to_dict(orient='records')[0]

        return data

    def check(self):
        """ensure charts and dims all configured and that we can get data"""

        if not HAS_REQUESTS:
            self.warning('requests library could not be imported')

        if not HAS_SQLALCHEMY:
            self.warning('sqlalchemy library could not be imported')

        if not self.chart_configs:
            self.error('chart_configs must be defined')

        data = dict()

        # add each chart as defined by the config
        for chart_config in self.chart_configs:
            if chart_config['name'] not in self.charts:
                chart_template = {
                    'options': [
                        chart_config['name'],
                        chart_config['title'],
                        chart_config['units'],
                        chart_config['family'],
                        chart_config['context'],
                        chart_config['type']
                        ],
                    'lines': []
                    }
                self.charts.add_chart([chart_config['name']] + chart_template['options'])

            data_tmp = self.run_code(chart_config['df_steps'])
            data.update(data_tmp)

            for dim in data_tmp:
                self.charts[chart_config['name']].add_dimension([dim, dim, 'absolute', 1, 1])

        return True

    def get_data(self):
        """get data for each chart config"""

        data = dict()

        for chart_config in self.chart_configs:
            data_tmp = self.run_code(chart_config['df_steps'])
            data.update(data_tmp)

        return data