Tencent Cloud Monitor App

Grafana is an open source temporal statistics and monitoring platform, which supports many data sources such as ElasticSearch, Graphite, and InfluxDB. It is also famous for its powerful interface editor, which allows you to query, visually display, set alarms, etc. And custom configuration dashboard.

Grafana already has a strong community of contributors and plug-in developers. The developer community offers three types of plug-ins:

  • Panel Plugin: A graphical display Panel Plugin;
  • Datasource Plugin: a plug-in for the Datasource;
  • App Plugin: A plug-in for a complete application, usually consisting of Panel Plugin, Datasource Plugin and Dashboards template.

Tencent Cloud Monitor App directory structure

This article mainly introduces the development process of App Plugin and related code organization. Based on Tencent Tencent greetings to Monitor the API Cloud Monitor App plug-in (TencentCloud/TencentCloud – Monitor – grafana – App), is mainly composed of two parts: Datasource Plugin and Dashboards template, the code directory structure is as follows:

.Bass Exercises ── Bass Exercises ── Bass Exercises.Bass Exercises ── Bass Exercises, ├── SRC │ ├── ├─ config.html │ ├── ├.ts │ ├─ dashboards // │ │ ├── example_cvm_dashboards. Json │ │ ├─ example_cVM_dashboards Plguin code │ │ ├ ─ ─ __mocks__ │ │ │ └ ─ ─ core_module. Ts │ │ ├ ─ ─ common │ │ │ ├ ─ ─ the ts │ │ │ └ ─ ─ sign. Ts │ │ ├ ─ ─ Components / / custom presents component │ │ │ ├ ─ ─ custom_select_dropdown. Ts │ │ │ └ ─ ─ multi_condition. Ts │ │ ├ ─ ─ CSS │ │ │ └ ─ ─ Query_editor. CSS │ │ ├─ ├─ Config.Ctrl. ts // │ │ ├─ datasource QueryCtrl module │ │ ├ ─ ─ img │ │ │ └ ─ ─ tencent - cloud. SVG │ │ ├ ─ ─ partials / / Datasource HTML page in the Plugin │ │ │ ├ ─ ─ Config.html // config.ctrl.ts │ │ ├─ Query.editor.html // Query.ctrl. ts │ │ ├─ Module The Datasource Plguin module. The ts │ │ ├ ─ ─ the plugin. The json / / Datasource Plguin module. Ts │ │ ├ ─ ─ specs / / test case folder │ │ │ ├ ─ ─ │ ├─ ├─ tc_monitor_movement.test.ts │ ├─ tc_monitor_movement.test.ts │ ├─ CDB │ │ │ ├ ─ ─ a datasource. Ts │ │ │ ├ ─ ─ query. Ts │ │ │ └ ─ ─ query_def. Ts │ │ ├ ─ ─ CVM │ │ │ ├ ─ ─ a datasource. Ts │ │ │ ├ ─ ─ Query. Ts │ │ │ └ ─ ─ query_def. Ts │ │ └ ─ ─ index. The ts │ ├ ─ ─ image / / folder, │ ├─ ├─ ├.txt TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT Json ├─ Tsconfig.json ├─ Tsconfig.json ├─ Tsconfig.json ├─ Webpack. Config. Analyze the js ├ ─ ─ webpack. Config. Js └ ─ ─ webpack. Config. Prod. JsCopy the code

There are two important configuration files in every Plugin development: plugin.json and module.ts.

plugin.json

Plugin. json(Required): Describes information about the plug-in. On the startup of Grafana service, all plug-in folders will be scanned, dist directory of each plug-in will be mounted, and plugin.json file will be searched, and automatic registration of plug-ins will be completed according to the content of the file.

There are two types of Plugin in Tencent Cloud Monitor App, and their configuration files are as follows: plugin.json is configured in App Plugin:

