def query(self):
        """
        Request object passed to datasource.query function:

        {
            'timezone': 'browser',
            'panelId': 38,
            'range': {
                'from': '2018-08-29T02:38:09.633Z',
                'to': '2018-08-29T03:38:09.633Z',
                'raw': {'from': 'now-1h', 'to': 'now'}
            },
            'rangeRaw': {'from': 'now-1h', 'to': 'now'},
            'interval': '10s',
            'intervalMs': 10000,
            'targets': [
                {
                    'target': 'problems', 'refId': 'A', 'type': 'table'}
            ],
            'format': 'json',
            'maxDataPoints': 314,
            'scopedVars': {
                '__interval': {'text': '10s', 'value': '10s'},
                '__interval_ms': {'text': 10000, 'value': 10000}
            }
        }

        Only the first target is considered. If several targets are required, an error is raised.

        The target is a string that is searched in the target_queries dictionary. If found
        the corresponding query is executed and the result is returned.

        Table response from datasource.query. An array of:

        [
          {
            "type": "table",
            "columns": [
              {
                "text": "Time",
                "type": "time",
                "sort": true,
                "desc": true,
              },
              {
                "text": "mean",
              },
              {
                "text": "sum",
              }
            ],
            "rows": [
              [
                1457425380000,
                null,
                null
              ],
              [
                1457425370000,
                1002.76215352,
                1002.76215352
              ],
            ]
          }
        ]
        :return: See upper comment
        :rtype: list
        """
        logger.debug("Grafana query... %s", cherrypy.request.method)
        if cherrypy.request.method == 'OPTIONS':
            cherrypy.response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PATCH,PUT,DELETE'
            cherrypy.response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization'
            cherrypy.response.headers['Access-Control-Allow-Origin'] = '*'
            cherrypy.request.handler = None
            return {}

        if getattr(cherrypy.request, 'json', None):
            posted_data = cherrypy.request.json
            logger.debug("Posted data: %s", cherrypy.request.json)

        targets = None
        target = None
        try:
            targets = posted_data.get("targets")
            assert targets
            assert len(targets) == 1
            target = targets[0].get("target")
        except Exception as exp:  # pylint: disable=broad-except
            cherrypy.response.status = 409
            return {'_status': u'ERR', '_message': u'Request error: %s.' % exp}

        resp = []
        if target in ['events_log']:
            resp = [{
                "type": "table",
                "columns": [
                    {
                        "text": "Time",
                        "type": "time",
                        "sort": True,
                        "desc": True
                    },
                    {
                        "text": "Severity",
                        "type": "integer"
                    },
                    {
                        "text": "Message",
                        "type": "string"
                    }
                ],
                "rows": []
            }]

            severity = {
                "info": 0,
                'warning': 1,
                'error': 2,
                'critical': 3
            }
            for log in reversed(self.app.recent_events):
                # 0 for the first required target
                # timestamp must be precise on ms for Grafana
                resp[0]['rows'].append([log['timestamp'] * 1000,
                                        severity.get(log['level'].lower(), 3), log['message']])

        if target in ['problems_log']:
            resp = [{
                "type": "table",
                "columns": [
                    {
                        "text": "Raised",
                        "type": "time",
                        "sort": True,
                        "desc": True
                    },
                    {
                        "text": "Severity",
                        "type": "integer"
                    },
                    {
                        "text": "Host",
                        "type": "string"
                    },
                    {
                        "text": "Service",
                        "type": "string"
                    },
                    {
                        "text": "State",
                        "type": "integer"
                    },
                    {
                        "text": "Output",
                        "type": "string"
                    }
                ],
                "rows": []
            }]

            severity = {
                "up": 0,
                'down': 2,
                'ok': 0,
                'warning': 1,
                'critical': 2
            }

            problems = {}
            for scheduler_link in self.app.conf.schedulers:
                sched_res = scheduler_link.con.get('monitoring_problems', wait=True)
                if 'problems' in sched_res:
                    problems.update(sched_res['problems'])

            # todo: add a sorting
            for problem_uuid in problems:
                log = problems[problem_uuid]

                # 0 for the first required target
                resp[0]['rows'].append([log['last_hard_state_change'] * 1000,
                                        severity.get(log['state'].lower(), 3),
                                        log['host'], log['service'], log['state'], log['output']])

        return resp
Request object passed to datasource.query function:

        {
            'timezone': 'browser',
            'panelId': 38,
            'range': {
                'from': '2018-08-29T02:38:09.633Z',
                'to': '2018-08-29T03:38:09.633Z',
                'raw': {'from': 'now-1h', 'to': 'now'}
            },
            'rangeRaw': {'from': 'now-1h', 'to': 'now'},
            'interval': '10s',
            'intervalMs': 10000,
            'targets': [
                {
                    'target': 'problems', 'refId': 'A', 'type': 'table'}
            ],
            'format': 'json',
            'maxDataPoints': 314,
            'scopedVars': {
                '__interval': {'text': '10s', 'value': '10s'},
                '__interval_ms': {'text': 10000, 'value': 10000}
            }
        }

        Only the first target is considered. If several targets are required, an error is raised.

        The target is a string that is searched in the target_queries dictionary. If found
        the corresponding query is executed and the result is returned.

        Table response from datasource.query. An array of:

        [
          {
            "type": "table",
            "columns": [
              {
                "text": "Time",
                "type": "time",
                "sort": true,
                "desc": true,
              },
              {
                "text": "mean",
              },
              {
                "text": "sum",
              }
            ],
            "rows": [
              [
                1457425380000,
                null,
                null
              ],
              [
                1457425370000,
                1002.76215352,
                1002.76215352
              ],
            ]
          }
        ]
        :return: See upper comment
        :rtype: list