构建一个数据源插件
简介
Grafana支持广泛的数据源,包括Prometheus、MySQL,甚至datdogg。你很有可能已经从你所设置的系统中可视化了指标。不过,在某些情况下,您已经有了想要添加到Grafana仪表板中的内部度量解决方案。本教程将教会您如何构建对数据源的支持。
在本教程中,您将:
- 构建一个数据源来可视化正弦波
- 使用查询编辑器构造查询
- 使用配置编辑器配置数据源
先决条件
- Grafana > = 7.0
- NodeJS > = 14
- 纱
设置您的环境
在开始构建插件之前,需要为插件开发设置环境。
为了发现插件,Grafana扫描a插件目录,它的位置取决于你的操作系统。
创建一个名为
grafana-plugins
在您首选的工作空间中。找到
插件
属性,并设置插件
财产的路径你grafana-plugins
目录中。请参阅Grafana配置文档更多信息。[paths] plugins = "/path/to/grafana-plugins"
如果Grafana已经在运行,则重新启动它,以加载新的配置。
可选方法:Docker
如果不想在本地机器上安装Grafana,可以使用码头工人.
使用Docker建立Grafana插件开发,运行以下命令:
运行-d -p 3000:3000 -v "$(pwd)"/ var/lib/grafana/plugins——name=grafana grafana/grafana:7.0.0 .
由于Grafana只在启动时加载插件,所以在添加或删除插件时需要重新启动容器。
Docker重启grafana
创建一个新插件
现代web开发的工具很难让你理解。虽然您当然可以编写自己的webpack配置,但在本指南中,您将使用grafana create-plugin工具
Grafanacreate-plugin工具是一个CLI应用程序,它简化了Grafana插件的开发,因此您可以专注于代码。该工具为您提供了启动器插件和所有所需的配置。
在插件目录中,使用create-plugin从模板创建一个插件:
npx @grafana / create-plugin
更改目录到你新创建的插件:
cd my-plugin
安装依赖项:
线安装
编译插件:
纱线开发
重新启动Grafana服务器以发现您的插件。
打开Grafana然后去配置->插件.确保你的插件在那里。
默认情况下,Grafana在发现插件时记录日志:
INFO[01-01|12:00:00] registered plugin logger=plugins name=my-plugin . INFO[01-01|12:00:00
插件的剖析
插件有不同的形状和大小。在我们深入讨论之前,让我们看看它们共有的一些属性。
你创建的每个插件都至少需要两个文件:plugin.json
而且module.ts
.
plugin.json
当Grafana启动时,它会扫描插件目录中包含plugin.json
文件。的plugin.json
文件包含关于你的插件的信息,并告诉Grafana你的插件需要什么功能和依赖。
虽然某些插件类型可以有特定的配置选项,但让我们看看强制性的配置选项:
类型
告诉Grafana应该期待什么类型的插件。Grafana支持三种类型的插件:面板
,数据源
,应用程序
.的名字
是用户将在插件列表中看到的内容。如果您正在创建一个数据源,这通常是它所连接的数据库的名称,例如Prometheus、PostgreSQL或Stackdriver。id
唯一标识您的插件,并应以您的Grafana用户名开始,以避免与其他插件冲突。注册一个Grafana账户来声明您的用户名。
控件的所有可用配置设置plugin.json
,请参阅plugin.jsonSchema.
module.ts
发现插件后,Grafana加载module.ts
文件,你的插件的入口点。module.ts
公开插件的实现,这取决于您正在构建的插件的类型。
具体地说,module.ts
需要公开扩展的对象GrafanaPlugin,可以是以下任何一个:
数据源插件
Grafana中的数据源必须扩展DataSourceApi
接口,它要求您定义两个方法:查询
而且testDatasource
.
的查询
方法
的查询
方法是任何数据源插件的核心。它接受来自用户的查询,从外部数据库检索数据,并以Grafana可识别的格式返回数据。
async查询(选项:DataQueryRequest): Promise
的选项
对象包含查询,或者目标,以及上下文信息,如当前时间间隔。使用此信息查询外部数据库。
这个词目标起源于Graphite,早期的Grafana是唯一受支持的数据源。随着Grafana获得对更多数据源的支持,术语“目标”成为任何类型查询的同义词。
测试数据源
testDatasource
为数据源实现运行状况检查。例如,每当用户单击保存和测试按钮,更改连接设置后。
异步testDatasource ()
数据帧
现在有无数不同的数据库,每一个都有自己的查询数据的方法。为了能够支持所有不同的数据格式,Grafana将数据合并为一个统一的数据结构,称为数据帧.
方法创建和返回数据帧查询
方法。在这一步中,您将更改starter插件中的代码以返回一个正弦波.
在水流中
查询
方法中删除代码地图
函数。的
查询
方法现在看起来像这样:async query(options: DataQueryRequest
): Promise {const {range} = options;const from = range!.to.valueOf();Const data = options.targets。地图(target => { // Your code goes here. }); return { data }; } 在
地图
函数,使用lodash /违约
包用于为未设置的查询属性设置默认值:const query = defaults(target, defaultQuery);
创建一个包含时间字段和数字字段的数据帧:
const frame = new MutableDataFrame({refId: query.)refId,字段:[{name: 'time',类型:FieldType。time}, {name: 'value',类型:FieldType。Number},],});
refId
需要设置来告诉Grafana是哪个查询生成了这个日期帧。
接下来,我们将向数据帧添加实际值。不要担心用于计算值的数学。
创建两个辅助变量:
//时间范围的持续时间,单位为毫秒。Const duration = to - from;// step决定点之间的时间距离(ms)。Const step = duration / 1000;
将值添加到数据帧中:
For (let t = 0;T < duration;T += step){帧。add({时间:从+ t,值:数学。sin(2 *数学。)PI * t) /持续时间)});}
的
frame.add ()
接受一个对象,其中键对应数据帧中每个字段的名称。返回数据帧:
返回帧;
重新构建插件并尝试它。
您的数据源现在正在发送Grafana可以可视化的数据帧。接下来,我们将看看如何通过定义a来控制正弦波的频率查询.
在本例中,我们从当前时间范围生成时间戳。这意味着无论您使用什么时间范围,都将得到相同的图表。实际上,您应该使用数据库返回的时间戳。
定义查询
大多数数据源都提供了查询特定数据的方法。MySQL和PostgreSQL使用SQL,而Prometheus有自己的查询语言,称为PromQL.无论数据库使用什么查询语言,Grafana都允许您构建对它的支持。
通过实现自己的数据源,为数据源添加对自定义查询的支持查询编辑器这是一个React组件,它允许用户通过用户友好的图形界面构建自己的查询。
查询编辑器可以像文本字段一样简单,用户可以在其中编辑原始查询文本,也可以提供更用户友好的表单,其中包含下拉菜单和开关,稍后将其转换为原始查询文本,然后再将其发送到数据库。
定义查询模型
设计查询编辑器的第一步是定义它查询模型.查询模型定义数据源的用户输入。
我们想要能够控制正弦波的频率,所以让我们添加另一个性质。
添加一个名为
频率
对于查询模型:src / types.ts
导出MyQuery扩展DataQuery {queryText?:字符串;常数:数量;频率:数量;}
将默认值设置为new
频率
属性:export const defaultQuery: Partial
={常量:6.5,频率:1.0,};
将模型绑定到表单
既然已经定义了希望支持的查询模型,下一步就是将模型绑定到表单。的FormField
文本字段组件是否来自grafana / ui
这使您可以注册一个侦听器,该侦听器将在表单字段值更改时被调用。
向查询编辑器添加一个新的表单字段,以控制新的频率属性。
QueryEditor.tsx
const {queryText, constant, frequency} =查询;
. 为新属性添加一个事件监听器。
onFrequencyChange = (event: ChangeEvent
) => {const {onChange, query, onRunQuery} = this.props;onChange({…查询,频率:parseFloat(event.target.value) }); // executes the query onRunQuery(); }; 注册听众,
onFrequencyChange
称onChange
使用来自表单字段的值更新当前查询。onRunQuery ();
告诉Grafana在每次更改后运行查询。对于快速查询,建议这样做,以提供响应更快的体验。
使用属性
新的查询模型现在可以在我们的查询
方法。
在
查询
方法,使用频率
属性来调整我们的方程。框架。add({时间:从+ t,值:数学。sin(2 *数学。)PI * query.frequency * t) / duration)});
配置数据源
要访问特定的数据源,通常需要配置主机名、凭证或身份验证方法等。一个配置编辑器让你的用户配置你的数据源插件来满足他们的需求。
配置编辑器看起来类似于查询编辑器,因为它定义了一个模型并将其绑定到一个表单。
因为在正弦波示例中,我们实际上没有连接到外部数据库,所以实际上不需要太多选项。为了向您展示如何添加选项,我们将添加波决议作为一个选项。
分辨率控制数据点之间的时间距离。更高的分辨率意味着更多的点靠得更近,代价是要处理更多的数据。
定义选项模型
添加一个名为
决议
到期权模型。types.ts
导出接口MyDataSourceOptions扩展DataSourceJsonData{路径?:字符串;决议?:数量;}
将模型绑定到表单
就像查询编辑器一样,配置编辑器中的表单字段在值更改时调用注册的侦听器。
向查询编辑器添加一个新的表单字段,以控制新的解析选项。
ConfigEditor.tsx
为新选项添加一个事件监听器。
onResolutionChange = (event: ChangeEvent
) => {const {onOptionsChange, options} = this.props;const jsonData ={…jsonData,解析:parseFloat(event.target.value),};onOptionsChange({…选项,jsonData }); }; 的
onResolutionChange
监听器调用onOptionsChange
使用来自表单字段的值更新当前选项。
使用选项
创建一个名为
决议
到数据源
类。导出类DataSource extends DataSourceApi
{分辨率:number;构造函数(instanceSettings: DataSourceInstanceSettings ) {super(instanceSettings);这一点。resolution = instancessets . jsondata .resolution || 1000.0;} //… 在
查询
方法,使用决议
属性计算步长。src / DataSource.ts
Const step = duration / this.resolution;
从外部API获取数据
到目前为止,您已经生成了数据源返回的数据。更现实的用例是从外部API获取数据。
你可以用axios或者是获取API要发出请求,我们建议使用getBackendSrv
函数来自grafana /运行时包中。
的主要优点getBackendSrv
它通过Grafana服务器代理请求,而不是从浏览器发出请求。当向外部API发出经过身份验证的请求时,强烈建议这样做。有关验证外部请求的更多信息,请参见为数据源插件添加身份验证.
进口
getBackendSrv
.src / DataSource.ts
import {getBackendSrv} from "@grafana/runtime"
创建一个helper方法
doRequest
然后使用datasourceRequest
方法向API发出请求。取代https://api.example.com/metrics
来指向您自己的API端点。async doRequest(query: MyQuery) {const result = await getBackendSrv()。datasourceRequest({ method: "GET", url: "https://api.example.com/metrics", params: query, }) return result; }
为每个查询发出请求。
Promises.all
等待所有请求完成后再返回数据。async query(options: DataQueryRequest
): Promise {const promises = options.targets.map((query) => this.doRequest(query).then((response) => {const frame = new MutableDataFrame({refId: query。refId, fields: [{name: "Time", type: FieldType.]time},{名称:“值”,类型:FieldType。Number},],});response.data。forEach((point: any) => {frame.appendRow([point: any])时间,point.value]);});返回帧;}));return Promise.all(promises).then((data) => ({data}));}
总结
在本教程中,您为Grafana构建了一个完整的数据源插件,该插件使用查询编辑器来控制要可视化的数据。您已经添加了一个数据源选项,通常用于设置连接选项等。
了解更多
了解如何进一步改进插件,请阅读我们的高级指南: