Grafana添加自定义数据源-simpod-json-datasource

JSON数据源针对任意后端执行JSON请求。Grafana虽然支持很多数据源,但是有一些特殊的数据处理没办法实现,JSON数据源使得我们更加灵活的组装我们想要的数据。使Grafana不在有数据源的限制,更加灵活。

官网地址:https://grafana.com/grafana/plugins/simpod-json-datasource/

github地址:https://github.com/simPod/GrafanaJsonDatasource

一、安装

1、本地安装,针对通过二进制方式安装的Grafana。

grafana-cli plugins install simpod-json-datasource

【注意】mac在安装完成之后直接重启grafana即可。centos、redhat安装后,执行上面的插件安装命令重启后,看不到新的数据源。因为这个插件安装后的默认位置是/var/lib/grafana/plugins,需要手动将这个插件复制到安装目录的/plugins目录下。因为配置文件中指定了插件的位置,或者将配置文件中插件的位置修改为/var/lib/grafana/plugins。

2、Docker安装

# 进入grafana
docker exec -it grafana bash
# 安装插件
grafana-cli plugins install simpod-json-datasource
# 退出docker
exit
# 将docker中的插件拷贝到宿主机的插件目录下,因为docker启动挂载了宿主机目录
docker cp grafana:/var/lib/grafana/plugins/simpod-json-datasource /Users/guanxin/tools/grafana/plugins
# 查询docker信息
docker ps
# 重启
docker restart <container_id_or_name>

二、添加数据源

登录Grafana,按照一下目录:Home > Connections > Add new connections > JSON

三、接口开发

接口的相关的请求参数和返回参数格式参考官方文档和openapi.yaml文件,地址如下:

https://github.com/simPod/GrafanaJsonDatasource/blob/0.6.x/openapi.yaml

完成 GET / 接口后,点击数据源Save & Test,提示DataSource is working

以下GrafanaController.java的地址要在gateway服务添加放行路由,项目中用的Sa-Token权限认证框架,所以要在网关服务的SaTokenConfigure.java类中添加"/**/grafana/ds/json/**"路由,具体如下图:

GrafanaController.java

@RestController
@RequestMapping(value = "/grafana")
@Api(tags = {"Grafana"})
public class GrafanaController {

    @Autowired
    private GrafanaJsonDsService grafanaJsonDsService;

    @GetMapping(value = "/ds/json/")
    @ApiOperation(value = "测试连接", httpMethod = "GET")
    public Result testConnect() {
        return Result.success();
    }

    @PostMapping(value = "/ds/json/metrics")
    @ApiOperation(value = "指标", httpMethod = "POST")
    public JSONArray getMetrics() {
        return grafanaJsonDsService.getMetrics();
    }

    @PostMapping(value = "/ds/json/metric-payload-options")
    @ApiOperation(value = "度量有效载荷选项", httpMethod = "POST")
    public JSONArray getPayloadOptions() {
        return grafanaJsonDsService.getPayloadOptions();
    }

    @PostMapping(value = "/ds/json/query")
    @ApiOperation(value = "查询", httpMethod = "POST")
    public JSONArray query(@RequestBody String queryParams) {
        return grafanaJsonDsService.query(queryParams);
    }

}

GrafanaJsonDsService.java

public interface GrafanaJsonDsService {

    /**
     * 获取JSON API Grafana Datasource指标
     *
     * @return 指标集合
     */
    JSONArray getMetrics();

    /**
     * 获取JSON API Grafana Datasource主机选项
     * @return
     */
    JSONArray getPayloadOptions();

    /**
     * 获取JSON API Grafana Datasource指标数据
     *
     * @param queryParams 查询参数
     * @return 指标数据集合
     */
    JSONArray query(String queryParams);

}

GrafanaJsonDsServiceImpl.java

@Service
public class GrafanaJsonDsServiceImpl implements GrafanaJsonDsService {

    @Autowired
    private MetricTypeService metricTypeService;
    @Autowired
    private MonitorMetricService monitorMetricService;
    @Autowired
    private HostInfoService hostInfoService;
    @Autowired
    private InfluxDbQueryService influxDbQueryService;
    @Autowired
    private GrafanaJsonProperties grafanaJsonProperties;

