添加对变量的支持
变量是值的占位符,您可以使用它们来创建模板查询和仪表板或面板链接。有关变量的更多信息,请参阅 模板和变量。
在本指南中,您将了解如何将类似于这样的查询字符串
SELECT * FROM services WHERE id = "$service"
转换为
SELECT * FROM services WHERE id = "auth-api"
Grafana 提供了一些辅助函数来在字符串模板中插入变量。让我们看看您如何在您的插件中使用它们。
向插件添加变量
在面板插件中插入变量
对于面板,replaceVariables
函数在 PanelProps
中可用。
将 replaceVariables
添加到参数列表中,并传递一个用户定义的模板字符串给它
export function SimplePanel({ options, data, width, height, replaceVariables }: Props) {
const query = replaceVariables('Now displaying $service');
return <div>{query}</div>;
}
在数据源插件中插入变量
对于数据源,您需要使用getTemplateSrv
,该函数返回一个TemplateSrv
实例。
-
从
runtime
包中导入getTemplateSrv
import { getTemplateSrv } from '@grafana/runtime';
-
在您的
query
方法中,使用用户定义的模板字符串调用replace
方法async query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse> {
const query = getTemplateSrv().replace('SELECT * FROM services WHERE id = "$service"', options.scopedVars);
const data = makeDbQuery(query);
return { data };
}
从您的插件中设置变量
您不仅可以从插件中读取变量的值,还可以更新变量。使用locationService.partial(query, replace)
。
以下示例展示了如何更新名为service
的变量。
query
包含您想要更新的查询参数。控制变量的查询参数以var-
为前缀。replace: true
指示Grafana更新当前URL状态,而不是创建新的历史记录条目。
import { locationService } from '@grafana/runtime';
locationService.partial({ 'var-service': 'billing' }, true);
每次更新变量时,Grafana都会查询数据源。频繁更新变量可能会减慢Grafana的速度,并导致用户体验不佳。
为您的数据源添加查询变量的支持
查询变量是一种允许您查询数据源以获取值的变量类型。通过为您的数据源插件添加查询变量的支持,用户可以基于您的数据源创建动态仪表板。
让我们首先定义一个变量查询的查询模型。
export interface MyVariableQuery {
namespace: string;
rawQuery: string;
}
要使数据源支持查询变量,请覆盖您的DataSourceApi
类中的metricFindQuery
。该metricFindQuery
函数返回一个包含MetricFindValue
的数组,该数组具有一个名为text
的单个属性。
async metricFindQuery(query: MyVariableQuery, options?: any) {
// Retrieve DataQueryResponse based on query.
const response = await this.fetchMetricNames(query.namespace, query.rawQuery);
// Convert query results to a MetricFindValue[]
const values = response.data.map(frame => ({ text: frame.name }));
return values;
}
默认情况下,Grafana为简单的文本查询提供基本的查询模型和编辑器。如果这满足您的需求,请将查询类型保留为string
。
async metricFindQuery(query: string, options?: any)
让我们创建一个自定义查询编辑器,以便用户可以编辑查询模型。
-
创建一个
VariableQueryEditor
组件src/VariableQueryEditor.tsximport React, { useState } from 'react';
import { MyVariableQuery } from './types';
interface VariableQueryProps {
query: MyVariableQuery;
onChange: (query: MyVariableQuery, definition: string) => void;
}
export const VariableQueryEditor = ({ onChange, query }: VariableQueryProps) => {
const [state, setState] = useState(query);
const saveQuery = () => {
onChange(state, `${state.query} (${state.namespace})`);
};
const handleChange = (event: React.FormEvent<HTMLInputElement>) =>
setState({
...state,
[event.currentTarget.name]: event.currentTarget.value,
});
return (
<>
<div className="gf-form">
<span className="gf-form-label width-10">Namespace</span>
<input
name="namespace"
className="gf-form-input"
onBlur={saveQuery}
onChange={handleChange}
value={state.namespace}
/>
</div>
<div className="gf-form">
<span className="gf-form-label width-10">Query</span>
<input
name="rawQuery"
className="gf-form-input"
onBlur={saveQuery}
onChange={handleChange}
value={state.rawQuery}
/>
</div>
</>
);
};Grafana在文本字段失去焦点(
onBlur
)时保存查询模型,然后它预览由metricFindQuery
返回的值。onChange
的第二个参数允许您设置一个文本表示的查询,该查询将出现在变量列表中变量的名称旁边。 -
配置您的插件以使用查询编辑器
import { VariableQueryEditor } from './VariableQueryEditor';
export const plugin = new DataSourcePlugin<DataSource, MyQuery, MyDataSourceOptions>(DataSource)
.setQueryEditor(QueryEditor)
.setVariableQueryEditor(VariableQueryEditor);
这就完了!您现在可以通过向仪表板添加查询变量来尝试插件。
使用模板变量
模板变量 允许用户创建基于输入动态变化的仪表盘。由于变量在 Grafana 中已经存在很长时间,许多用户期望它们能够支持他们安装的任何数据源。
插值模板变量
要插值模板变量,您需要从 @grafana/runtime
包导入 getTemplateSrv()
函数
import { getTemplateSrv } from '@grafana/runtime';
getTemplateSrv()
函数返回一个 TemplateSrv
实例,该实例提供用于处理模板变量的方法。其中最重要的是 replace()
方法,它接受一个包含变量的字符串作为输入,并返回一个插值字符串,其中变量已被用户选择的值所替换。
例如,如果您有一个名为 instance
的变量,以下代码将用其对应值替换该变量
getTemplateSrv().replace("I'd like $instance, please!");
// I'd like server-1, please!
replace()
方法甚至可以处理内置变量,如 $__from
和 $__to
。
就是这样!对于大多数用例,您只需做这些就可以在您的数据源中添加对模板变量的支持。请注意,决定哪些字段将支持模板变量由您自己决定。例如,为了在查询中插值单个属性 rawQuery
,添加以下内容
const interpolatedQuery: MyQuery = {
...query,
rawQuery: getTemplateSrv().replace(query.rawQuery),
};
格式多值变量
在上面的例子中,变量只有一个值,即 server-1
。然而,如果用户创建了一个多值变量,它可以同时持有多个值。多值变量带来新的挑战:您如何决定如何格式化值集合?
例如,以下哪些不同格式适合您的用例?
{server-1, server-2, server-3} (Graphite)
["server-1", "server-2", "server-3"] (JSON)
("server-1" OR "server-2" OR "server-3") (Lucene)
幸运的是,replace()
方法允许您传递第三个参数,让您可以选择一系列预定义的格式,如 CSV 格式
getTemplateSrv().replace("I'd like $instance, please!", {}, "csv");
// I'd like server-1, server-2, server-3, please!
replace()
方法的第二个参数允许您配置要插值字符串时包含的变量集,或作用域变量。除非这引起您的兴趣,否则请随意传递空对象 {}
。
Grafana 支持一系列格式选项。要浏览可用的格式,请参阅高级变量格式选项。
使用插值函数格式化变量
在查看高级变量格式选项后,您可能会发现您想要支持一个不可用的格式选项。幸运的是,Grafana 允许您通过使用插值函数完全控制 replace()
如何格式化变量。
您可以将插值函数传递给 replace()
作为第三个参数,而不是字符串。以下示例使用自定义格式化函数在最后一个元素之前添加 and
。
const formatter = (value: string | string[]): string => {
if (typeof value == 'string') {
return value;
}
// Add 'and' before the last element.
if (value.length > 1) {
return value.slice(0, -1).join(', ') + ' and ' + value[value.length - 1];
}
return value[0];
};
getTemplateSrv().replace("I'd like $instance, please!", {}, formatter);
// I'd like server-1, server-2, and server-3, please!
函数的参数可以是字符串或字符串数组(如 (string | string[])
),具体取决于变量是否支持多个值,因此在使用之前请确保检查值的类型。
在模板外部使用变量
可能存在您想在模板外部使用变量的情况。例如,如果您想验证所选值的数量或将其添加到下拉菜单中。
此辅助函数使用 replace()
方法将值作为数组返回
function getValuesForVariable(name: string): string[] {
const values: string[] = [];
// Collects the values in an array.
getTemplateSrv().replace(`$${name}`, {}, (value: string | string[]) => {
if (Array.isArray(value)) {
values.push(...value);
} else {
values.push(value);
}
// We don't really care about the string here.
return '';
});
return values;
}
const instances = getValuesForVariable("instance");
for (var instance of instances) {
console.log(instance);
}
// server-1
// server-2
// server-3
您甚至可以更进一步,创建一个整洁地包含所有变量及其值的对象
function getAllVariables(): Record<string, string[]> {
const entries = getTemplateSrv()
.getVariables()
.map((v) => [v.name, getValuesForVariable(v.name)]);
return Object.fromEntries(entries);
}
const vars = getAllVariables();
console.log(vars.instance);
// ["server-1", "server-2", "server-3"]
在这个例子中,使用getTemplateSrv().getVariables()
列出当前仪表板中所有配置的变量。
您还可以根据可预测的分隔符拆分插值字符串。请根据您的理解自由地调整这些代码片段。