metrics.py 6.4 KB
from datetime import datetime, timedelta
from operator import or_
from sqlalchemy.sql.expression import intersect_all
import re
from sqlalchemy.sql.functions import func
from .models import db, MonitorInfo
from sqlalchemy import and_
from app.util.component.ApiTemplate import ApiTemplate
import math
from functools import reduce


class Api(ApiTemplate):
    api_name = "统计指标"

    def process(self):

        # 返回结果
        res = {}
        res["data"] = []
        logs = []
        try:
            server = self.para.get("server")  # server
            metrics_type = self.para.get("metrics_type")
            interval = self.para.get("interval")
            start_time = self.para.get("start")
            to_time = self.para.get("to")
            start_datetime = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
            end_datetime = datetime.strptime(to_time, "%Y-%m-%d %H:%M:%S")
            format = "%Y-%m-%d %H:%M:%S"

            interval_size = int(re.findall("\d+", interval)[0])
            interval_unit = re.findall("\D+", interval)[0]

            if interval_size == 1 and interval_unit == 'm':
                logs = db.session.query(MonitorInfo.time_stamp.label('key'), MonitorInfo.value).filter(
                    and_(MonitorInfo.time_stamp <= end_datetime.strftime(format),
                         MonitorInfo.time_stamp > start_datetime.strftime(
                        format),
                        MonitorInfo.server == server,
                        MonitorInfo.metrics == metrics_type)).order_by(MonitorInfo.time_stamp).group_by(
                    MonitorInfo.time_stamp, MonitorInfo.value)
                datas = list(map(lambda log:
                                 {"key": datetime.strftime(log.key, format),
                                  "value": log.value},
                                 logs))
                datas = reduce(lambda y, x: y if (x['key'] in [i['key'] for i in y]) else (
                    lambda z, u: (z.append(u), z))(y, x)[1], datas, [])
                for data in datas:
                    res['data'].append([data['key'], data['value']])
            else:
                interval_start_datetime = start_datetime
                interval_end_datatime = self.get_end_interval(
                    interval_start_datetime, interval_unit, interval_size)
                res_format = "%Y-%m-%d %H:%M:%S"

                while interval_end_datatime <= end_datetime:
                    logs = db.session.query(MonitorInfo.time_stamp.label('key'), MonitorInfo.value).filter(
                        and_(MonitorInfo.time_stamp <= interval_end_datatime.strftime(format),
                                MonitorInfo.time_stamp > interval_start_datetime.strftime(
                            format), MonitorInfo.server == server, MonitorInfo.metrics == metrics_type)).order_by(MonitorInfo.time_stamp).group_by(
                        MonitorInfo.time_stamp, MonitorInfo.value).all()
                    tmp_data = list(map(lambda log:
                                        {"key": datetime.strftime(log.key, res_format),
                                            "value": log.value},
                                        logs))
                    datas = self.get_sample_data(tmp_data)
                    datas = reduce(lambda y, x: y if (x['key'] in [i['key'] for i in y]) else (
                        lambda z, u: (z.append(u), z))(y, x)[1], datas, [])
                    for data in datas:
                        res['data'].append([data['key'], data['value']])

                    interval_start_datetime = interval_end_datatime
                    interval_end_datatime = self.get_end_interval(
                        interval_start_datetime, interval_unit, interval_size)
            res["result"] = True
        except Exception as e:
            raise e
        return res

    api_doc = {
        "tags": ["监控接口"],
        "parameters": [
            {"name": "server",
             "in": "query",
             "type": "string",
             "description": "服务器地址"},
            {"name": "interval",
             "in": "query",
             "type": "string",
             "description": "间隔"},
            {"name": "to",
             "in": "query",
             "type": "string",
             "description": "查询终止时间"},
            {"name": "start",
             "in": "query",
             "type": "string",
             "description": "查询起始时间"},
            {"name": "metrics_type",
             "in": "query",
             "type": "string",
             "description": "查询指标"}
        ],
        "responses": {
            200: {
                "schema": {
                    "properties": {
                    }
                }
            }
        }
    }

    def get_end_interval(self, start, unit, size):
        if unit == 'm':
            return start+timedelta(minutes=size)
        elif unit == 'h':
            return start+timedelta(hours=size)
        elif unit == 'd':
            return start+timedelta(days=size)
        else:
            return None

    def get_sample_data(self, orginal):
        res = []
        size = len(orginal)
        orginal_stamp = {'head': 1, 'tail': size}
        if size > 1:
            stamp = {'P0': 1,
                     'P50': math.floor(0.5*size),
                     #  'P90': math.floor(0.9*size),
                     #  'P95': math.floor(0.95*size),
                     #  'P99': math.floor(0.99*size),
                     'P100': size}
        elif size == 1:
            stamp = {'P0': 1,
                     'P50': size,
                     #  'P90': size,
                     #  'P95': size,
                     #  'P99': size,
                     'P100': size}
        else:
            return res

        for key in dict.keys(orginal_stamp):
            cur_data = orginal[orginal_stamp[key]-1]
            info = {'key': cur_data['key'], 'value': cur_data['value']}
            res.append(info)

        data = sorted(orginal, key=lambda x: x['value'])
        for key in dict.keys(stamp):
            cur_data = data[stamp[key]-1]
            info = {'key': cur_data['key'], 'value': cur_data['value']}
            res.append(info)

        res.sort(key=self.takeKey)
        return res

    def takeKey(self, elem):
        return elem['key']