    @Override
    public JSONArray getMetrics() {
        JSONArray result = new JSONArray();
        List<MetricType> metricTypeList = metricTypeService.getTypeList();
        if (CollUtil.isNotEmpty(metricTypeList)) {
            for (MetricType metricType : metricTypeList) {
                JSONObject metricsVO = new JSONObject();
                metricsVO.put("label", metricType.getName());
                metricsVO.put("value", metricType.getName());
                JSONArray payloads = new JSONArray();
                payloads.add(this.getMetricPayload(metricType));
                payloads.add(this.getHostPayload(metricType));
                metricsVO.put("payloads", payloads);
                result.add(metricsVO);
            }
        }
        return result;
    }

    @Override
    public JSONArray getPayloadOptions() {
        JSONArray hostOptions = new JSONArray();
        List<HostInfo> hostList = hostInfoService.getHostInfoList();
        if (CollUtil.isNotEmpty(hostList)) {
            for (HostInfo hostInfo : hostList) {
                JSONObject hostOption = new JSONObject();
                hostOption.put("label", hostInfo.getHostName());
                hostOption.put("value", hostInfo.getInnerIp() + "," + hostInfo.getCloudId());
                hostOptions.add(hostOption);
            }
        }
        return hostOptions;
    }

    @Override
    public JSONArray query(String queryParams) {
        JSONArray result = new JSONArray();
        JSONObject jsonObject = JSON.parseObject(queryParams);
        // 步长
        String interval = jsonObject.getString("interval");
        // 时间
        JSONObject range = this.getRawFromAndTo(jsonObject.getString("range"));
        // 查询条件
        String targets = jsonObject.getString("targets");
        List<TargetsDTO> list = JSONArray.parseArray(targets, TargetsDTO.class);
        if (CollUtil.isNotEmpty(list)) {
            for (TargetsDTO targetsDTO : list) {
                InfluxDbData data = null;
                String start = (String) range.get("start");
                String end = (String) range.get("end");
                JSONArray params = this.getQueryMetricsParams(targetsDTO);
                if (CollUtil.isNotEmpty(params)) {
                    for (int i = 0; i < params.size(); i++) {
                        JSONObject timeSeries = new JSONObject();
                        JSONObject param = params.getJSONObject(i);
                        if (null != param.get("formula")) {
                            data = influxDbQueryService.getMetricDataByPromql((String) param.get("formula"), start, end, interval);
                        } else if (null != param.get("type")) {
                            TsQueryParam tsQueryParam = MetricDataUtil.getTsQueryParam(start, end, (String) param.get("ip"), (String) param.get("cloudId"), (Integer) param.get("type"), interval, (String) param.get("metrics"));
                            data = influxDbQueryService.getMetricChartDataByTs(tsQueryParam);
                        }
                        timeSeries.put("target", param.get("target"));
                        timeSeries.put("datapoints", this.getDataPoints(data));
                        result.add(timeSeries);
                    }
                }
            }
        }
        return result;
    }

    /**
     * 获取查询指标数据的查询参数
     *
     * @param targetsDTO JSON API Grafana Datasource Query接口查询条件
     */
    private JSONArray getQueryMetricsParams(TargetsDTO targetsDTO) {
        JSONArray params = new JSONArray();
        String metrics;
        String target = targetsDTO.getTarget();
        if (StrUtil.isNotBlank(target)) {
            JSONObject payload = targetsDTO.getPayload();
            metrics = (String) payload.get(target);
            MonitorMetric monitorMetric = monitorMetricService.getInfoByCode(metrics);
            if (null != monitorMetric) {
                String ipAndCloudIdList = payload.getString(target + "Host");
                if (StrUtil.isNotBlank(ipAndCloudIdList)) {
                    JSONArray ipAndCloudIdArray = JSON.parseArray(ipAndCloudIdList);
                    if (CollUtil.isNotEmpty(ipAndCloudIdArray)) {
                        for (Object ipAndCloudIdObject : ipAndCloudIdArray) {
                            JSONObject param = new JSONObject();
                            String ipAndCloudId = ipAndCloudIdObject.toString();
                            String ip = ipAndCloudId.split(",")[0];
                            String cloudId = ipAndCloudId.split(",")[1];
                            param.put("target", monitorMetric.getName() + "-" + ip);
                            if (StrUtil.isNotBlank(monitorMetric.getFormula())) {
                                param.put("formula", monitorMetric.getFormula().replace("$ip", ip).replace("$cloudid", cloudId));
                            } else {
                                param.put("ip", ip);
                                param.put("cloudId", cloudId);
                                param.put("type", monitorMetric.getType());
                                param.put("metrics", metrics);
                                param.put("formula", null);
                            }
                            params.add(param);
                        }
                    }
                }
            }
        }
        return params;
    }

