Grafana的Datasource外掛開發實踐一中介紹了開發datasource需要知道的基本內容。這篇文章中將介紹在專案中具體的開發實踐。
Datasource模組
與Grafana的其餘部分進行互動,外掛檔案需要匯出以下5個模組:
Datasource // Required
QueryCtrl // Required
ConfigCtrl // Required
QueryOptionsCtrl //
AnnotationsQueryCtrl //
複製程式碼
constructor函式
datasource外掛與資料來源通訊,並將資料轉換為時間序列。
資料來源有以下功能:
query(options) // 用於panel查詢資料
testDatasource() // 用於自定義資料來源的頁面,測試當前配置的資料來源是可用的
annotationQuery(options) // 用於dashboard獲取註釋資訊
metricFindQuery(options) // used by query editor to get metric suggestions.
複製程式碼
constructor函式傳入的引數有:
constructor(instanceSettings, $q, backendSrv, templateSrv) {}
// instanceSettings物件為:
{
id: 5,
jsonData: {
keepCookies: [],
tlsAuth: false,
tlsAuthWithCACert: false,
tlsSkipVerify: false,
},
meta: {
alerting: false,
annotations: true,
baseUrl: "public/plugins/grafana-server-datasource",
dependencies: {
grafanaVersion: "3.x.x",
plugins: [],
},
id: "grafana-server-datasource",
includes: null,
info: {
author: {
name:"liuchunhui",
url:"https://grafana.com",
},
description: "代理服務端作為資料來源",
links: [
{name: "Github", url: ""},
{name: "MIT License", url: ""}
],
logos: {
large:"public/plugins/grafana-server-datasource/img/server-logo.png",
small:"public/plugins/grafana-server-datasource/img/server-logo.png"
},
screenshots:null
updated:"2018-04-23"
version:"1.0.0"
},
metrics: true,
module: "plugins/grafana-server-datasource/module",
name: "代理服務端",
routes: null,
type: "datasource",
}
name:"代理服務端資料來源",
type:"grafana-server-datasource",
url:"/api/datasources/proxy/5",
}
// $q 是個函式
// backendSrv物件為:
{
$http: ƒ p(e),
$q: ƒ M(t),
$timeout: ƒ o(o,s,u),
HTTP_REQUEST_CANCELLED: -1,
alertSrv: {
$rootScope: object,
$timeout: ƒ o(o,s,u)
list: []
}
contextSrv: {
isEditor: true,
isGrafanaAdmin: true,
isSignedIn: true,
sidemenu: true,
sidemenuSmallBreakpoint: false,
user: { // 當前登入的使用者資訊
email:"admin@localhost",
gravatarUrl:"/avatar/46d229b033af06a191ff2267bca9ae56",
helpFlags1:0,
id:1,
isGrafanaAdmin:true,
isSignedIn:true,
lightTheme:true,
locale:"zh-CN",
login:"admin",
name:"admin",
orgCount:1,
orgId:1,
orgName:"Main Org.",
orgRole:"Admin",
timezone:"browser",
},
version:"5.0.1",
},
inFlightRequests:{},
noBackendCache:true,
}
// templateSrv物件為:
{
builtIns: {
__interval:{text: "1s", value: "1s"},
__interval_ms:{text: "100", value: "100"}
},
grafanaVariables: {},
index:{},
regex:/$(w+)|[[([sS]+?)(?::(w+))?]]|${(w+)(?::(w+))?}/g
}
複製程式碼
query函式
真正去查詢資料時要呼叫的函式。官方提供的資料來源有兩種不同的結果,time series
和table
,目前grafana官方所有資料來源和皮膚都支援time series
格式,table
格式僅由InfluxDB資料來源和表格皮膚支援。
我們開發外掛時可以自定義型別值,但是要做到開發的datasource外掛也適配官方自帶的panel外掛,那麼定義datasource返回的資料格式和grafana的一致。
datasource.query的time series
型別響應格式:
[{
"target":"upper_75",
"datapoints":[
[622, 1450754160000],
[365, 1450754220000]
]
}, {
"target":"upper_90",
"datapoints":[
[861, 1450754160000],
[767, 1450754220000]
]
}]
複製程式碼
datasource.query的table
型別響應格式:
[{
"columns": [{
"text": "Time",
"type": "time",
"sort": true,
"desc": true,
}, {
"text": "mean",
}, {
"text": "sum",
}],
"rows": [[
1457425380000,
null,
null
], [
1457425370000,
1002.76215352,
1002.76215352
]],
"type": "table"
}]
複製程式碼
傳遞給datasource.query
函式的請求物件:
{
"range": {
"from": moment, // 全域性時間篩選起始日期
"raw": {from: "now-7d", to: "now"},
"to": moment, // 全域性時間篩選結束日期
},
"rangeRaw": {
"from": "now-7d",
"to": "now",
},
"interval": "15m",
"intervalMs": 900000,
"targets": [{ // 定義的查詢條件們
"refId": "A",
"target": "upper_75"
}, {
"refId": "B",
"target": "upper_90"
}],
"format": "json",
"maxDataPoints": 2495, //decided by the panel
"cacheTimeout": undefined,
"panelId": 2,
"timezone": "browser"
}
複製程式碼
query函式示例:
query(options) { // 返回的結果資料,panel外掛會通過監聽`data-received`獲取到
const params = { // 封裝http請求引數
from: options.range.from.format(`x`),
to: options.range.to.format(`x`),
targets: options.queries,
};
return this.doRequest({ // 發起http請求並返回結果
url: this.url + `/card-data`, // 要制定公共介面規範
method: `POST`,
data: params
});
}
doRequest(options) {
options.withCredentials = this.withCredentials;
options.headers = this.headers;
return this.backendSrv.datasourceRequest(options); // datasourceRequest()是grafana提供的請求datasource函式
}
複製程式碼
testDatasource函式
當使用者在新增新資料來源時點選Save&Test
按鈕,詳細資訊首先儲存到資料庫,然後testDatasource
呼叫資料來源外掛中定義的函式。
此函式向資料來源發出查詢,驗證資料來源是否配置的正確可用,確保當使用者在新儀表板中編寫查詢時,資料來源已正確配置。
函式示例:
/**
* 當儲存並測試資料來源時會呼叫該函式
* 測試資料來源是否正常工
* return { status: "", message: "", title: "" }
*/
testDatasource() {
return this.doRequest({
url: this.url + `/`,
method: `GET`,
}).then(response => {
if (response.status === 200) {
return { status: "success", message: "Data source is working", title: "Success" };
}
});
}
複製程式碼
annotationQuery函式
註釋查詢,傳遞給datasource.annotationQuery函式的請求物件:
{
"range": {
"from": "2016-03-04T04:07:55.144Z",
"to": "2016-03-04T07:07:55.144Z" },
"rangeRaw": {
"from": "now-3h",
"to": "now"
},
"annotation": {
"datasource": "generic datasource",
"enable": true,
"name": "annotation name"
}
}
複製程式碼
datasource.annotationQuery的預期結果:
[{
"annotation": {
"name": "annotation name", //should match the annotation name in grafana
"enabled": true,
"datasource": "generic datasource",
},
"title": "Cluster outage",
"time": 1457075272576,
"text": "Joe causes brain split",
"tags": "joe, cluster, failure"
}]
複製程式碼
可以使用grafana平臺的資料庫存取`註釋`
metricFindQuery 函式
ConfigCtrl模組
當使用者編輯或建立此型別的新資料來源時,該類將被例項化並視為Angular控制器。
該類需要一個靜態模板或templateUrl變數,該模板或變數將被渲染為此控制器的檢視。
ConfigCtrl類中的this物件內容為:
{
current: {
name: "代理服務端資料來源", // 資料來源名稱
isDefault: true, // 是否是預設
type: "grafana-server-datasource", // 資料來源外掛的id值
url: "http://localhost:3001", // HTTP:資料來源對應的url
access: "proxy", // HTTP:連線資料來源型別,有`direct`和`proxy`兩種型別可選
basicAuth: true, // Auth:Basic Auth選項
basicAuthUser: "basic auth user", // Basic Auth Details:User選項,當basicAuth為true時有效
basicAuthPassword:"basic auth password", // Basic Auth Details:Password選項,當basicAuth為true時有效
withCredentials: true, // Auth:With Credentials選項
jsonData: {
tlsAuth: true, // Auth:TLS Client Auth選項
tlsAuthWithCACert: true, // Auth: With CA Cert選項
tlsSkipVerify: true, // Auth: Skip TLS Verification (Insecure)選項值
keepCookies: ["Advanced Cookoe"], // Advanced HTTP Settings: cookie的白名單
},
secureJsonData: {
tlsCACert: "TLS Auth CA Cert", // TLS Auth Details:CA Cert選項,當jsonData下的tlsAuthWithCACert值為true時有效
tlsClientCert: "TLS Auth Client Cert", // TLS Auth Details:Client Cert選項,當jsonData下的tlsAuth值為true時有效
tlsClientKey: "TLS Auth Client Key", // TLS Auth Details:Client Key選項,當jsonData下的tlsAuth值為true時有效
},
secureJsonFields: {},
},
meta: {
baseUrl: "public/plugins/grafana-server-datasource",
defaultNavUrl: "",
dependencies: {
grafanaVersion: "3.x.x",
plugins: [],
},
enabled: false,
hasUpdate: false,
id: "grafana-server-datasource",
includes: null,
info: { // plugin.json中配置的資訊
author: {
name: "liuchunhui",
url: "https://grafana.com"
},
description: "代理服務端作為資料來源",
links: [
{name: "Github", url: ""},
{name: "MIT License", url: ""}
],
logos: {
large:"public/plugins/grafana-server-datasource/img/server-logo.png",
small:"public/plugins/grafana-server-datasource/img/server-logo.png"
},
screenshots:null,
updated:"2018-04-23",
version:"1.0.0"
},
jsonData: null,
latestVersion: "",
module: "plugins/grafana-server-datasource/module",
name: "代理服務端",
pinned: false
state: "",
type: "datasource",
}
複製程式碼
模板頁面中使用grafana封裝的angular元件,傳入this的current
物件,實現HTTP、Auth兩個模組的定義:
<datasource-http-settings current="ctrl.current"></datasource-http-settings>
複製程式碼
QueryCtrl模組
一個JavaScript類,當使用者在皮膚中編輯指標時,它將被例項化並作為Angular控制器處理。
該類必須從app/plugins/sdk.QueryCtrl
類繼承。
該類需要一個靜態模板或templateUrl變數,該模板或變數將被渲染為此控制器的檢視。
當使用者在panel皮膚下,切回到Metrics
模組時,會初始化該類。所以我們可以在建構函式中做一些我們自己的事情。比如獲取指標維度列表,作為使用者篩選的展示條件。
import { QueryCtrl } from `app/plugins/sdk`;
export default class GenericQueryCtrl extends QueryCtrl {
constructor($scope, $injector) {
super($scope, $injector);
// 獲取引數列表請求
this.requestParams().then(response => {
const targets = response.data.target;
this.options = response.data.options;
this.text = response.data.text;
this.keys = Object.keys(targets);
for (let key in targets) {
this.target[key] = this.target[key] || targets[key];
}
});
}
requestParams() { // 請求獲取引數列表
const params = {
header: {
`Content-Type`: `application/json`
},
method: `GET`,
retry: 0,
url: this.datasource.url + `/param-list`
};
return this.datasource.backendSrv.datasourceRequest(params); // 使用grafana提供的http請求函式
}
onChangeInternal() { // 重新整理皮膚
this.panelCtrl.refresh(); // grafana自帶方法使皮膚更新資料
}
toggleEditorMode() { // 是否開啟編輯模式
this.target.rawQuery = !this.target.rawQuery;
}
}
GenericQueryCtrl.templateUrl = `./page/query.html`;
複製程式碼
QueryCtrl控制器的query.html模板:
<query-editor-row query-ctrl="ctrl" has-text-edit-mode="true">
<div class="gf-form"
ng-if="!ctrl.target.rawQuery"
ng-repeat="key in ctrl.keys">
<span class="gf-form-label width-7">
{{ctrl.text[key]}}
</span>
<select class="gf-form-input width-25"
ng-model="ctrl.target[key]"
ng-change="ctrl.onChangeInternal()">
<option ng-repeat="option in ctrl.options[key]"
value="{{option.name}}">
{{option.desc}}
</option>
</select>
</div>
<div ng-if="ctrl.target.rawQuery">
<textarea class="gf-form-input" rows="5" spellcheck="false" ng-blur="ctrl.onChangeInternal()" />
</div>
</query-editor-row>
複製程式碼
<query-editor-row query-ctrl="ctrl">
標籤的內容會加入到Add Query
模板中,標籤中的has-text-edit-mode=”true”屬性,能開啟Toggle Edit Mode
功能。
QueryCtrl控制器中的target.rawQuery引數,標記著兩種編輯模式的切換,但是這兩種模式需要寫程式碼定義。
AnnotationsQueryCtrl模組
當使用者在datasource的模板選單中選擇這種型別的資料來源時,將被例項化並作為Angular控制器處理的JavaScript類。
此類需要一個靜態模板或templateUrl變數,該模板或變數將被渲染為此控制器的檢視。
繫結到此控制器的欄位隨後會傳送到資料庫物件annotationQuery函式。
在開發外掛時能自定義dashboard的Built in query
的條件。
AnnotationQueryCtrl程式碼:
export default class GenericAnnotationsQueryCtrl {}
GenericAnnotationsQueryCtrl.templateUrl = `./page/annotationsQuery.html`;
複製程式碼
annotationsQuery.html程式碼:
<h5 class="section-heading">註解查詢條件設定</h5>
<div class="gf-form-group">
<div class="gf-form">
<input type="text" class="gf-form-input" ng-model=`ctrl.annotation.query` placeholder="" />
</div>
</div>
複製程式碼
QueryOptionsCtrl模組
一個JavaScript類,當使用者在皮膚中編輯指標時,它將被例項化並作為Angular控制器處理。
此控制器負責處理資料來源的皮膚範圍設定,如間隔,速率和聚合(如果需要)。
此類需要一個靜態模板或templateUrl變數,該模板或變數將被渲染為此控制器的檢視。
QueryOptionsCtrl程式碼:
export default class GenericQueryOptionsCtrl {}
GenericQueryOptionsCtrl.templateUrl = `./page/queryOptions.html`;
複製程式碼
queryOptions.html程式碼:
<section class="grafana-metric-options" >
<div class="gf-form"></div>
</section>
複製程式碼