我用Grafana制作了一个关于东京和大阪新冠病毒每日新增感染者数量的图表
不,与Covid-19几乎无关。这是关于我探索用自己编写的脚本作为数据源来替代Prometheus,并且欺骗Grafana的笔记。
做过的事情
我使用Python/Flask创建的简易Web应用程序被指定为Grafana的数据源。
该Web应用程序扮演了一个伪造的Prometheus角色。
如果数据源是Prometheus的话,Grafana会向Web应用程序发送一系列类似以下的请求,只要对每个请求做出合适的响应,它就会绘制相应的图形。
127.0.0.1 - - [28/Sep/2021 16:36:42] "POST /api/v1/query HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:52] "POST /api/v1/labels HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:52] "GET /api/v1/label/__name__/values?start=1632825412&end=1632847012 HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:52] "GET /api/v1/metadata HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:53] "POST /api/v1/labels HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:53] "GET /api/v1/label/__name__/values?start=1632825413&end=1632847013 HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:53] "GET /api/v1/metadata HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:53] "GET /api/v1/label/__name__/values?start=1632825413&end=1632847013 HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:36:55] "POST /api/v1/series HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:37:10] "POST /api/v1/labels HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:37:10] "POST /api/v1/query_exemplars HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:37:10] "GET /api/v1/label/__name__/values?start=1632825430&end=1632847030 HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:37:10] "GET /api/v1/metadata HTTP/1.1" 200 -
127.0.0.1 - - [28/Sep/2021 16:37:19] "POST /api/v1/query_range HTTP/1.1" 200 -

制作方法
创建一个Ubuntu 20的虚拟机

2. 安装 Grafana
通过SSH连接并执行以下操作。
(参考)Grafana – 在Debian或Ubuntu上安装
https://grafana.com/docs/grafana/latest/installation/debian/
$ sudo apt-get install -y apt-transport-https
$ sudo apt-get install -y software-properties-common wget
$ wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
$ echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
$ sudo apt-get update
$ sudo apt-get install -y grafana
$ sudo systemctl daemon-reload
$ sudo systemctl start grafana-server
$ sudo systemctl enable grafana-server.service
$ sudo systemctl status grafana-server

安装Python/Flask
$ sudo apt install -y python3-flask
制作一个“假冒的普罗米修斯”。
请创建一个名为pseudo.py的文件。目录位置和用户都可以随意选择,不必为root。
另外,关于Prometheus的各个API返回的数据类型可以参考以下链接:
(参考)Proetheus – HTTP API
https://prometheus.io/docs/prometheus/latest/querying/api/
只需提供一个选项:
虽然跳过了对各个API返回类似响应的部分的解释,但是’/api/v1/query_range’接口中生成数据的处理大致如下:
获取东京的感染者数列表(CSV文件)。
https://catalog.data.metro.tokyo.lg.jp/dataset/t000010d0000000068/resource/c2d997db-1450-43fa-8037-ebb11ec28d4c
将CSV文件的第五列作为日期,每个新阳性患者对应一条记录,统计同一日期的记录数量。
将统计数据转换为数组形式,并使其适应Grafana的格式。
取得大阪的感染者列表(CSV文件)。由于字符编码是sjis,需要将其转换为utf-8。
https://covid19-osaka.info/
由于此数据已预先按日期汇总,因此将第一列视为日期,第三列视为新增阳性人数,并将其读入数组中。
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/api/v1/query', methods=["POST"])
def query():
return "{}"
@app.route('/api/v1/labels', methods=["POST"])
def labels():
return '''
{
"status": "success",
"data": [
"__name__",
"region"
]
}
'''
@app.route('/api/v1/label/__name__/values')
def label__name__values():
return '''
{
"status": "success",
"data": [
"new-cases"
]
}
'''
@app.route('/api/v1/label/region/values')
def label_region_values():
return '''
{
"status": "success",
"data": [
"tokyo", "osaka"
]
}
'''
@app.route('/api/v1/metadata')
def metadata():
return '''
{
"status": "success",
"data": [
"new-cases": [
{
"type": "counter",
"help": "Number of new cases",
"unit": ""
}
]
]
}
'''
@app.route('/api/v1/series', methods=["POST"])
def series():
return '''
{
"status": "success",
"data": [
{
"__name__": "new-cases",
"region": "tokyo"
},
{
"__name__": "new-cases",
"region": "osaka"
}
]
}
'''
@app.route('/api/v1/query_exemplars', methods=["POST"])
def query_exemplars():
return '''
{
"status": "success",
"data": [
{
"seriesLabels": {
},
"exemplars": [
]
}
]
}
'''
@app.route('/api/v1/query_range', methods=["POST"])
def query_range():
import json
tokyo = fetch_tokyo()
osaka = fetch_osaka()
return '''
{
"status": "success",
"data": {
"resultType": "matrix",
"result": [
{
"metric": {
"__name__": "new-cases",
"region": "tokyo"
},
"values":
''' + json.dumps(tokyo) + '''
},
{
"metric": {
"__name__": "new-cases",
"region": "osaka"
},
"values":
''' + json.dumps(osaka) + '''
}
]
}
}
'''
def fetch_tokyo():
import os
import csv
import datetime
import urllib
if(not os.path.exists("tokyo.csv")):
urllib.request.urlretrieve("https://stopcovid19.metro.tokyo.lg.jp/data/130001_tokyo_covid19_patients.csv", "tokyo.csv")
f = open("tokyo.csv")
r = csv.reader(f)
h = next(r)
d = {}
for l in r:
t = datetime.datetime.strptime(l[4], "%Y-%m-%d")
if(t not in d):
d[t] = 0
d[t] = d[t] + 1
a = []
for k in d:
a.append([k.timestamp(), d[k]])
return a
def fetch_osaka():
import os
import csv
import datetime
import urllib
import subprocess
if(not os.path.exists("osaka-u.csv")):
urllib.request.urlretrieve("https://covid19-osaka.info/data/summary.csv", "osaka.csv")
subprocess.run("iconv -f sjis -t utf8 osaka.csv -o osaka-u.csv", shell=True)
f = open("osaka-u.csv")
r = csv.reader(f)
h = next(r)
a = []
for l in r:
t = datetime.datetime.strptime(l[0], "%Y-%m-%d")
a.append([t.timestamp(), l[2]])
return a
启动玩笑模式
在9090端口上,先前创建的假Prometheus进行启动。
本地的Grafana只是用于读取数据,所以无需开放防火墙端口。
# FLASK_APP=pseudo.py flask run --port=9090
6. 设置Grafana的数据源
选择使用Prometheus作为数据源的类型,并指定从“http://localhost:9090”读取。



制作仪表板
应该能够看到作为指标的“新增病例”,然后将其呈现在图表上。








最后
希望Grafana作为通用BI工具的应用范围更广,但不知道怎么样… 比我想的更贵更麻烦。
希望Prometheus能更轻便,更方便使用。