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/04/30 09:06:39 UTC

[skywalking-grafana-plugins] branch main updated (ceeae96 -> 7d35f8e)

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

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


    from ceeae96  feat: update query editor
     new b5f3687  feat: query node metrics
     new 7d35f8e  feat: query call metrics

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/components/ConfigEditor.tsx |  2 +-
 src/components/QueryEditor.tsx  |  8 +----
 src/datasource.ts               | 74 +++++++++++++++++++++++++++++++++--------
 src/types.ts                    | 14 +++++++-
 4 files changed, 76 insertions(+), 22 deletions(-)


[skywalking-grafana-plugins] 01/02: feat: query node metrics

Posted by qi...@apache.org.
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 b5f3687e325623c28bfd0d8c782a5b9c54ff454f
Author: Fine0830 <fa...@gmail.com>
AuthorDate: Sun Apr 30 16:39:42 2023 +0800

    feat: query node metrics
---
 src/components/ConfigEditor.tsx |  2 +-
 src/datasource.ts               | 56 +++++++++++++++++++++++++++++++++--------
 src/types.ts                    | 13 ++++++++++
 3 files changed, 59 insertions(+), 12 deletions(-)

diff --git a/src/components/ConfigEditor.tsx b/src/components/ConfigEditor.tsx
index 3a9345b..c1afd1c 100644
--- a/src/components/ConfigEditor.tsx
+++ b/src/components/ConfigEditor.tsx
@@ -57,7 +57,7 @@ export function ConfigEditor(props: Props) {
         <Input
           onChange={onURLChange}
           value={jsonData.URL || ''}
-          placeholder="http://skywalking.example.com"
+          placeholder="http://skywalking.example.com/graphql"
           width={40}
         />
       </InlineField>
diff --git a/src/datasource.ts b/src/datasource.ts
index 94f507b..cc83b56 100644
--- a/src/datasource.ts
+++ b/src/datasource.ts
@@ -12,7 +12,7 @@ import dayjs from "dayjs";
 import timezone from "dayjs/plugin/timezone";
 import utc from "dayjs/plugin/utc";
 
-import { MyQuery, MyDataSourceOptions, DEFAULT_QUERY } from './types';
+import { MyQuery, MyDataSourceOptions, DEFAULT_QUERY, DurationTime, MetricData } from './types';
 import {Fragments, RoutePath, TimeType } from "./constant";
 
 export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
@@ -44,19 +44,22 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
       const query = defaults(target, DEFAULT_QUERY);
       const serviceName = getTemplateSrv().replace(query.service, options.scopedVars);
       const layer = getTemplateSrv().replace(query.layer, options.scopedVars);
-      this.validate(layer);
+      const nodeMetrics = getTemplateSrv().replace(query.nodeMetrics, options.scopedVars);
+      let services = [];
       let t: any = {
         query: Fragments.globalTopology,
         variables: {duration},
       };
+      let serviceObj;
+      // fetch services from api
+      const  s =  {
+        query: Fragments.services,
+        variables: {duration, keyword: ""},
+      };
+      const resp = await this.doRequest(s);
+      services = resp.data.services || [];
       if (serviceName) {
-        const  s =  {
-          query: Fragments.services,
-          variables: {duration, keyword: ""},
-        };
-        // fetch services from api
-        const resp = await this.doRequest(s);
-        const serviceObj = (resp.data.services || []).find((d: {name: string, id: string}) => d.name === serviceName);
+        serviceObj = services.find((d: {name: string, id: string}) => d.name === serviceName);
         if(serviceObj) {
           t = {
             query: Fragments.serviceTopolgy,
@@ -67,6 +70,16 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
       
       // fetch topology data from api
       const res = await this.doRequest(t);
+      if (layer && nodeMetrics) {
+        const regex = /{[^}]+}/g;
+        const arr = nodeMetrics.match(regex);
+        const metrics = arr?.map((d: string) => JSON.parse(d)) || [];
+        const names = metrics?.map((d: MetricData) => d.name);
+        const ids = serviceObj ? [serviceObj.id] : services.map((d: any) => d.id);
+        const m = this.queryTopologyMetrics(names, ids, duration);
+        const metricJson = await this.doRequest(m);
+        console.log(metricJson);
+      }
       const nodes = res.data.topology.nodes || [];
       const calls = res.data.topology.calls || [];
       const nodeFrame =  new MutableDataFrame({
@@ -115,8 +128,29 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
     return result;
   }
 
-  validate(param: string) {
-    console.log(param);
+  queryTopologyMetrics(metrics: string[], ids: string[], duration: DurationTime) {
+    const conditions: { [key: string]: unknown } = {
+      duration,
+      ids,
+    };
+    const variables: string[] = [`$duration: Duration!`, `$ids: [ID!]!`];
+    const fragmentList = metrics.map((d: string, index: number) => {
+      conditions[`m${index}`] = d;
+      variables.push(`$m${index}: String!`);
+
+      return `${d}: getValues(metric: {
+        name: $m${index}
+        ids: $ids
+      }, duration: $duration) {
+        values {
+          id
+          value
+        }
+      }`;
+    });
+    const query = `query queryData(${variables}) {${fragmentList.join(" ")}}`;
+
+    return { query, variables: conditions };
   }
 
   timeFormat(time: Date[]) {
diff --git a/src/types.ts b/src/types.ts
index 8244a98..7a05872 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -24,3 +24,16 @@ export interface MyDataSourceOptions extends DataSourceJsonData {
 export interface MySecureJsonData {
   apiKey?: string;
 }
+
+export type DurationTime = {
+  start: string;
+  end: string;
+  step: string;
+}
+
+export type MetricData = {
+  name: string;
+  unit: string;
+  label: string;
+  calculation: string;
+}


[skywalking-grafana-plugins] 02/02: feat: query call metrics

Posted by qi...@apache.org.
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 7d35f8e932733f66f1d6b1a8e5383c88e453ef0e
Author: Fine0830 <fa...@gmail.com>
AuthorDate: Sun Apr 30 16:52:01 2023 +0800

    feat: query call metrics
---
 src/components/QueryEditor.tsx |  8 +-------
 src/datasource.ts              | 36 +++++++++++++++++++++++++-----------
 src/types.ts                   |  1 -
 3 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/src/components/QueryEditor.tsx b/src/components/QueryEditor.tsx
index d08bfd7..1f14503 100644
--- a/src/components/QueryEditor.tsx
+++ b/src/components/QueryEditor.tsx
@@ -10,9 +10,6 @@ export function QueryEditor({ query, onChange, onRunQuery }: Props) {
   const onServiceChange = (event: ChangeEvent<HTMLInputElement>) => {
     onChange({ ...query, service: event.target.value });
   };
-  const onLayerChange = (event: ChangeEvent<HTMLInputElement>) => {
-    onChange({ ...query, layer: event.target.value });
-  };
   const onNodeMetricsChange = (event: ChangeEvent<HTMLInputElement>) => {
     onChange({ ...query, nodeMetrics: event.target.value });
   };
@@ -25,16 +22,13 @@ export function QueryEditor({ query, onChange, onRunQuery }: Props) {
   const onRunQueryText = () => {
     onRunQuery();
   };
-  const { service, layer, nodeMetrics, edgeServerMetrics, edgeClientMetrics } = query;
+  const { service, nodeMetrics, edgeServerMetrics, edgeClientMetrics } = query;
 
   return (
     <div className="gf-form-group">
       <InlineField label="Service"  tooltip="Not used yet" labelWidth={20}>
         <Input onBlur={onRunQueryText} onChange={onServiceChange} value={service || ''} width={40} />
       </InlineField>
-      <InlineField label="Layer"  tooltip="Not used yet" labelWidth={20}>
-        <Input onBlur={onRunQueryText} onChange={onLayerChange} value={layer || ''} width={40} />
-      </InlineField>
       <InlineField label="Node Metrics"  tooltip="Not used yet" labelWidth={20}>
         <Input onBlur={onRunQueryText} onChange={onNodeMetricsChange} value={nodeMetrics || ''} width={60} />
       </InlineField>
diff --git a/src/datasource.ts b/src/datasource.ts
index cc83b56..670d42e 100644
--- a/src/datasource.ts
+++ b/src/datasource.ts
@@ -43,8 +43,9 @@ 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 layer = getTemplateSrv().replace(query.layer, 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);
       let services = [];
       let t: any = {
         query: Fragments.globalTopology,
@@ -67,18 +68,20 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
           };
         }
       }
-      
+
+      const ids = serviceObj ? [serviceObj.id] : services.map((d: any) => d.id);
       // fetch topology data from api
       const res = await this.doRequest(t);
-      if (layer && nodeMetrics) {
-        const regex = /{[^}]+}/g;
-        const arr = nodeMetrics.match(regex);
-        const metrics = arr?.map((d: string) => JSON.parse(d)) || [];
-        const names = metrics?.map((d: MetricData) => d.name);
-        const ids = serviceObj ? [serviceObj.id] : services.map((d: any) => d.id);
-        const m = this.queryTopologyMetrics(names, ids, duration);
-        const metricJson = await this.doRequest(m);
-        console.log(metricJson);
+
+      // fetch topology metrics from api
+      if (nodeMetrics) {
+        await this.parseMetrics(nodeMetrics, ids, duration);
+      }
+      if (edgeServerMetrics) {
+        await this.parseMetrics(edgeServerMetrics, ids, duration);
+      }
+      if (edgeClientMetrics) {
+        await this.parseMetrics(edgeClientMetrics, ids, duration);
       }
       const nodes = res.data.topology.nodes || [];
       const calls = res.data.topology.calls || [];
@@ -128,6 +131,17 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
     return result;
   }
 
+  async parseMetrics(params: string, ids: string[], duration: DurationTime) {
+    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);
+    const m = this.queryTopologyMetrics(names, ids, duration);
+    const metricJson = await this.doRequest(m);
+
+    return metricJson;
+  }
+
   queryTopologyMetrics(metrics: string[], ids: string[], duration: DurationTime) {
     const conditions: { [key: string]: unknown } = {
       duration,
diff --git a/src/types.ts b/src/types.ts
index 7a05872..d1583c3 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -2,7 +2,6 @@ import { DataQuery, DataSourceJsonData } from '@grafana/data';
 
 export interface MyQuery extends DataQuery {
   service?: string;
-  layer?: string;
   nodeMetrics?: string;
   edgeServerMetrics?: string;
   edgeClientMetrics?: string;