在时序分析及监控展示领域,Grafana无疑是开源解决方案中的翘楚,其灵活的插件机制,支持各种漂亮的面板、丰富的数据源以及强大的应用。典型的面板有Graph、Text、Singlestat、PieChart、Table、Histogram等,支持的数据源有ES、Graphite、InfluxDB、OpenTSDB、MySQL、Druid 、Prometheus、SimpleJson等,提供的应用有Zabbix、K8s等。但是某公司在分布式集群中物理机监控的数据源为gRPC方式,即连接gRPC即可获取实时物理机监控信息,如CPU,内存,磁盘,负载等信息,这样就能使用后台转发gRPC的消息,这里使用SSM框架的java后台为grafana提供的SimpleJson数据源。
作者撰文时,网上几乎没有分享SimpleJson数据源的java后台API,为此分享给大家,初次分享,不便之处请见谅。
整体架构如下所示:
一、WebAPI
如果要支持SimpleJson,后端WebAPI需要实现4个URL:
/:返回200,用于SimpleJson数据源测试连通性;
/search:返回所有可选的指标;
/query:返回对应指标的时间序列点;
/annotations:返回注解。
@RequestMapping(value = "/", method = RequestMethod.GET)@ResponseBodypublic Map ReturnTest(HttpServletResponse response){response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");Map<String, Object> map = new HashMap<String, Object>();map.put("result", "200 ok");return map;}
@RequestMapping(value = "/search", method = RequestMethod.POST)@ResponseBodypublic List Search(HttpServletResponse response) {response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");List<String> result = new ArrayList<String>();result.add("CPU");result.add("RAM");result.add("LOAD");result.add("SWAP");result.add("DISK");result.add("NET");return result;}
`````java@RequestMapping(value = "/query", method = RequestMethod.POST)@ResponseBodypublic List Query(@RequestBody Map<String,Object> params, HttpServletResponse response) {List<Map> targetList = (List) params.get("targets");List<Map<String, Object>> result = new ArrayList<Map<String, Object>>() ;for (Map targetMap : targetList){String target = (String)targetMap.get("target");Map scopedVars = (Map) params.get("scopedVars");Map IP = (Map) scopedVars.get("IP");String nodeIP = (String) IP.get("text");if (target.equals("CPU")){result.add(nodeMonitorService.getCpuMap(nodeIP));}else if (target.equals("RAM")){result.add(nodeMonitorService.getRamMap(nodeIP));}else if (target.equals("LOAD")) {result.add(nodeMonitorService.getLoadMap(nodeIP));}else if (target.equals("SWAP")){result.add(nodeMonitorService.getSwapMap(nodeIP));}else if(target.equals("DISK")){result = nodeMonitorService.getDiskList(nodeIP);}else if (target.equals("NET")){result = nodeMonitorService.getNetList(nodeIP);}}response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");Collections.sort(result, new Comparator<Map<String, Object>>() {public int compare(Map<String, Object> o1, Map<String, Object> o2) {String name1 = String.valueOf(o1.get("target").toString()) ;String name2 = String.valueOf(o2.get("target").toString()) ; return name1.compareTo(name2);}});return result;}
@RequestMapping(value = "/annotations", method = RequestMethod.POST)@ResponseBodypublic Map Annotations() {Map<String, Object> map = new HashMap<String, Object>();map.put("result", "200 ok");return map;}
具体参数可以用以下函数替换,如getCupMap:
private Map<String, Object> strjson() {//String str = "{\"A\":{\"tables\":[{\"columns\":[{\"text\":\"序列\",\"sort\":true,\"desc\":true,\"title\":\"序列\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:644\"},{\"text\":\"水果名称12\",\"title\":\"水果名称12\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:645\"},{\"text\":\"价钱\",\"title\":\"价钱\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:646\"},{\"text\":\"重量(kg)\",\"title\":\"重量(kg)\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:647\"},{\"text\":\"总价钱\",\"title\":\"总价钱\",\"style\":{\"alias\":\"\",\"colorMode\":null,\"colors\":[\"rgba(245, 54, 54, 0.9)\",\"rgba(237, 129, 40, 0.89)\",\"rgba(50, 172, 45, 0.97)\"],\"decimals\":2,\"pattern\":\"/.*/\",\"thresholds\":[],\"type\":\"number\",\"unit\":\"short\"},\"hidden\":false,\"$$hashKey\":\"object:648\"}],\"rows\":[[1,\"水果01\",4,2,8],[2,\"水果02\",5,2,10],[3,\"水果03\",6,2,12],[4,\"水果04\",7,2,14],[5,\"水果05\",8,2,16]]}]}}";Map<String, Object> map = new HashMap<>();JSONArray ja = new JSONArray();for (int i = 0; i < 10; i++) {JSONObject jb = new JSONObject();jb.put("num", 10*i);jb.put("createTime", "2019-05-09T"+(11+i)+":01:01");ja.add(jb);}map.put("reasult", ja);return map;}
注意header里面加上这3条:
response.setHeader("Access-Control-Allow-Headers", "accept, content-type");response.setHeader("Access-Control-Allow-Methods", "POST");response.setHeader("Access-Control-Allow-Origin", "*");
二、grafana配置
安装grafana,安装SimpleJson插件,在grafana官网,有详细说明。
启动访问,使用admin账户登录,
1、创建数据源:DataSources
type选择SimpleJson类型,URL填入后台服务的API地址,
2、创建面板dashboard
这个面板我已经分享到grafana网站了,可以前去下载:https://grafana.com/dashboards/5075
综上所述,基于SimpleJson数据源,只要配置数据源之后,按正确的方式添加API即可将数据灵活展现在Grafana中,当然SimpleJson只是一个数据源协议载体,理论上可以对接任何类型的后台数据,只要组装成它支持的格式即可。
面板源代码,扩展名成 .json就行,然后import即可:
{"__inputs": [{"name": "DS_DATA-PUBLIC","label": "data-public","description": "由java后台提供物理机信息,java连接物理机上的grpc接口,用于采集传送物理机信息","type": "datasource","pluginId": "grafana-simple-json-datasource","pluginName": "SimpleJson"},{"name": "DS_IP-PUBLIC","label": "ip-public","description": "提供物理机IP","type": "datasource","pluginId": "grafana-simple-json-datasource","pluginName": "SimpleJson"}],"__requires": [{"type": "grafana","id": "grafana","name": "Grafana","version": "5.0.0"},{"type": "datasource","id": "grafana-simple-json-datasource","name": "SimpleJson","version": "1.3.5"},{"type": "panel","id": "graph","name": "Graph","version": "5.0.0"},{"type": "panel","id": "singlestat","name": "Singlestat","version": "5.0.0"},{"type": "panel","id": "text","name": "Text","version": "5.0.0"}],"annotations": {"list": [{"builtIn": 1,"datasource": "-- Grafana --","enable": true,"hide": true,"iconColor": "rgba(0, 211, 255, 1)","name": "Annotations & Alerts","type": "dashboard"}]},"description": "物理机秒级监控页面","editable": true,"gnetId": 5075,"graphTooltip": 2,"id": null,"iteration": 1520931758719,"links": [],"panels": [{"collapsed": false,"gridPos": {"h": 1,"w": 24,"x": 0,"y": 0},"id": 6,"panels": [],"title": "指标","type": "row"},{"content": "# $IP","gridPos": {"h": 3,"w": 3,"x": 0,"y": 1},"id": 4,"links": [],"mode": "markdown","repeat": "IP","repeatDirection": "v","title": "物理机","transparent": false,"type": "text"},{"cacheTimeout": null,"colorBackground": false,"colorValue": true,"colors": ["rgba(0, 190, 250, 0.97)","rgba(237, 129, 40, 0.89)","rgba(245, 54, 54, 0.9)"],"datasource": "${DS_DATA-PUBLIC}","decimals": 2,"format": "percent","gauge": {"maxValue": 100,"minValue": 0,"show": false,"thresholdLabels": false,"thresholdMarkers": true},"gridPos": {"h": 3,"w": 4,"x": 3,"y": 1},"height": "100px","id": 12,"interval": null,"links": [],"mappingType": 1,"mappingTypes": [{"name": "value to text","value": 1},{"name": "range to text","value": 2}],"maxDataPoints": 100,"minSpan": 6,"nullPointMode": "connected","nullText": null,"postfix": "","postfixFontSize": "50%","prefix": "","prefixFontSize": "50%","rangeMaps": [{"from": "null","text": "N/A","to": "null"}],"repeat": "IP","repeatDirection": "v","span": 3,"sparkline": {"fillColor": "rgba(0, 141, 255, 0.1)","full": false,"lineColor": "rgb(0, 133, 253)","show": true},"tableColumn": "","targets": [{"bucketAggs": [{"field": "create_time","id": "2","settings": {"interval": "auto","min_doc_count": 0,"trimEdges": 0},"type": "date_histogram"}],"dsType": "elasticsearch","metrics": [{"field": "value","id": "1","inlineScript": "100-_value","meta": {},"settings": {"script": {"inline": "100-_value"}},"type": "avg"}],"query": "mib:ssCpuIdle AND ip:\"$ip\"","refId": "A","target": "CPU","timeField": "create_time","type": "timeserie"}],"thresholds": "50,80","title": "CPU使用率","type": "singlestat","valueFontSize": "80%","valueMaps": [{"op": "=","text": "N/A","value": "null"}],"valueName": "current"},{"cacheTimeout": null,"colorBackground": false,"colorValue": true,"colors": ["rgba(0, 162, 238, 0.97)","rgba(237, 129, 40, 0.89)","rgba(245, 54, 54, 0.9)"],"datasource": "${DS_DATA-PUBLIC}","format": "percent","gauge": {"maxValue": 100,"minValue": 0,"show": true,"thresholdLabels": false,"thresholdMarkers": true},"gridPos": {"h": 3,"w": 6,"x": 7,"y": 1},"height": "100px","id": 10,"interval": null,"links": [],"mappingType": 1,"mappingTypes": [{"name": "value to text","value": 1},{"name": "range to text","value": 2}],"maxDataPoints": 100,"nullPointMode": "connected","nullText": null,"postfix": "","postfixFontSize": "50%","prefix": "","prefixFontSize": "50%","rangeMaps": [{"from": "null","text": "N/A","to": "null"}],"repeat": "IP","repeatDirection": "v","span": 3,"sparkline": {"fillColor": "rgba(31, 118, 189, 0.18)","full": false,"lineColor": "rgb(31, 120, 193)","show": false},"tableColumn": "","targets": [{"bucketAggs": [{"field": "@timestamp","id": "2","settings": {"interval": "auto","min_doc_count": 0,"trimEdges": 0},"type": "date_histogram"}],"dsType": "elasticsearch","metrics": [{"field": "value","id": "1","inlineScript": "_value*100","meta": {},"settings": {"script": {"inline": "_value*100"}},"type": "avg"}],"query": "mib:disk_percent AND ip:\"$ip\"","refId": "A","target": "RAM","timeField": "create_time","type": "timeserie"}],"thresholds": "70,90","title": "内存使用率","type": "singlestat","valueFontSize": "100%","valueMaps": [{"op": "=","text": "N/A","value": "null"}],"valueName": "avg"},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 0,"y": 4},"hideTimeOverride": false,"id": 2,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "CPU","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "CPU使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 12,"y": 4},"hideTimeOverride": false,"id": 14,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "RAM","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "RAM使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 0,"y": 13},"hideTimeOverride": false,"id": 18,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": true,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "DISK","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "磁盘使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 12,"y": 13},"hideTimeOverride": false,"id": 20,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": true,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "NET","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "网络指标","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "bytes","label": "","logBase": 1,"max": null,"min": null,"show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 0,"y": 22},"hideTimeOverride": false,"id": 16,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "SWAP","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "虚拟内存(SWAP)使用率","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "percent","label": "","logBase": 1,"max": "100","min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": true}]},{"aliasColors": {},"bars": false,"dashLength": 10,"dashes": false,"datasource": "${DS_DATA-PUBLIC}","fill": 1,"gridPos": {"h": 9,"w": 12,"x": 12,"y": 22},"hideTimeOverride": false,"id": 15,"legend": {"alignAsTable": true,"avg": true,"current": true,"max": true,"min": true,"rightSide": false,"show": true,"total": false,"values": true},"lines": true,"linewidth": 1,"links": [],"nullPointMode": "null","percentage": false,"pointradius": 5,"points": false,"renderer": "flot","repeat": "IP","repeatDirection": "v","seriesOverrides": [],"spaceLength": 10,"stack": false,"steppedLine": false,"targets": [{"hide": false,"rawQuery": false,"refId": "A","target": "LOAD","type": "timeserie"}],"thresholds": [],"timeFrom": null,"timeShift": null,"title": "系统负载","tooltip": {"shared": true,"sort": 0,"value_type": "individual"},"transparent": false,"type": "graph","xaxis": {"buckets": null,"mode": "time","name": null,"show": true,"values": []},"yaxes": [{"format": "none","label": "","logBase": 1,"max": null,"min": "0","show": true},{"format": "percent","label": null,"logBase": 1,"max": "100","min": "0","show": false}]}],"refresh": "5s","schemaVersion": 16,"style": "dark","tags": ["node-panlei"],"templating": {"list": [{"allValue": null,"current": {},"datasource": "${DS_IP-PUBLIC}","hide": 0,"includeAll": false,"label": null,"multi": false,"name": "IP","options": [],"query": "show IP","refresh": 1,"regex": "","sort": 0,"tagValuesQuery": "","tags": [],"tagsQuery": "","type": "query","useTags": false}]},"time": {"from": "now-15m","to": "now-1s"},"timepicker": {"hidden": true,"nowDelay": "1s","refresh_intervals": ["1s","5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"time_options": ["5m","15m","1h","6h","12h","24h","2d","7d","30d"]},"timezone": "browser","title": "node-monitor","uid": "VF00gigiz","version": 109
}
作者:风吹散了的回忆
链接:https://www.jianshu.com/p/bbd507a68bb9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。