{" type ":" app ", / / plug-in type: a panel | | app datasource "name" : "Tencent Cloud Monitor", / / the plugin name "id" : "Tencentcloud-monitor -app", // plugin ID must be unique "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 includes Datasource Plugin and Dashboards template information {"type": "dashboard", "name": "[Example] CDB single-node Monitoring ", "path": "dashboards/example_cdb_dashboard.json"}, {"type": "dashboard", "name": "[Example] CVM Single-node monitoring ", "path": "dashboards/ example_CVM_dashboard. json"}, {"type": "datasource", "name": "> < span style =" max-width: 100%; box-sizing: border-box;Copy the code

Datasource plugin.json:

{ "type": "datasource", "name": "Tencent Cloud Monitor Datasource", "id": "tencentcloud-monitor-datasource", "metrics": Annotations true, // Datasource plugin specifies whether the panel supports metrics "Annotations ": Annotations ({"maxDataPoints": true}, "routes": [], "info": { "author": { "name": "Tencent Cloud" }, "logos": { "small": "img/tencent-cloud.svg", "large": "img/tencent-cloud.svg" } } }Copy the code

Note in particular that the plugin.json configuration of the Datasource Plugin must have metrics and Annotations, and at least one of them must have a value of true.

module.ts

Module.ts (Required) : Plugin entry file that determines the implementation of the Plugin. The content varies depending on the type of plug-in.

/* App Plugin module.ts needs to export 1 module */
export {
  ConfigCtrl,
};

/* Datasource Plugin module.ts normally requires 5 modules to be exported */
export {
  Datasource,                 // Required
  ConfigCtrl,                 // Required
  QueryCtrl,                  // Required
  AnnotationsQueryCtrl,
  QueryOptionsCtrl
};
Copy the code

Tencent Cloud Monitor App development practice

The complete structure of Tencent Cloud Monitor App based on Tencent Cloud monitoring API is as follows:

In the whole application development, the most important is the development of Datasource Plugin module. Here we take this module as an example to introduce in detail.

Datasource Plugin development

The Datasource Plugin has three required files: Datasource, QueryCtrl, and ConfigCtrl;

Datasource

The Datasource class acts as a data portal and communicates with the Datasource. For different products in Tencent Cloud Monitor App, there must be a corresponding Datasource implementation class. Therefore, we define an interface protocol for the Datasource class that every product’s Datasource class must follow:

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;
}
Copy the code

Remark:

// The Datasource class must comply with the Grafana naming protocol to implement the following functions. The Datasource interface protocol is also designed according to this requirement.
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.
Copy the code

The Datasource class contains the following code:

/* Datasource Plugin */
import { Datasources, SERVICES } from './tc_monitor';   // Datasources is an object consisting of the Datasource implementation classes for each cloud product
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) => {                   // Automatically instantiate the Datasource class for each cloud product
      this[key] = new _class(this.instanceSettings, this.backendSrv, this.templateSrv); }); } testDatasource() {... }// Call testDatasource() of each cloud product Datasource class based on the selected cloud product.query(options) {... }// Call the query() in the Datasource class of each cloud product based on the selected cloud product.metricFindQuery(query) {... }// Call getRegions() in the Datasource class of each cloud product based on the selected cloud product.getRegions() {... }// Call getMetrics() in the Datasource class of each cloud product based on the selected cloud productgetMetrics() {... }// Call each cloud product Datasource class getZones() based on the selected cloud product.getInstances() {... } getZones() {... }}/* Datasource module in the CVM product */ 
export default class CVMDatasource implements DatasourceInterface {
  constructor() {... } testDatasource() {... } query(options) {... } metricFindQuery(query) {... } getRegions() {... } getMetrics() {... } getInstances() {... } getZones() {... }}Copy the code

When adding a new product, you only need to add the corresponding subdirectory in the TC_monitor directory to realize the respective datasource.ts class (inheriting the DatasourceInterface protocol). The Datasources entry is then configured in the index.tx file in the TC_monitor directory.

QueryCtrl

When a user edits a Panel on a Dashboard page, the QueryCtrl class is instantiated as an Angular controller and loads a View based on the class’s templateUrl to provide a graphical interface for querying interface data. This class must inherit from grafana/app/plugins/ SDK. The specific page display and main code logic are as follows:

import { QueryCtrl } from 'grafana/app/plugins/sdk';

export class TCMonitorDatasourceQueryCtrl extends QueryCtrl {
  static templateUrl = 'datasource/partials/query.editor.html';
  datasource: any;                  // The object corresponding to the datasource. Ts instance
  panelCtrl: any;                   // Corresponds to the instance object of the Panel
  target: {                         // Save specific query conditions
    refId: string;
    namespace: string;
    service: string;
    showInstanceDetails: boolean;
  };
  defaults = {                      // Initialize the value
    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 instance data receive processing function
  onDataReceived(dataList) {
    this.lastQueryError = undefined;
    this.lastQuery = ' ';
    const anySeriesFromQuery: any = _.find(dataList, { refId: this.target.refId });
    if (anySeriesFromQuery) {
      this.lastQuery = anySeriesFromQuery.query; }}// Panel data query failed to call function
  onDataError(err) {
    this.handleQueryCtrlError(err); } handleQueryCtrlError(err) {... }// Omit other detailed code
}
Copy the code

the contents of the tag are added to the Add Query template:

<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>
  <! -- Omit more details -->

  <! -- To add different cloud products, you need to add the configuration page unique to the new product -->
  <! -- 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>
Copy the code

QueryCtrl class is the entrance of the query panel, in which the query conditions of Namespace, Region, MetricName, Period and Insatnce are common to Tencent cloud products, and its business logic is implemented in the QueryCtrl class. For custom businesses, a separate Angular component can be implemented in a custom QueryCtrl class. Take the panel shown in the image above, where ShowDetail controls getting the list of instances for a particular business and therefore needs to be abstracted into a separate Angular component. New products need to implement their query.ts classes in the tc_monitor directory and register this component with import in the index.tx file, corresponding to the components introduced in query.editor.html.

ConfigCtrl class

The ConfigCtrl class is the panel that adds the data source for control. When a user configures a data source for the App Plugin, the class is instantiated as an Angular controller and loaded with a View based on the class’s templateUrl that renders the data from the panel that defines the configuration. The following is an example of the page:

/ * file path for/SRC/datasource/config. CTRL. Ts * /
import * as _ from 'lodash';
import { SERVICES } from './tc_monitor';

export class TCMonitorDatasourceConfigCtrl {
  static templateUrl = 'datasource/partials/config.html';   / / specify the Controller corresponding to the View file, and the actual path to/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; }); }}Copy the code

The end of the

Tencent Cloud Monitor App has been open source on github.com. Welcome to mention issues and give us encouragement for Star. Address of the project: TencentCloud/TencentCloud – monitor – grafana – app (github.com/TencentClou…).

Project code Development members:

  • susiezhao(github.com/susiezhao)
  • taoran34(github.com/taoran34)