7

tars-grafana后端数据源插件要点

 2 years ago
source link: https://www.zoucz.com/blog/2020/12/10/2c882220-3a3c-11eb-90b5-eb40e9720ed0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Tars微服务框架 在从腾讯开源出去的过程中,运营体系被剥离了两个很重要的能力,一个是容器管理,一个是监控告警。 我要说话

为了让开源的Tars重新拥有这两项能力,而能力的支持尽量对Tars本身的侵入性小,我前段时间分别做了一个tars和k8s生命周期融合的插件、一个tars grafana插件,来分别支持容器管理和监控告警。后续看看能不能整理后开源出来吧。 我要说话

此文主要讲讲grafana告警插件,因为开发的过程中还是踩了不少坑,先回忆一下,记录一些要点,供未来的自己或网友参考。 我要说话

grafana插件开发文档 我要说话

技术选型背景

首先必须得承认,grafana是一个非常优秀的看板&监控开源项目。最开始我本来是想用Prometheus来做这个告警的,后来发现Prometheus自带看板比较差,官方也采用了grafana这个项目,深入了解之后发现grafana更加契合tars这种,已经有了上报数据,没有告警能力的情况。 我要说话

理论上来说,数据不需要重复做上报/收集了,这样Prometheus的意义就失去了一大半;而grafana则更好是读取数据源,配置告警项,完美。 我要说话

然而后来的开发过程中发现,项目本身的优秀,并不代表对开发者友好。它的文档给开发工作带来了太多的阻碍了。最终设计: 我要说话

image.png我要说话

无法配置告警的场景

文档中并没有描述: 我要说话

  • 带模板变量的Panel无法配置告警
  • 应用了Transform的Panel无法配置告警

轻飘飘的两个特性,却会在开发过程中造成血案,因为文档中压根没有提及(至少截止v7.3版本未提及)这两点特性,只有在付出了大量工作量后,才能发现这俩特性,导致之前的方案被推翻我要说话

说干就干,一开始基于tars的mysql表写了一堆sql,以及针对时间序列数据格式的转换。Dashboard做完之后,才发现依赖模板变量的mysql数据源方式行不通。 我要说话

转换方向,后来采用自己开发后端数据源插件的方案,第一版接口返回了比较通用的格式,在Panel中使用Transform来转换数据格式,做完后才发现应用了Transform的Panel无法配置告警。 我要说话

插件后端读取前端的配置数据

插件配置有两块,一块是后端数据源配置
image.png我要说话

另一块是Panel查询配置
image.png我要说话

这两个配置在前端设置后,golang后台如何获取配置的值呢?其中Panel查询配置,在脚手架工程代码中能比较容易的看到。而后端数据源配置,试了下面几种渠道都没找到,印象深刻: 我要说话

  • 找遍google、baidu
  • 翻遍官网文档
  • 加了四五个grafana技术交流群
  • 咨询公司内曾经做过插件开发的同事

均没有得到正确答案。最终解决的方法是,看后端插件SDK的代码 + 加log定位,找到了如何读取这个配置。 入口并不深,但是对于首次接触的开发者来说,真的不好找。 我要说话

// 返回 datasource.ServeOpts.结构对象
func newDatasource() datasource.ServeOpts {
    // 创建插件的manager对象(instance manager)
    // 当实例第一次被创建或者数据源配置更改时,传入 `NewInstanceManger` 的函数 newDataSourceInstance 被调用
    im := datasource.NewInstanceManager(newDataSourceInstance)
    //创建 data source结构对象
    ds := &TarsDatasource{
        im: im,
    }
    //创建并返回sdk的datasource.ServeOpts结构对象,传入datasource对象作为查询和监控检查的handler
    return datasource.ServeOpts{
        QueryDataHandler:   ds,
        CheckHealthHandler: ds,
    }
}
func (td *TarsDatasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
}
func (td *TarsDatasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
}
func newDataSourceInstance(setting backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
}

贴一下关键代码。
真正的方式是在QueryData或者CheckHealth函数里边,通过req.PluginContext.DataSourceInstanceSettings.JSONDatareq.PluginContext.DataSourceInstanceSettings. DecryptedSecureJSONData来获取。入口不深,但是藏在PluginContext里边,文档又没有描述,天知道呢? 我要说话

可能有人会奇怪,其实生命周期函数已经传递了这个DataSourceInstanceSettings参数。为何第一时间没发现呢? 这又涉及到了下一个环环相扣的坑。 我要说话

插件后端的生命周期不生效

首先,官网本身并没有对插件生命周期很细致的描述。下面是脚手架工程中的函数注释: 我要说话

// 这个函数描述的是第一次实例化或者配置变化时被调用,但是貌似并不会真的被调用
func newDataSourceInstance(setting backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
    PluginConfigObj.SetConfigBySettings(&setting)
    TarCheckIns.StartCheckTarsDashboard()
    return &instanceSettings{
        httpClient: &http.Client{},
    }, nil
}

这个函数其实 并不会 生效,这也是为啥第一时间死活找不到如何获取数据源配置。我要说话

用协程启动Webhook监听失败

尝试在插件加载起来的时候,同时开启供发送自定义方式告警的Webhook。然而很蛋疼的发现,main函数入口、datasource.Serve(newDatasource()) 入口逻辑中,用协程启动端口监听都不可行,插件进程拉起后会立即被杀掉。
这种奇葩的现象,文档中更不可能说明原因了。最终给放到了CheckHealth中去做首次拉起,以及一个定时任务中去做check拉起。无奈。我要说话

本文链接:https://www.zoucz.com/blog/2020/12/10/2c882220-3a3c-11eb-90b5-eb40e9720ed0/我要说话

☞ 参与评论我要说话


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK