基於騰訊雲監控 API 的 Grafana App 插件開發

Tencent Cloud Monitor App

Grafana 是一個開源的時序性統計和監控平臺,支持例如 elasticsearch、graphite、influxdb 等衆多的數據源,並以功能強大的界面編輯器著稱,容許您對指標進行查詢、可視化展現、設置告警等操做,以及自定義配置儀表盤。javascript

Grafana 已經擁有一個強大的貢獻者和插件開發者社區。開發者社區提供了三種類型的插件:css

  • Panel Plugin: 針對圖形展現的面板插件;
  • Datasource Plugin: 針對數據源的插件;
  • App Plugin: 針對完整應用的插件,一般由 Panel Plugin,Datasource Plugin 以及 Dashboards 模板組成;

Tencent Cloud Monitor App 的目錄結構

本文主要介紹的是 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.jsonmodule.tsjava

plugin.json

plugin.json(Required): 用於描述插件的相關信息。在 Grafana 服務啓動時會掃描全部的插件文件夾並掛載每一個插件的 dist 目錄,並查找 plugin.json 文件,根據文件的內容完成插件的自動註冊。webpack

在 Tencent Cloud Monitor App 中存在兩種類型的 Plugin, 其配置文件以下: App Plugin 中配置 plugin.jsongit

{
  "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.jsongithub

{
  "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 配置中必須存在 metricannotations,且其中至少有一個屬性的值爲 trueweb

module.ts

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
};
複製代碼

Tencent Cloud Monitor App 開發實踐

基於騰訊云云監控 API —— Tencent Cloud Monitor App 完整結構圖以下所示:
bash

Tencent Cloud Monitor App 結構圖

在整個應用開發中最爲重要的是 Datasource Plugin 模塊的開發,下面咱們以該模塊爲例進行詳細介紹。

Datasource Plugin 的開發

Datasource Plugin 中有3個必須文件:DatasourceQueryCtrlConfigCtrl

Datasource Plugin 結構圖

Datasource

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 配置該類入口。

Tencent Cloud Monitor App 中 Datasource Plugin 的結構圖

QueryCtrl

當用戶在 Dashboard 頁面對 Panel 進行編輯時,QueryCtrl 類將被實例化並做爲 Angular 控制器,並根據類中的 templateUrl 去加載對應的 View 視圖,以圖形化的界面提供接口數據查詢。該類必須繼承自 grafana/app/plugins/sdk。具體頁面展現以及主要代碼邏輯以下:

Tencent Cloud Monitor App 中 Panel 面板的數據查詢頁面

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 類是查詢面板的入口,其中 NamespaceRegionMetricNamePeriodInsatnce 查詢條件是騰訊雲產品共有的,其業務邏輯實如今 QueryCtrl 類中。對於自定義業務,則可在自定義QueryCtrl 類中實現單獨的 Angular 組件。以上面圖片顯示的面板爲例,其中 ShowDetail 控制獲取特定業務的實例列表數據,所以需抽象到單獨的 Angular 組件中。新增產品則須要在 tc_monitor 目錄實現各自的 query.ts 類,並在 index.tx 文件中經過 import 註冊該組件,則對應在 query.editor.html 中引入產品實現的組件便可。

Tencent Cloud Monitor App 中 Datasource Plugin 的 QueryCtrl 結構圖

ConfigCtrl 類

ConfigCtrl 類是添加數據源的面板進行控制。 當用戶對該 App Plugin 的數據源進行配置時,該類會被實例化爲 Angular 的控制器,並根據類中的 templateUrl 去加載對應的 View 視圖,用於呈現數據源自定義配置的面板。具體頁面展現示例以下:

Tencent Cloud Monitor App 的數據源配置頁面

/* 文件路徑爲 /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…)

項目代碼開發成員:

相關文章
相關標籤/搜索