com.qq.tars.service.monitor.TARSStatMonitorService.java Source code

Java tutorial

Introduction

Here is the source code for com.qq.tars.service.monitor.TARSStatMonitorService.java

Source

/*
 * Tencent is pleased to support the open source community by making Tars available.
 *
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
 *
 * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * https://opensource.org/licenses/BSD-3-Clause
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.qq.tars.service.monitor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qq.common.TCPClient;
import com.qq.tars.service.admin.AdminService;
import org.apache.commons.collections.keyvalue.MultiKey;
import org.apache.commons.collections.map.MultiKeyMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

@Service
public class TARSStatMonitorService {

    private final Logger log = LoggerFactory.getLogger(TARSStatMonitorService.class);

    @Autowired
    private AdminService adminService;

    public List<TARSStatMonitorDataRow> getTARSStatMonitorData(TARSStatMonitorCondition condition)
            throws IOException {
        MultiKeyMap thedata = call(condition, true);
        MultiKeyMap predata = call(condition, false);
        return merge(condition, thedata, predata);
    }

    private List<String> getCallGroupBy(TARSStatMonitorCondition condition) {
        List<String> callGroupBy = new LinkedList<>();
        if (null != condition.getGroupBy()) {
            callGroupBy.add("f_date");
            callGroupBy.add(condition.getGroupBy());
        } else {
            callGroupBy.add("f_tflag");
        }
        return callGroupBy;
    }

    private Set<MultiKey> mergeKey(TARSStatMonitorCondition condition, MultiKeyMap thedata, MultiKeyMap predata) {
        Set<MultiKey> keys = new TreeSet<>((left, right) -> {
            for (int i = 0; i < left.size(); i++) {
                Object leftKey = left.getKey(i);
                Object rightKey = right.getKey(i);
                if (leftKey.equals(rightKey)) {
                    continue;
                }
                return ((String) leftKey).compareTo((String) rightKey);
            }
            return 0;
        });
        keys.addAll(thedata.keySet());
        for (Object obj : predata.keySet()) {
            Object[] keyparts = ((MultiKey) obj).getKeys();
            if (keyparts.length > 1) {
                keyparts[0] = condition.getThedate();
            }
            keys.add(new MultiKey(keyparts));
        }
        return keys;
    }

    private void dimension(TARSStatMonitorCondition condition, MultiKey key, TARSStatMonitorDataRow row) {
        if (!"master_name".equals(condition.getGroupBy())) {
            row.setMasterName(null != condition.getMasterName() ? condition.getMasterName() : "%");
        }

        if (!"slave_name".equals(condition.getGroupBy())) {
            row.setSlaveName(null != condition.getSlaveName() ? condition.getSlaveName() : "%");
        }

        if (!"interface_name".equals(condition.getGroupBy())) {
            row.setInterfaceName(null != condition.getInterfaceName() ? condition.getInterfaceName() : "%");
        }

        if (!"master_ip".equals(condition.getGroupBy())) {
            row.setMasterIp(null != condition.getMasterIp() ? condition.getMasterIp() : "%");
        }

        if (!"slave_ip".equals(condition.getGroupBy())) {
            row.setSlaveIp(null != condition.getSlaveIp() ? condition.getSlaveIp() : "%");
        }

        List<String> callGroupBy = getCallGroupBy(condition);
        for (int i = 0; i < callGroupBy.size(); i++) {
            String callGroup = callGroupBy.get(i);
            String callGroupValue = (String) key.getKey(i);

            if ("f_date".equals(callGroup)) {
                row.setShowDate(callGroupValue);
            } else if ("f_tflag".equals(callGroup)) {
                row.setShowTime(callGroupValue);
            } else if ("master_name".equals(callGroup)) {
                row.setMasterName(callGroupValue);
            } else if ("slave_name".equals(callGroup)) {
                row.setSlaveName(callGroupValue);
            } else if ("interface_name".equals(callGroup)) {
                row.setInterfaceName(callGroupValue);
            } else if ("master_ip".equals(callGroup)) {
                row.setMasterIp(callGroupValue);
            } else if ("slave_ip".equals(callGroup)) {
                row.setSlaveIp(callGroupValue);
            }
        }
    }

    private double[] translate(long[] data) {
        if (null == data) {
            return new double[] { -1, -1, -1, -1 };
        }

        double[] result = new double[4];
        long total = data[0] + data[1] + data[2];
        result[0] = total;
        result[1] = total == 0 ? -1 : data[3] / result[0];
        result[2] = total == 0 ? -1 : data[2] / result[0];
        result[3] = total == 0 ? -1 : data[1] / result[0];
        return result;
    }

    private String[] translate(double[] data) {
        String[] result = new String[4];
        result[0] = data[0] < 0 ? "--" : String.format("%.0f", data[0]);
        result[1] = data[1] < 0 ? "--" : String.format("%.2f", data[1]);
        result[2] = data[2] < 0 ? "--" : String.format("%.2f", data[2] * 100) + "%";
        result[3] = data[3] < 0 ? "--" : String.format("%.2f", data[3] * 100) + "%";
        return result;
    }

    private List<TARSStatMonitorDataRow> merge(TARSStatMonitorCondition condition, MultiKeyMap thedata,
            MultiKeyMap predata) {
        Set<MultiKey> keys = mergeKey(condition, thedata, predata);

        List<TARSStatMonitorDataRow> result = new LinkedList<>();
        for (MultiKey key : keys) {
            TARSStatMonitorDataRow row = new TARSStatMonitorDataRow();
            result.add(row);

            double[] thevalue = translate((long[]) thedata.get(key));
            double[] prevalue = translate((long[]) predata.get(key));
            String[] thevalueoutput = translate(thevalue);
            String[] prevalueoutput = translate(prevalue);

            row.setTheTotalCount(thevalueoutput[0]);
            row.setTheAvgTime(thevalueoutput[1]);
            row.setTheFailRate(thevalueoutput[2]);
            row.setTheTimeoutRate(thevalueoutput[3]);

            row.setPreTotalCount(prevalueoutput[0]);
            row.setPreAvgTime(prevalueoutput[1]);
            row.setPreFailRate(prevalueoutput[2]);
            row.setPreTimeoutRate(prevalueoutput[3]);

            if (thevalue[0] < 0 || prevalue[0] < 0) {
                row.setTotalCountWave("--");
            } else {
                if (0 == prevalue[0]) {
                    if (0 == thevalue[0]) {
                        row.setTotalCountWave("0%");
                    } else {
                        row.setTotalCountWave("+%");
                    }
                } else {
                    double wave = (thevalue[0] - prevalue[0]) / prevalue[0];
                    row.setTotalCountWave(String.format("%.2f", wave * 100) + "%");
                }
            }

            dimension(condition, key, row);
        }
        return result;
    }

    private MultiKeyMap call(TARSStatMonitorCondition condition, boolean the) throws IOException {
        String date = the ? condition.getThedate() : condition.getPredate();

        List<String> callConditions = new LinkedList<>();
        callConditions.add("f_date='" + date + "'");
        callConditions.add("f_tflag>='" + condition.getTheshowtime() + "'");
        callConditions.add("f_tflag<='" + condition.getPreshowtime() + "'");

        if (null != condition.getMasterName()) {
            callConditions.add("master_name like '" + condition.getMasterName() + "'");
        }
        if (null != condition.getSlaveName()) {
            callConditions.add("slave_name like '" + condition.getSlaveName() + "'");
        }
        if (null != condition.getInterfaceName()) {
            callConditions.add("interface_name like '" + condition.getInterfaceName() + "'");
        }
        if (null != condition.getMasterIp()) {
            callConditions.add("master_ip like '" + condition.getMasterIp() + "'");
        }
        if (null != condition.getSlaveIp()) {
            callConditions.add("slave_ip like '" + condition.getSlaveIp() + "'");
        }

        List<String> callGroupBy = new LinkedList<>();
        if (null != condition.getGroupBy()) {
            callGroupBy.add("f_date");
            callGroupBy.add(condition.getGroupBy());
        } else {
            callGroupBy.add("f_tflag");
        }

        return call(callGroupBy, callConditions);
    }

    private MultiKeyMap call(List<String> groupBy, List<String> conditions) throws IOException {
        String template = "{\"groupby\":%s,\"method\":\"query\",\"dataid\":\"tars_stat\","
                + "\"filter\":%s,\"indexs\":[\"succ_count\",\"timeout_count\",\"exce_count\",\"total_time\"]}";

        ObjectMapper mapper = new ObjectMapper();
        String request = String.format(template, mapper.writeValueAsString(groupBy),
                mapper.writeValueAsString(conditions));

        List<Pair<String, Integer>> addrs = adminService.getEndpoints("tars.tarsquerystat.NoTarsObj");
        if (addrs.isEmpty()) {
            throw new IOException("tars.tarsquerystat.NoTarsObj not found");
        }

        Pair<String, Integer> addr = addrs.get(0);
        log.info("tars.tarsquerystat.NoTarsObj, use {}:{}", addr.getLeft(), addr.getRight());

        TCPClient client = new TCPClient(addr.getLeft(), addr.getRight());
        List<String> response = client.sendAndReceive(request.getBytes(), 60000);

        log.debug("request={}", request);
        log.debug("reponse={}", StringUtils.join(response, "\n"));

        String line1 = response.get(0);
        if (!line1.startsWith("Ret:")) {
            throw new IOException(String.format("line #1, doesn't start with \"Ret:\", line=%s", line1));
        }
        int ret = Integer.parseInt(line1.substring(line1.lastIndexOf(':') + 1));
        if (ret == -1) {
            throw new IOException(String.format("line #1, Ret=%s", ret));
        }

        String line6 = response.get(5);
        if (!line6.startsWith("linecount:")) {
            throw new IOException(String.format("line #6, doesn't start with \"linecount:\", line=%s", line6));
        }
        int count = Integer.parseInt(line6.substring(line6.lastIndexOf(':') + 1));
        if (count + 7 != response.size()) {
            throw new IOException(String.format("line #6, size not match, %s vs %s", count + 7, response.size()));
        }

        String lastLine = response.get(response.size() - 1);
        if (!"endline".equals(lastLine)) {
            throw new IOException(
                    String.format("line #%s, doesn't equal to \"endline\", line=%s", response.size(), lastLine));
        }

        MultiKeyMap result = new MultiKeyMap();
        for (int i = 6; i < response.size() - 1; i++) {
            String line = StringUtils.removeEnd(response.get(i), ",");
            String[] tokens = line.split(",");
            if (tokens.length != groupBy.size() + 4) {
                throw new IOException(String.format("line format error, line=%s", line));
            }

            String[] key = new String[groupBy.size()];
            int j = 0;
            for (; j < key.length; j++) {
                key[j] = tokens[j];
            }

            long[] value = new long[] { Long.parseLong(tokens[j++]), Long.parseLong(tokens[j++]),
                    Long.parseLong(tokens[j++]), Long.parseLong(tokens[j]) };
            result.put(new MultiKey(key), value);
        }
        return result;
    }
}