Grafana 是一個開源的時序性統計和監控平臺,支持例如 elasticsearch、graphite、influxdb 等衆多的數據源,並以功能強大的界面編輯器著稱,容許您對指標進行查詢、可視化展現、設置告警等操做,以及自定義配置儀表盤。javascript
Grafana 已經擁有一個強大的貢獻者和插件開發者社區。開發者社區提供了三種類型的插件:css
本文主要介紹的是 App Plugin 的開發過程以及相關的代碼組織。基於騰訊云云監控 API 的 Tencent Cloud Monitor App 插件(TencentCloud/tencentcloud-monitor-grafana-app),主要由兩部分組成: Datasource Plugin 和 Dashboards 模板組成,代碼的目錄結構以下:html
.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dist // 文件夾,文件夾 src 打包後的代碼
├── package.json
├── src
│ ├── components
│ │ ├── config.html
│ │ └── config.ts
│ ├── dashboards // Dashboards 典型模板存放
│ │ ├── example_cdb_dashboard.json
│ │ └── example_cvm_dashboard.json
│ ├── datasource // Datasource Plguin 代碼
│ │ ├── __mocks__
│ │ │ └── core_module.ts
│ │ ├── common
│ │ │ ├── constants.ts
│ │ │ └── sign.ts
│ │ ├── components // 自定義的 Angular 組件
│ │ │ ├── custom_select_dropdown.ts
│ │ │ └── multi_condition.ts
│ │ ├── css
│ │ │ └── query_editor.css
│ │ ├── config.ctrl.ts // ConfigCtrl 模塊
│ │ ├── datasource.ts // Datasource 模塊
│ │ ├── query.ctrl.ts // QueryCtrl 模塊
│ │ ├── img
│ │ │ └── tencent-cloud.svg
│ │ ├── partials // Datasource Plugin 中的 html 頁面
│ │ │ ├── config.html // config.ctrl.ts 對應的 html
│ │ │ ├── query.editor.html // query.ctrl.ts 對應的 html
│ │ ├── module.ts // Datasource Plguin 的 module.ts
│ │ ├── plugin.json // Datasource Plguin 的 module.ts
│ │ ├── specs // 測試用例文件夾
│ │ │ ├── tc_monitor_cdb_datasource.test.ts
│ │ │ └── tc_monitor_cvm_datasource.test.ts
│ │ └── tc_monitor // 雲監控相關的產品
│ │ ├── cdb
│ │ │ ├── datasource.ts
│ │ │ ├── query.ts
│ │ │ └── query_def.ts
│ │ ├── cvm
│ │ │ ├── datasource.ts
│ │ │ ├── query.ts
│ │ │ └── query_def.ts
│ │ └── index.ts
│ ├── image // 文件夾,存放README.md 中圖片
│ ├── img
│ │ └── tencent-cloud.svg
│ ├── module.ts // App Plguin 的 module.ts
│ └── plugin.json // App Plugin 的 plugion.json
├── jest.config.js // jest 框架的配置信息
├── tsconfig.jest.json
├── tsconfig.json
├── tslint.json
├── webpack.config.analyze.js
├── webpack.config.js
└── webpack.config.prod.js
複製代碼
在每一個 Plugin 開發中存在兩個重要的配置文件: plugin.json 和 module.ts。java
plugin.json(Required)
: 用於描述插件的相關信息。在 Grafana 服務啓動時會掃描全部的插件文件夾並掛載每一個插件的 dist 目錄,並查找 plugin.json
文件,根據文件的內容完成插件的自動註冊。webpack
在 Tencent Cloud Monitor App 中存在兩種類型的 Plugin, 其配置文件以下: App Plugin 中配置 plugin.json
:git
{
"type": "app", // 插件的類型: panel | app | datasource
"name": "Tencent Cloud Monitor", // 插件名稱
"id": "tencentcloud-monitor-app", // 插件ID, 必須惟一
"info": {
"description": "Tencent Cloud Monitor App for Grafana",
"author": {
"name": "Tencent Cloud"
},
"keywords": [
"tencentcloud",
"tencentcloudmonitor",
"grafana",
"plugins"
],
"logos": {
"small": "img/tencent-cloud.svg",
"large": "img/tencent-cloud.svg"
},
"version": "1.0.0",
"updated": "2019-04-10"
},
"includes": [ // App Plugin 中包含的 Datasource Plugin 和 Dashboards 模板信息
{
"type": "dashboard",
"name": "【實例】CDB 單機監控",
"path": "dashboards/example_cdb_dashboard.json"
},
{
"type": "dashboard",
"name": "【實例】CVM 單機監控",
"path": "dashboards/example_cvm_dashboard.json"
},
{
"type": "datasource",
"name": "Tencent Cloud Monitor Datasource"
}
],
"dependencies": {
"grafanaVersion": "6.0",
"plugins": []
}
}
複製代碼
Datasource Plugin 中配置 plugin.json
:github
{
"type": "datasource",
"name": "Tencent Cloud Monitor Datasource",
"id": "tencentcloud-monitor-datasource",
"metrics": true, // Datasource plugin 特有的屬性,是否在 panel 中支持 metrics
"annotations": true, // Datasource plugin 特有的屬性,是否在 dashboard 中支持 annotations 查詢
"queryOptions": {
"maxDataPoints": true
},
"routes": [],
"info": {
"author": {
"name": "Tencent Cloud"
},
"logos": {
"small": "img/tencent-cloud.svg",
"large": "img/tencent-cloud.svg"
}
}
}
複製代碼
特別注意 Datasource Plugin 的 plugin.json
配置中必須存在 metric 和 annotations,且其中至少有一個屬性的值爲 true
。web
module.ts(Required)
: Plugin 入口文件,決定了 Plugin 的具體實現的。根據插件的類型不一樣其內容也有所差別。json
/* App Plugin 的 module.ts 須要導出1個模塊 */
export {
ConfigCtrl,
};
/* Datasource Plugin 的 module.ts 一般須要導出5個模塊 */
export {
Datasource, // Required
ConfigCtrl, // Required
QueryCtrl, // Required
AnnotationsQueryCtrl,
QueryOptionsCtrl
};
複製代碼
基於騰訊云云監控 API —— Tencent Cloud Monitor App 完整結構圖以下所示:
bash
在整個應用開發中最爲重要的是 Datasource Plugin 模塊的開發,下面咱們以該模塊爲例進行詳細介紹。
Datasource Plugin 中有3個必須文件:Datasource
、 QueryCtrl
和 ConfigCtrl
;
Datasource 類做爲數據入口,主要負責與數據源進行通訊。 針對 Tencent Cloud Monitor App 中不一樣的產品,都必須有一個對應 Datasource 實現類。所以咱們定義了一個 Datasource 類的接口協議,每一個產品的 Datasource 類都必須遵循這個接口協議:
interface DatasourceInterface {
instanceSettings: any;
backendSrv: any;
templateSrv: any;
query(options: any);
testDatasource();
metricFindQuery(query: any);
getRegions(service: string);
getMetrics(service: string, region: string);
getInstances(service: string, region: string, params: any);
getZones?: (service: string, region: string) => any;
}
複製代碼
備註:
// Datasource 類若是要實現如下功能函數,則必須遵循 Grafana 命名協議約定,因此 Datasource 類的接口協議也是按照該要求進行設計。
query(options) // Required, used by panels to get data
testDatasource() // Required, used by datasource configuration page to make sure the connection is working
annotationQuery(options) // used by dashboards to get annotations
metricFindQuery(options) // used by query editor to get metric suggestions.
複製代碼
Datasource 類的主要代碼:
/* Datasource Plugin 中的 datasource 類 */
import { Datasources, SERVICES } from './tc_monitor'; // Datasources 是每一個雲產品對應的 Datasource 實現類組成的對象
export class TCMonitorDatasource implements DatasourceInterface {
instanceSettings: any;
backendSrv: any;
templateSrv: any;
/** @ngInject */
constructor(instanceSettings, backendSrv, templateSrv) {
this.instanceSettings = instanceSettings;
this.backendSrv = backendSrv;
this.templateSrv = templateSrv;
_.forEach(Datasources, (_class, key) => { // 自動實例化每一個雲產品的 Datasource 類
this[key] = new _class(this.instanceSettings, this.backendSrv, this.templateSrv);
});
}
testDatasource() {...} // 根據選中的雲產品去調用每一個雲產品 Datasource 類中對應的 testDatasource()
query(options) {...} // 根據選中的雲產品去調用每一個雲產品 Datasource 類中對應的 query()
metricFindQuery(query) {...} // 根據選中的雲產品去調用每一個雲產品 Datasource 類中對應的 getRegions()
getRegions() {...} // 根據選中的雲產品去調用每一個雲產品 Datasource 類中對應的 getMetrics()
getMetrics() {...} // 根據選中的雲產品去調用每一個雲產品 Datasource 類中對應的 getZones()
getInstances() {...}
getZones() {...}
}
/*CVM 產品中的 datasource 模塊*/
export default class CVMDatasource implements DatasourceInterface {
constructor() {...}
testDatasource() {...}
query(options) {...}
metricFindQuery(query) {...}
getRegions() {...}
getMetrics() {...}
getInstances() {...}
getZones() {...}
}
複製代碼
在新增產品時只需在 tc_monitor
目錄中增長對應子目錄實現各自的 datasource.ts
類(繼承DatasourceInterface
協議),再在tc_monitor
目錄的 index.tx 文件中經過 Datasources 配置該類入口。
當用戶在 Dashboard 頁面對 Panel 進行編輯時,QueryCtrl 類將被實例化並做爲 Angular 控制器,並根據類中的 templateUrl
去加載對應的 View 視圖,以圖形化的界面提供接口數據查詢。該類必須繼承自 grafana/app/plugins/sdk。具體頁面展現以及主要代碼邏輯以下:
import { QueryCtrl } from 'grafana/app/plugins/sdk';
export class TCMonitorDatasourceQueryCtrl extends QueryCtrl {
static templateUrl = 'datasource/partials/query.editor.html';
datasource: any; // 對應 datasource.ts 實例的對象
panelCtrl: any; // 對應 Panel 的實例對象
target: { // 具體的查詢條件信息保存
refId: string;
namespace: string;
service: string;
showInstanceDetails: boolean;
};
defaults = { // 初始化值
namespace: '',
service: '',
showInstanceDetails: false,
...InitServiceState,
};
lastQuery: string;
lastQueryError?: string;
/** @ngInject */
constructor($scope, $injector, private templateSrv) {
super($scope, $injector);
_.defaultsDeep(this.target, this.defaults);
this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
}
// Panel 實例的數據接收處理函數
onDataReceived(dataList) {
this.lastQueryError = undefined;
this.lastQuery = '';
const anySeriesFromQuery: any = _.find(dataList, { refId: this.target.refId });
if (anySeriesFromQuery) {
this.lastQuery = anySeriesFromQuery.query;
}
}
// Panel 數據查詢失敗的調用函數
onDataError(err) {
this.handleQueryCtrlError(err);
}
handleQueryCtrlError(err) {...}
// 省略其它詳細代碼
}
複製代碼
對應視圖 View 中的部分代碼以下,<query-editor-row query-ctrl="ctrl"></query-editor-row>
標籤的內容會加入到Add Query模板中:
<query-editor-row query-ctrl="ctrl" class="generic-datasource-query-row" has-text-edit-mode="true">
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label query-keyword width-9">Namespace</label>
<div class="gf-form-select-wrapper gf-form-select-wrapper--caret-indent">
<select class="gf-form-input min-width-12" ng-model="ctrl.target.namespace" ng-options="f as f for f in ctrl.namespaces" ng-change="ctrl.onNamespaceChange()"></select>
</div>
</div>
</div>
<!-- 省略更多詳情 -->
<!-- 新增不一樣的雲產品,須要在該處增長新產品獨有的配置頁面 -->
<!-- CVM -->
<cvm-query ng-if="ctrl.target.service==='cvm'" target="ctrl.target.cvm" show-detail="ctrl.checkShowDetail('instance')" datasource="ctrl.datasource" on-change="ctrl.onInstanceQueryChange()" region="ctrl.replace(ctrl.target.cvm.region)" ></cvm-query>
<!-- Global error message -->
<div class="gf-form" ng-show="ctrl.lastQueryError">
<pre class="gf-form-pre alert alert-error">{{ctrl.lastQueryError}}</pre>
</div>
</query-editor-row>
複製代碼
QueryCtrl 類是查詢面板的入口,其中 Namespace
、Region
、MetricName
、 Period
、 Insatnce
查詢條件是騰訊雲產品共有的,其業務邏輯實如今 QueryCtrl 類中。對於自定義業務,則可在自定義QueryCtrl 類中實現單獨的 Angular 組件。以上面圖片顯示的面板爲例,其中 ShowDetail 控制獲取特定業務的實例列表數據,所以需抽象到單獨的 Angular 組件中。新增產品則須要在 tc_monitor
目錄實現各自的 query.ts
類,並在 index.tx 文件中經過 import
註冊該組件,則對應在 query.editor.html
中引入產品實現的組件便可。
ConfigCtrl 類是添加數據源的面板進行控制。 當用戶對該 App Plugin 的數據源進行配置時,該類會被實例化爲 Angular 的控制器,並根據類中的 templateUrl
去加載對應的 View 視圖,用於呈現數據源自定義配置的面板。具體頁面展現示例以下:
/* 文件路徑爲 /src/datasource/config.ctrl.ts */
import * as _ from 'lodash';
import { SERVICES } from './tc_monitor';
export class TCMonitorDatasourceConfigCtrl {
static templateUrl = 'datasource/partials/config.html'; // 指定該Controller 對應 View 文件,且實際路徑爲 /src/datasource/partials/config.html
current: any;
/** @ngInject */
constructor($scope) {
this.current.jsonData.services = SERVICES;
_.forEach(this.current.jsonData.services, (service) => {
this.current.jsonData[service.service] = true;
});
}
}
複製代碼
Tencent Cloud Monitor App 已經在 github.com 上開源了,歡迎你們多提 issues,順便給咱們 Star 鼓勵一下。
項目地址:TencentCloud/tencentcloud-monitor-grafana-app (github.com/TencentClou…)
項目代碼開發成員: