You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by qi...@apache.org on 2023/05/07 09:57:08 UTC

[skywalking-grafana-plugins] 03/04: feat: add expressions

This is an automated email from the ASF dual-hosted git repository.

qiuxiafan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-grafana-plugins.git

commit c6330b730817fa51eb9c7d699c7cafc35e4e195b
Author: Fine0830 <fa...@gmail.com>
AuthorDate: Sun May 7 17:36:44 2023 +0800

    feat: add expressions
---
 src/constant.ts   |  15 ++++++++
 src/datasource.ts | 112 ++++++++++++++++++++++++++++++++++++++++++------------
 src/types.ts      |   1 -
 3 files changed, 102 insertions(+), 26 deletions(-)

diff --git a/src/constant.ts b/src/constant.ts
index ea4ed84..51b2774 100644
--- a/src/constant.ts
+++ b/src/constant.ts
@@ -12,3 +12,18 @@ export enum TimeType {
   HOUR_TIME = "HOUR",
   DAY_TIME = "DAY",
 }
+export enum Calculations {
+  Percentage = "percentage",
+  ByteToKB = "byteToKB",
+  ByteToMB = "byteToMB",
+  ByteToGB = "byteToGB",
+  Apdex = "apdex",
+  ConvertSeconds = "convertSeconds",
+  ConvertMilliseconds = "convertMilliseconds",
+  MsToS = "msTos",
+  Average = "average",
+  PercentageAvg = "percentageAvg",
+  ApdexAvg = "apdexAvg",
+  SecondToDay = "secondToDay",
+  NanosecondToMillisecond = "nanosecondToMillisecond",
+}
diff --git a/src/datasource.ts b/src/datasource.ts
index b221503..a1df3d0 100644
--- a/src/datasource.ts
+++ b/src/datasource.ts
@@ -23,7 +23,7 @@ import {
   Node,
   Recordable
 } from './types';
-import {Fragments, RoutePath, TimeType } from "./constant";
+import {Fragments, RoutePath, TimeType, Calculations } from "./constant";
 
 export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
   URL: string;
@@ -53,9 +53,12 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
     const promises = options.targets.map(async (target) => {
       const query = defaults(target, DEFAULT_QUERY);
       const serviceName = getTemplateSrv().replace(query.service, options.scopedVars);
-      const nodeMetrics = getTemplateSrv().replace(query.nodeMetrics, options.scopedVars);
-      const edgeServerMetrics = getTemplateSrv().replace(query.edgeServerMetrics, options.scopedVars);
-      const edgeClientMetrics = getTemplateSrv().replace(query.edgeClientMetrics, options.scopedVars);
+      const nodeMetricsStr = getTemplateSrv().replace(query.nodeMetrics, options.scopedVars);
+      const nodeMetrics = nodeMetricsStr ? this.parseMetrics(nodeMetricsStr) : [];
+      const edgeServerMetricsStr = getTemplateSrv().replace(query.edgeServerMetrics, options.scopedVars);
+      const edgeServerMetrics = edgeServerMetricsStr ? this.parseMetrics(edgeServerMetricsStr) : [];
+      const edgeClientMetricsStr = getTemplateSrv().replace(query.edgeClientMetrics, options.scopedVars);
+      const edgeClientMetrics = edgeClientMetricsStr ? this.parseMetrics(edgeClientMetricsStr) : [];
       let services = [];
       let t: {
         query: string;
@@ -89,15 +92,15 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
       const idsC = calls.filter((i: Call) => i.detectPoints.includes("CLIENT")).map((b: Call) => b.id);
       const ids = nodes.map((d: Node) => d.id);
       // fetch topology metrics from api
-      const nodeMetricsResp = nodeMetrics ? await this.parseMetrics(nodeMetrics, ids, duration) : null;
-      const edgeServerMetricsResp = edgeServerMetrics && idsS.length ? await this.parseMetrics(edgeServerMetrics, idsS, duration) : null;
-      const edgeClientMetricsResp = edgeClientMetrics && idsC.length ? await this.parseMetrics(edgeClientMetrics, idsC, duration) : null;
+      const nodeMetricsResp = nodeMetrics.length ? await this.queryMetrics(nodeMetrics, ids, duration) : null;
+      const edgeServerMetricsResp = edgeServerMetrics.length && idsS.length ? await this.queryMetrics(edgeServerMetrics, idsS, duration) : null;
+      const edgeClientMetricsResp = edgeClientMetrics.length && idsC.length ? await this.queryMetrics(edgeClientMetrics, idsC, duration) : null;
       const topology = this.setTopologyMetrics({
         nodes,
         calls,
-        nodeMetrics: nodeMetricsResp ? nodeMetricsResp.data : undefined,
-        edgeServerMetrics: edgeServerMetricsResp ? edgeServerMetricsResp.data : undefined,
-        edgeClientMetrics: edgeClientMetricsResp ? edgeClientMetricsResp.data : undefined,
+        nodeMetrics: nodeMetricsResp ? {...nodeMetricsResp, config: nodeMetrics} : undefined,
+        edgeServerMetrics: edgeServerMetricsResp ? {...edgeServerMetricsResp, config: nodeMetrics} : undefined,
+        edgeClientMetrics: edgeClientMetricsResp ? {...edgeClientMetricsResp, config: nodeMetrics} : undefined,
       });
       const {nodeFieldTypes, edgeServerFieldTypes, edgeClientFieldTypes} = this.setFieldTypes({
         nodeMetrics: nodeMetricsResp ? nodeMetricsResp.data : undefined,
@@ -154,11 +157,16 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
     return result;
   }
 
-  async parseMetrics(params: string, ids: string[], duration: DurationTime) {
+  parseMetrics(params: string) {
     const regex = /{[^}]+}/g;
     const arr = params.match(regex);
     const metrics = arr?.map((d: string) => JSON.parse(d)) || [];
-    const names = metrics?.map((d: MetricData) => d.name);
+
+    return metrics;
+  }
+
+  async queryMetrics(params: any[], ids: string[], duration: DurationTime) {
+    const names = params.map((d: MetricData) => d.name);
     const m = this.queryTopologyMetrics(names, ids, duration);
     const metricJson = await this.doRequest(m);
 
@@ -223,32 +231,38 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
     const edgeServerMetrics = params.edgeServerMetrics || {};
     const edgeClientMetrics = params.edgeClientMetrics || {};
     const nodes = params.nodes.map((next: Node) => {
-      for (const [index, k] of Object.keys(nodeMetrics).entries()) {
-        const m = (nodeMetrics[k].values).find((v: {id: string}) => v.id === next.id) || {value: NaN};
+      for (const [index, k] of Object.keys(nodeMetrics.data).entries()) {
+        const c = nodeMetrics.config.find((d: MetricData) => d.name === k) || {};
+        const m = (nodeMetrics.data[k].values).find((v: {id: string}) => v.id === next.id) || {isEmptyValue: true};
+        const value = m.isEmptyValue ? NaN : this.expression(Number(m.value), c.calculation);
         if (index === 0) {
-          next.mainstat = m.value;
+          next.mainstat = value;
         } else if (index === 1) {
-          next.secondarystat = m.value;
+          next.secondarystat = value;
         } else {
-          next[`arc__${k}`] = m.value;
+          next[`arc__${k}`] = value;
         }
       }
       return next;
     })
     const calls = params.calls.map((next: Call) => {
-      for (const [index, k] of Object.keys(edgeServerMetrics).entries()) {
-        const m = (edgeServerMetrics[k].values).find((v: {id: string}) => v.id === next.id) || {value: NaN};
+      for (const [index, k] of Object.keys(edgeServerMetrics.data).entries()) {
+        const c = edgeServerMetrics.config.find((d: MetricData) => d.name === k) || {};
+        const m = (edgeServerMetrics.data[k].values).find((v: {id: string}) => v.id === next.id) || {value: NaN};
+        const value = m.isEmptyValue ? NaN : this.expression(Number(m.value), c.calculation);
         if (index === 0) {
-          next.mainstat = m.value;
+          next.mainstat = value;
         } else if (index === 1) {
-          next.secondarystat = m.value;
+          next.secondarystat = value;
         } else {
-          next[`detail__${k}`] = m.value;
+          next[`detail__${k}`] = value;
         }
       }
-      for (const k of Object.keys(edgeClientMetrics)) {
-        const m = (edgeClientMetrics[k].values).find((v: {id: string}) => v.id === next.id) || {value: NaN};
-        next[`detail__${k}`] = m.value;
+      for (const k of Object.keys(edgeClientMetrics.data)) {
+        const c = edgeClientMetrics.config.find((d: MetricData) => d.name === k) || {};
+        const m = (edgeClientMetrics.data[k].values).find((v: {id: string}) => v.id === next.id) || {value: NaN};
+        const value = m.isEmptyValue ? NaN : this.expression(Number(m.value), c.calculation);
+        next[`detail__${k}`] = value;
       }
       return next;
     })
@@ -256,6 +270,54 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
     return {nodes, calls}
   }
 
+  expression(val: number, calculation: string): number | string {
+    let data: number | string = Number(val);
+  
+    switch (calculation) {
+      case Calculations.Percentage:
+        data = (val / 100).toFixed(2);
+        break;
+      case Calculations.PercentageAvg:
+        data = (val / 100).toFixed(2);
+        break;
+      case Calculations.ByteToKB:
+        data = (val / 1024).toFixed(2);
+        break;
+      case Calculations.ByteToMB:
+        data = (val / 1024 / 1024).toFixed(2);
+        break;
+      case Calculations.ByteToGB:
+        data = (val / 1024 / 1024 / 1024).toFixed(2);
+        break;
+      case Calculations.Apdex:
+        data = (val / 10000).toFixed(2);
+        break;
+      case Calculations.ConvertSeconds:
+        data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss");
+        break;
+      case Calculations.ConvertMilliseconds:
+        data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
+        break;
+      case Calculations.MsToS:
+        data = (val / 1000).toFixed(2);
+        break;
+      case Calculations.SecondToDay:
+        data = (val / 86400).toFixed(2);
+        break;
+      case Calculations.NanosecondToMillisecond:
+        data = (val / 1000 / 1000).toFixed(2);
+        break;
+      case Calculations.ApdexAvg:
+        data = (val / 10000).toFixed(2);
+        break;
+      default:
+        data = data;
+        break;
+    }
+  
+    return data;
+  }
+
   queryTopologyMetrics(metrics: string[], ids: string[], duration: DurationTime) {
     const conditions: { [key: string]: unknown } = {
       duration,
diff --git a/src/types.ts b/src/types.ts
index c770c08..53b2237 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -32,7 +32,6 @@ export type DurationTime = {
 
 export type MetricData = {
   name: string;
-  unit: string;
   label: string;
   calculation: string;
 }