bosun grafana template

这篇文章是在上篇增加了bosun grafana plugin之后,在设置bosun的grafana dashboard时,发现了dashboard template的一个问题的临时处理办法的总结。

背景

比如我们在设置dashboard时,一般一个dashboard是有多个图的: 在设置图的query的时候,每个图都要修改host参数,如: 也就是说,如果有10张图,那我们得修改十次这个值,所以当一个dashboard较多图的时候,设置template是很有必要的,我们可以将查询语句统一写为:

q("sum:rate{counter,,1}:os.cpu(host=$host)","$start","")  

然后设置template:

具体可以参考官方文档

问题

但是bosun的grafana plugin貌似有个bug,直接报错了:

我又不懂javascript,怎么办?试了下,使用custom是可以的,不过需要自己手动填,如"192.168.1.1,192.168.1.2":

当然是非常不靠谱的方法,如机器多,填起来也麻烦,每当一个被监控机器加入的时候,又得手动填,更麻烦了。

在找了很多资料无果的情况下,只好自己尝试解决了。

首先是想找到有没有什么配置文件里面定义了这个值,只要我们获取下bosun api返回的tagv,然后用sed之类的更新下配置文件,是不是就可以解决了呢?

不过很遗憾,配置是写在一个sqlite3数据库里的,如下:

一整串json!借助了这个格式化输出json的网站,看了下结构,主要涉及的是以下key:

"current": {
    "text": "192.168.1.1",
    "value": "192.168.1.1"
}

"options": [
    {
        "selected": true, 
        "text": "192.168.1.1", 
        "value": "192.168.1.1"
    }
    {
        "selected": false, 
        "text": "192.168.1.2", 
        "value": "192.168.1.2"
    }
]

"query": "192.168.1.1,192.168.1.2"

测试了update指令,更新了数据库,发现确实可以在页面上显示出增加了主机。万事俱备,只欠写个python脚本了。

解决方法

以下是我用来更新template的python脚本,仅为能用而已,没有考虑错误处理等:

#!/usr/local/bin/python
#coding:utf8

import sqlite3  
import re  
import json  
import requests

granfa_db = "/var/lib/grafana/grafana.db"  
template_titles = {"host":"单个机器数据模板", "game":"单个游戏服数据模板"}  
bosun_api = {"host":"http://localhost:8070/api/tagv/host/scollector.hi", "game":"http://localhost:8070/api/tagv/node/application.game.hi"}  
regexs = {'options':r'"options":\[[^]]+\]', 'query':r'"query":"[^"]+"'}

def get_template_data(query):  
    if query == "host" or query == "game":
        conn = sqlite3.connect(granfa_db)
        cursor = conn.execute('''select data from dashboard where title = "%s"''' % template_titles[query])
        return cursor.fetchall()[0][0]
    else:
        return []

def update_template(query, data):  
    if query == "host" or query == "game":
        conn = sqlite3.connect(granfa_db)
        cursor = conn.execute('''update dashboard set data = '%s' where title = "%s"''' % (data, template_titles[query]))
        conn.commit()

def query_bosun(query):  
    if query == "host" or query == "game":
        return [item for item in json.loads(requests.get(bosun_api[query]).text)]
    else:
        return []

def assemble_options(query):  
    if query == "host" or query == "game":
        options = '''{"selected":false,"text":"A","value":"A"}'''
        query_ret = query_bosun(query)
        options_ret = []
        for item in query_ret:
            options_ret.append(re.sub('A', item, options))
        return '''"options":[%s]''' % re.sub("false", "true", ",".join(options_ret), 1)
    else:
        return []

def assemble_query(query):  
    if query == "host" or query == "game":
        queries = '''"query":"A"'''
        query_ret = ",".join(query_bosun(query))
        return '''"query":"%s"''' % query_ret
    else:
        return ""

def assemble_data(query):  
    if query == "host" or query == "game":
        new_data = re.sub(regexs['options'], assemble_options(query), get_template_data(query))
        new_data = re.sub(regexs['query'], assemble_query(query), new_data)
        return new_data

if __name__ == "__main__":  
    new_data = assemble_data("host")
    update_template("host", new_data)
    new_data = assemble_data("game")
    update_template("game", new_data)

然后设置定时任务,每半小时更新一次,足够了。

效果如下:

缺陷

当然是不能实时更新了,还要自己写脚本这么蛋疼。

后记

目前(2016/12/05)最新版本的bosun插件已经没有上述问题了。