skywalking-booster-ui/src/hooks/useProcessor.ts
2022-01-23 17:01:58 +08:00

253 lines
8.4 KiB
TypeScript

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { RespFields, MetricQueryTypes, CalculationType } from "./data";
import { ElMessage } from "element-plus";
import { useDashboardStore } from "@/store/modules/dashboard";
import { useSelectorStore } from "@/store/modules/selectors";
import { useAppStoreWithOut } from "@/store/modules/app";
import { Instance } from "@/types/selector";
export function useQueryProcessor(config: any) {
if (!(config.metrics && config.metrics.length)) {
return;
}
const appStore = useAppStoreWithOut();
const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore();
const conditions: { [key: string]: unknown } = {
duration: appStore.durationTime,
};
const variables: string[] = [`$duration: Duration!`];
const { currentPod, currentService, currentDestPod, currentDestService } =
selectorStore;
const { entity } = dashboardStore;
const isRelation = [
"ServiceRelation",
"ServiceInstanceRelation",
"EndpointRelation",
].includes(entity);
const fragment = config.metrics.map((name: string, index: number) => {
const metricType = config.metricTypes[index] || "";
const labels = ["0", "1", "2", "3", "4"];
if (
[
MetricQueryTypes.ReadSampledRecords,
MetricQueryTypes.SortMetrics,
].includes(metricType)
) {
variables.push(`$condition${index}: TopNCondition!`);
conditions[`condition${index}`] = {
name,
parentService: ["Service", "All"].includes(entity)
? null
: currentService.value,
normal: currentService.normal,
scope: entity,
topN: 10,
order: "DES",
};
} else {
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
variables.push(`$labels${index}: [String!]!`);
conditions[`labels${index}`] = labels;
}
variables.push(`$condition${index}: MetricsCondition!`);
conditions[`condition${index}`] = {
name,
entity: {
scope: entity,
serviceName: entity === "All" ? undefined : currentService.value,
normal: entity === "All" ? undefined : currentService.normal,
serviceInstanceName: entity.includes("ServiceInstance")
? currentPod
: undefined,
endpointName: entity.includes("Endpoint") ? currentPod : undefined,
destNormal: isRelation ? currentDestService.normal : undefined,
destServiceName: isRelation ? currentDestService.value : undefined,
destServiceInstanceName:
entity === "ServiceInstanceRelation" ? currentDestPod : undefined,
destEndpointName:
entity === "EndpointRelation" ? currentDestPod : undefined,
},
};
}
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
} else {
return `${name}${index}: ${metricType}(condition: $condition${index}, duration: $duration)${RespFields[metricType]}`;
}
});
const queryStr = `query queryData(${variables}) {${fragment}}`;
return {
queryStr,
conditions,
};
}
export function useSourceProcessor(
resp: { errors: string; data: { [key: string]: any } },
config: { metrics: string[]; metricTypes: string[] }
) {
if (resp.errors) {
ElMessage.error(resp.errors);
return {};
}
const source: { [key: string]: unknown } = {};
const keys = Object.keys(resp.data);
config.metricTypes.forEach((type: string, index) => {
const m = config.metrics[index];
if (type === MetricQueryTypes.ReadMetricsValues) {
source[m] = resp.data[keys[index]].values.values.map(
(d: { value: number }) => d.value
);
}
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
const resVal = Object.values(resp.data)[0] || [];
const labelsIdx = ["0", "1", "2", "3", "4"];
const labels = ["P50", "P75", "P90", "P95", "P99"];
for (const item of resVal) {
const values = item.values.values.map(
(d: { value: number }) => d.value
);
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
if (labels[indexNum] && indexNum > -1) {
source[labels[indexNum]] = values;
} else {
source[item.label] = values;
}
}
}
if (type === MetricQueryTypes.ReadMetricsValue) {
source[m] = Object.values(resp.data)[0];
}
if (
type === MetricQueryTypes.SortMetrics ||
type === MetricQueryTypes.ReadSampledRecords
) {
source[m] = Object.values(resp.data)[0] || [];
}
if (type === MetricQueryTypes.READHEATMAP) {
const resVal = Object.values(resp.data)[0] || {};
const nodes = [] as any;
if (!(resVal && resVal.values)) {
source[m] = { nodes: [] };
return;
}
resVal.values.forEach((items: { values: number[] }, x: number) => {
const grids = items.values.map((val: number, y: number) => [x, y, val]);
nodes.push(...grids);
});
let buckets = [] as any;
if (resVal.buckets.length) {
buckets = [
resVal.buckets[0].min,
...resVal.buckets.map(
(item: { min: string; max: string }) => item.max
),
];
}
source[m] = { nodes, buckets }; // nodes: number[][]
}
});
return source;
}
function aggregation(json: {
data: number;
type: string;
aggregationNum: number;
}) {
if (isNaN(json.aggregationNum)) {
return json.data;
}
if (json.type === CalculationType.Plus) {
return json.data + json.aggregationNum;
}
if (json.type === CalculationType.Minus) {
return json.data - json.aggregationNum;
}
if (json.type === CalculationType.Multiplication) {
return json.data * json.aggregationNum;
}
if (json.type === CalculationType.Division) {
return json.data / json.aggregationNum;
}
return json.data;
}
export function useQueryPodsMetrics(
pods: Instance[],
config: { metrics: string[]; metricTypes: string[] }
) {
const appStore = useAppStoreWithOut();
const selectorStore = useSelectorStore();
const conditions: { [key: string]: unknown } = {
duration: appStore.durationTime,
};
const variables: string[] = [`$duration: Duration!`];
const { currentService } = selectorStore;
const fragmentList = pods.map((d: Instance, index: number) => {
const param = {
scope: "ServiceInstance",
serviceName: currentService.label,
serviceInstanceName: d.label,
normal: currentService.normal,
};
const f = config.metrics.map((name: string, idx: number) => {
const metricType = config.metricTypes[idx] || "";
conditions[`condition${index}${idx}`] = {
name,
entity: param,
};
variables.push(`$condition${index}${idx}: MetricsCondition!`);
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, duration: $duration)${RespFields[metricType]}`;
});
return f;
});
const fragment = fragmentList.flat(1).join(" ");
const queryStr = `query queryData(${variables}) {${fragment}}`;
return { queryStr, conditions };
}
export function usePodsSource(
instances: Instance[],
resp: { errors: string; data: { [key: string]: any } },
config: { metrics: string[]; metricTypes: string[] }
): any {
if (resp.errors) {
ElMessage.error(resp.errors);
return {};
}
const data = instances.map((d: Instance | any, idx: number) => {
config.metrics.map((name: string, index: number) => {
const key = name + idx + index;
d[name] = resp.data[key].values.values.map(
(d: { value: number }) => d.value
);
});
return d;
});
return data;
}