在石墨,我们之前使用 ELK 搭了一套监控图表,由于一些原因,比如:
所以调研了一下,选择用 StatsD + Grafana + InfluxDB 搭建一套新的监控系统。
➜ Desktop docker-machine start
Starting "default"...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Machine "default" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
➜ Desktop docker-machine env
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/nswbmw/.docker/machine/machines/default"
export DOCKER_MACHINE_NAME="default"
# Run this command to configure your shell:
# eval $(docker-machine env)
➜ Desktop eval $(docker-machine env)
➜ Desktop docker ps
docker run -d \
--name docker-statsd-influxdb-grafana \
-p 3000:9000 \
-p 8083:8083 \
-p 8086:8086 \
-p 22022:22 \
-p 8125:8125/udp \
samuelebistoletti/docker-statsd-influxdb-grafana:latest
'use strict';
const StatsD = require('node-statsd'),
client = new StatsD({
host: '192.168.99.100',
port: 8125
});
setInterval(function () {
const responseTime = Math.floor(Math.random() * 100);
client.timing('api', responseTime, function (error, bytes) {
if (error) {
console.error(error);
} else {
console.log(`Successfully sent ${
bytes} bytes, responseTime: ${
responseTime}`);
}
});
}, 1000);
'use strict';
const StatsD = require('node-statsd');
const config = require('config');
module.exports = new StatsD({
host: config.statsd.host,
port: config.statsd.port
});
'use strict';
const statsdClient = require('../lib/statsd');
module.exports = function () {
return function *statsd(next) {
const routerName = this.route ? this.route.handler.controller + '.' + this.route.handler.action : null;
const start = Date.now();
yield next;
const spent = Date.now() - start;
if (routerName) {
statsdClient.timing(`api.${
routerName}`, spent);
statsdClient.timing('api', spent);
}
};
};
app.use(require('./middlewares/statsd')());
const routerName = this.routerName;
我们 API 有近百个接口,要是每次都去手动创建并配置图表那就费老劲了,而且每次创建的图表的配置都差不多,于是我寻思寻找一些捷径。我发现 Grafana 有 Template 的功能,然而尝试了下并没有搞明白怎么用。。我又发现 Grafana 有 Import 的功能,于是先把配置好的图表先导出 JSON,然后不断复制粘贴修改,保存尝试 Import 看下效果 ,最后成功。
注意:导出的 JSON 中 rows 代表了每一行,每个 row 中有一个 panels 数组存储了每一个 Graph(下图一个 row 有两个 Graph),每个 Graph 有一个 id 字段是递增的(如:1、2、3...),targets 下每个曲线的 refId 是递增的(如:A、B、C...),记得修正过来,否则无法正常显示图表。
最终我写了个脚本,运行后生成了每个接口的 JSON 文件,30 多个接口导出了 30 多个文件,每次 Import 那也要 30 几次。机智的我怎么可能就此放弃(其实是懒),应该还有更省事的方法,我在浏览器中导入的时候,在控制台看了下 Grafana 的网络请求,发现导入时调用的是:
POST https://xxx:3006/api/dashboards/import
而且 JSON 文件的数据直接放在 post 请求体里,那这样就好办了,也不用生成文件了,最后生成的配置放到了一个数组里,用 co + co-request 循环调用上面那个接口导入就好了,真正做到一键导入数据。
以下是一个 dashboard 及对应的 JSON 配置:
{
"id": 32,
"title": "API file",
"tags": [],
"style": "dark",
"timezone": "browser",
"editable": true,
"hideControls": false,
"sharedCrosshair": false,
"rows": [
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "api-influxdb",
"editable": true,
"error": false,
"fill": 2,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 1,
"isNew": true,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"minSpan": 6,
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "tps",
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$interval"
],
"type": "time"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "api.file.show.timer.count",
"policy": "default",
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"value"
],
"type": "field"
},
{
"params": [],
"type": "mean"
}
]
],
"tags": []
}
],
"timeFrom": null,
"timeShift": null,
"title": "api.file.show.count",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"datasource": "api-influxdb",
"editable": true,
"error": false,
"fill": 1,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 2,
"isNew": true,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"minSpan": 5,
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$interval"
],
"type": "time"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "api.file.show.timer.mean",
"policy": "default",
"refId": "A",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"value"
],
"type": "field"
},
{
"params": [],
"type": "mean"
}
]
],
"tags": [],
"alias": "mean"
},
{
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$interval"
],
"type": "time"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "api.file.show.timer.mean_90",
"policy": "default",
"refId": "B",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"value"
],
"type": "field"
},
{
"params": [],
"type": "mean"
}
]
],
"tags": [],
"alias": "mean_90"
},
{
"dsType": "influxdb",
"groupBy": [
{
"params": [
"$interval"
],
"type": "time"
},
{
"params": [
"null"
],
"type": "fill"
}
],
"measurement": "api.file.show.timer.upper_90",
"policy": "default",
"refId": "C",
"resultFormat": "time_series",
"select": [
[
{
"params": [
"value"
],
"type": "field"
},
{
"params": [],
"type": "mean"
}
]
],
"tags": [],
"alias": "upper_90"
}
],
"timeFrom": null,
"timeShift": null,
"title": "api.file.show.timer",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"title": "Row"
}
],
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"templating": {
"list": []
},
"annotations": {
"list": []
},
"refresh": "5s",
"schemaVersion": 12,
"version": 2,
"links": [],
"gnetId": null
}
我们正在招聘!
[北京/武汉] 石墨文档 做最美产品 - 寻找中国最有才华的工程师加入