    /**
     * 获取坐标点数据
     *
     * @param data 指标数据
     */
    private JSONArray getDataPoints(InfluxDbData data) {
        JSONArray dataPoints = new JSONArray();
        if (null != data) {
            List<List<String>> valuesList = MetricDataUtil.getMetricsValues(data);
            if (CollUtil.isNotEmpty(valuesList)) {
                for (List<String> values : valuesList) {
                    long time = TimeUtil.getUTCDateUnixTimestamp(values.get(0));
                    double val = 0;
                    if (null != values.get(1)) {
                        val = new BigDecimal(values.get(1)).setScale(2, RoundingMode.HALF_UP).stripTrailingZeros().doubleValue();
                    }
                    JSONArray dataPoint = new JSONArray();
                    dataPoint.add(val);
                    dataPoint.add(time);
                    dataPoints.add(dataPoint);
                }
            }
        }
        return dataPoints;
    }

    /**
     * 获取Raw的开始和结束时间
     *
     * @param range 时间参数
     * @return 转换为简写格式的开始和结束时间
     */
    private JSONObject getRawFromAndTo(String range) {
        JSONObject fromAndTo = new JSONObject();
        if (StrUtil.isNotBlank(range)) {
            RangeDTO rangeDTO = JSONArray.parseObject(range, RangeDTO.class);
            RawDTO raw = rangeDTO.getRaw();
            String start = raw.getFrom().replace("now", "");
            String end = raw.getTo().replace("now", "0" + raw.getFrom().substring(raw.getFrom().length() - 1));
            fromAndTo.put("start", start);
            fromAndTo.put("end", end);
        }
        return fromAndTo;
    }

    /**
     * 获取指标组下拉框
     *
     * @param metricType 指标类型
     */
    private JSONObject getMetricPayload(MetricType metricType) {
        JSONObject metricPayload = new JSONObject();
        metricPayload.put("label", metricType.getRemark());
        metricPayload.put("name", metricType.getName());
        metricPayload.put("type", grafanaJsonProperties.getMetricPayloadType());
        metricPayload.put("placeholder", "请选择指标");
        metricPayload.put("reloadMetric", Boolean.FALSE);
        metricPayload.put("width", grafanaJsonProperties.getPayloadWidth());
        metricPayload.put("options", this.getMetricOptions(metricType));
        return metricPayload;
    }

    /**
     * 获取指标组下拉框的指标项
     *
     * @param metricType 指标类型
     * @return 指标项集合
     */
    private JSONArray getMetricOptions(MetricType metricType) {
        JSONArray metricOptions = new JSONArray();
        List<MonitorMetric> monitorMetricList = monitorMetricService.getMetricByTypeId(metricType.getUuid());
        if (CollUtil.isNotEmpty(monitorMetricList)) {
            for (MonitorMetric monitorMetric : monitorMetricList) {
                JSONObject metricOption = new JSONObject();
                metricOption.put("label", monitorMetric.getName());
                metricOption.put("value", monitorMetric.getCode());
                metricOptions.add(metricOption);
            }
        }
        return metricOptions;
    }

    /**
     * 获取主机下拉框
     */
    private JSONObject getHostPayload(MetricType metricType) {
        JSONObject hostPayload = new JSONObject();
        hostPayload.put("label", metricType.getName() + "主机");
        hostPayload.put("name", metricType.getName() + "Host");
        hostPayload.put("type", grafanaJsonProperties.getHostPayloadType());
        hostPayload.put("placeholder", "请选择主机");
        hostPayload.put("reloadMetric", Boolean.FALSE);
        hostPayload.put("width", grafanaJsonProperties.getPayloadWidth());
        return hostPayload;
    }

}

GrafanaJsonProperties.java

@Data
@Configuration
@ConfigurationProperties("grafana.json")
public class GrafanaJsonProperties {
    /**
     * 指标选择框类型(单选)
     */
    private String metricPayloadType;
    /**
     * 主机选择框类型(多选)
     */
    private String hostPayloadType;
    /**
     * 指标及主机选择框宽度
     */
    private Integer payloadWidth;
}

配置文件信息

grafana:
  json:
    metricPayloadType: select
    hostPayloadType: multi-select
    payloadWidth: 80

四、页面效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值