mirror of
https://github.com/didi/KnowStreaming.git
synced 2026-01-05 13:08:48 +08:00
kafka-manager 2.0
This commit is contained in:
210
kafka-manager-console/src/container/admin/data-curve/config.ts
Normal file
210
kafka-manager-console/src/container/admin/data-curve/config.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
import { EChartOption } from 'echarts/lib/echarts';
|
||||
import moment from 'moment';
|
||||
import { ICurve } from 'container/common-curve/config';
|
||||
import { adminMonitor } from 'store/admin-monitor';
|
||||
import { parseBrokerMetricOption } from './parser';
|
||||
|
||||
export interface IPeriod {
|
||||
label: string;
|
||||
key: string;
|
||||
dateRange: [moment.Moment, moment.Moment];
|
||||
}
|
||||
|
||||
export const getMoment = () => {
|
||||
return moment();
|
||||
};
|
||||
export const baseColors = ['#F28E61', '#7082A6', '#5AD2A2', '#E96A72', '#59AEE9', '#65A8BF', '#9D7ECF'];
|
||||
|
||||
export enum curveKeys {
|
||||
'byteIn/byteOut' = 'byteIn/byteOut',
|
||||
bytesRejectedPerSec = 'bytesRejectedPerSec',
|
||||
failFetchRequestPerSec = 'failFetchRequestPerSec',
|
||||
failProduceRequestPerSec = 'failProduceRequestPerSec',
|
||||
fetchConsumerRequestPerSec = 'fetchConsumerRequestPerSec',
|
||||
healthScore = 'healthScore',
|
||||
messagesInPerSec = 'messagesInPerSec',
|
||||
networkProcessorIdlPercent = 'networkProcessorIdlPercent',
|
||||
produceRequestPerSec = 'produceRequestPerSec',
|
||||
requestHandlerIdlPercent = 'requestHandlerIdlPercent',
|
||||
requestQueueSize = 'requestQueueSize',
|
||||
responseQueueSize = 'responseQueueSize',
|
||||
totalTimeFetchConsumer99Th = 'totalTimeFetchConsumer99Th',
|
||||
totalTimeProduce99Th = 'totalTimeProduce99Th',
|
||||
}
|
||||
|
||||
export const byteCurves: ICurve[] = [
|
||||
{
|
||||
title: 'byteIn/byteOut',
|
||||
path: curveKeys['byteIn/byteOut'],
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'bytesRejectedPerSec',
|
||||
path: curveKeys.bytesRejectedPerSec,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: ['#E96A72'],
|
||||
},
|
||||
];
|
||||
|
||||
export const perSecCurves: ICurve[] = [
|
||||
{
|
||||
title: 'failFetchRequestPerSec',
|
||||
path: curveKeys.failFetchRequestPerSec,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'failProduceRequestPerSec',
|
||||
path: curveKeys.failProduceRequestPerSec,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'fetchConsumerRequestPerSec',
|
||||
path: curveKeys.fetchConsumerRequestPerSec,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'produceRequestPerSec',
|
||||
path: curveKeys.produceRequestPerSec,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
},
|
||||
];
|
||||
|
||||
export const otherCurves: ICurve[] = [
|
||||
{
|
||||
title: 'healthScore',
|
||||
path: curveKeys.healthScore,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'messagesInPerSec',
|
||||
path: curveKeys.messagesInPerSec,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'networkProcessorIdlPercent',
|
||||
path: curveKeys.networkProcessorIdlPercent,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'requestHandlerIdlPercent',
|
||||
path: curveKeys.requestHandlerIdlPercent,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'requestQueueSize',
|
||||
path: curveKeys.requestQueueSize,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'responseQueueSize',
|
||||
path: curveKeys.responseQueueSize,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'totalTimeFetchConsumer99Th',
|
||||
path: curveKeys.totalTimeFetchConsumer99Th,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
}, {
|
||||
title: 'totalTimeProduce99Th',
|
||||
path: curveKeys.totalTimeProduce99Th,
|
||||
api: adminMonitor.getBrokersChartsData,
|
||||
colors: baseColors,
|
||||
},
|
||||
];
|
||||
|
||||
export enum curveType {
|
||||
byteCurves = 'byteCurves',
|
||||
perSecCurves = 'perSecCurves',
|
||||
other = 'other',
|
||||
}
|
||||
|
||||
export interface ICurveType {
|
||||
type: curveType;
|
||||
title: string;
|
||||
curves: ICurve[];
|
||||
parser: (option: ICurve, data: any[]) => EChartOption;
|
||||
}
|
||||
|
||||
export const byteTypeCurves: ICurveType[] = [
|
||||
{
|
||||
type: curveType.byteCurves,
|
||||
title: 'byte',
|
||||
curves: byteCurves.concat(perSecCurves, otherCurves),
|
||||
parser: parseBrokerMetricOption,
|
||||
},
|
||||
];
|
||||
export const perSecTypeCurves: ICurveType[] = [
|
||||
{
|
||||
type: curveType.perSecCurves,
|
||||
title: 'perSec',
|
||||
curves: perSecCurves,
|
||||
parser: parseBrokerMetricOption,
|
||||
},
|
||||
];
|
||||
export const otherTypeCurves: ICurveType[] = [
|
||||
{
|
||||
type: curveType.other,
|
||||
title: 'other',
|
||||
curves: otherCurves,
|
||||
parser: parseBrokerMetricOption,
|
||||
},
|
||||
];
|
||||
|
||||
export const allCurves: ICurveType[] = [].concat(byteTypeCurves);
|
||||
|
||||
const curveKeyMap = new Map<string, {typeInfo: ICurveType, curveInfo: ICurve}>();
|
||||
allCurves.forEach(t => {
|
||||
t.curves.forEach(c => {
|
||||
curveKeyMap.set(c.path, {
|
||||
typeInfo: t,
|
||||
curveInfo: c,
|
||||
});
|
||||
});
|
||||
});
|
||||
export const CURVE_KEY_MAP = curveKeyMap;
|
||||
|
||||
export const PERIOD_RADIO = [
|
||||
{
|
||||
label: '10分钟',
|
||||
key: 'tenMin',
|
||||
get dateRange() {
|
||||
return [getMoment().subtract(10, 'minute'), getMoment()];
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '1小时',
|
||||
key: 'oneHour',
|
||||
get dateRange() {
|
||||
return [getMoment().subtract(1, 'hour'), getMoment()];
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '6小时',
|
||||
key: 'sixHour',
|
||||
get dateRange() {
|
||||
return [getMoment().subtract(6, 'hour'), getMoment()];
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '近1天',
|
||||
key: 'oneDay',
|
||||
get dateRange() {
|
||||
return [getMoment().subtract(1, 'day'), getMoment()];
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '近1周',
|
||||
key: 'oneWeek',
|
||||
get dateRange() {
|
||||
return [getMoment().subtract(7, 'day'), getMoment()];
|
||||
},
|
||||
},
|
||||
] as IPeriod[];
|
||||
|
||||
const periodRadioMap = new Map<string, IPeriod>();
|
||||
PERIOD_RADIO.forEach(p => {
|
||||
periodRadioMap.set(p.key, p);
|
||||
});
|
||||
export const PERIOD_RADIO_MAP = periodRadioMap;
|
||||
@@ -0,0 +1,14 @@
|
||||
.curve-wrapper {
|
||||
background-color: #fff;
|
||||
padding: 24px;
|
||||
position: relative;
|
||||
}
|
||||
.right-btn {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
top: 24px;
|
||||
}
|
||||
.operator-select {
|
||||
position: absolute;
|
||||
top: 34px;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import './index.less';
|
||||
import { Radio, DatePicker, RadioChangeEvent, RangePickerValue, Button, Icon } from 'component/antd';
|
||||
import { curveInfo } from 'store/curve-info';
|
||||
import { curveKeys, CURVE_KEY_MAP, PERIOD_RADIO_MAP, PERIOD_RADIO } from './config';
|
||||
import moment = require('moment');
|
||||
import { observer } from 'mobx-react';
|
||||
import { timeStampStr } from 'constants/strategy';
|
||||
|
||||
@observer
|
||||
export class DataCurveFilter extends React.Component {
|
||||
public handleRangeChange = (dates: RangePickerValue, dateStrings: [string, string]) => {
|
||||
curveInfo.setTimeRange(dates as [moment.Moment, moment.Moment]);
|
||||
this.refreshAll();
|
||||
}
|
||||
|
||||
public radioChange = (e: RadioChangeEvent) => {
|
||||
const { value } = e.target;
|
||||
curveInfo.setTimeRange(PERIOD_RADIO_MAP.get(value).dateRange);
|
||||
this.refreshAll();
|
||||
}
|
||||
|
||||
public refreshAll = () => {
|
||||
Object.keys(curveKeys).forEach((c: curveKeys) => {
|
||||
const { typeInfo, curveInfo: option } = CURVE_KEY_MAP.get(c);
|
||||
const { parser } = typeInfo;
|
||||
curveInfo.getCommonCurveData(option, parser, true);
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<>
|
||||
<Radio.Group onChange={this.radioChange} defaultValue={curveInfo.periodKey}>
|
||||
{PERIOD_RADIO.map(p => <Radio.Button key={p.key} value={p.key}>{p.label}</Radio.Button>)}
|
||||
</Radio.Group>
|
||||
<DatePicker.RangePicker
|
||||
format={timeStampStr}
|
||||
onChange={this.handleRangeChange}
|
||||
className="ml-10"
|
||||
value={curveInfo.timeRange}
|
||||
/>
|
||||
<div className="right-btn">
|
||||
<Button onClick={this.refreshAll}><Icon className="dsui-icon-shuaxin1 mr-4" type="reload" />刷新</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
147
kafka-manager-console/src/container/admin/data-curve/parser.ts
Normal file
147
kafka-manager-console/src/container/admin/data-curve/parser.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import moment from 'moment';
|
||||
import { EChartOption } from 'echarts';
|
||||
import { ICurve, ILineData, baseLineLegend, baseLineGrid, baseAxisStyle, noAxis, UNIT_HEIGHT } from 'container/common-curve/config';
|
||||
import { IClusterMetrics, ISeriesOption } from 'types/base-type';
|
||||
import { timeFormat } from 'constants/strategy';
|
||||
import { getFilterSeries } from 'lib/chart-utils';
|
||||
import { dealFlowData } from 'lib/chart-utils';
|
||||
|
||||
export const getBaseOptions = (option: ICurve, data: ILineData[]) => {
|
||||
const date = (data || []).map(i => moment(i.timeStamp).format(timeFormat));
|
||||
|
||||
return {
|
||||
animationDuration: 200,
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
...baseLineLegend,
|
||||
bottom: '0',
|
||||
align: 'auto',
|
||||
},
|
||||
grid: {
|
||||
...baseLineGrid,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: date,
|
||||
...baseAxisStyle,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
...baseAxisStyle,
|
||||
...noAxis,
|
||||
name: option.unit || '',
|
||||
nameTextStyle: {
|
||||
lineHeight: UNIT_HEIGHT,
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
type: 'line',
|
||||
data: data.map(i => {
|
||||
return Number(i.value);
|
||||
}),
|
||||
}],
|
||||
} as EChartOption;
|
||||
};
|
||||
|
||||
export const parseLine = (option: ICurve, data: ILineData[]): EChartOption => {
|
||||
return Object.assign({}, getBaseOptions(option, data), {
|
||||
legend: {
|
||||
...baseLineLegend,
|
||||
bottom: '0',
|
||||
align: 'auto',
|
||||
},
|
||||
}) as EChartOption;
|
||||
};
|
||||
|
||||
export const parseBrokerMetricOption = (option: ICurve, data: IClusterMetrics[]): EChartOption => {
|
||||
let name;
|
||||
let series: ISeriesOption[];
|
||||
data = data || [];
|
||||
data = data.map(item => {
|
||||
return {
|
||||
time: moment(item.gmtCreate).format(timeFormat),
|
||||
...item,
|
||||
};
|
||||
});
|
||||
data = data.sort((a, b) => a.gmtCreate - b.gmtCreate);
|
||||
const legend = option.path === 'byteIn/byteOut' ? ['bytesInPerSec', 'bytesOutPerSec'] : [option.path];
|
||||
series = Array.from(legend, (item: string) => ({
|
||||
name: item,
|
||||
id: item,
|
||||
type: 'line',
|
||||
symbol: 'circle',
|
||||
showSymbol: false,
|
||||
smooth: true,
|
||||
encode: {
|
||||
x: 'time',
|
||||
y: item,
|
||||
tooltip: [
|
||||
item,
|
||||
],
|
||||
},
|
||||
data: data.map(row => row[item] !== null ? Number(row[item]) : null),
|
||||
}));
|
||||
|
||||
const filterSeries = getFilterSeries(series);
|
||||
const { name: unitName, data: xData } = dealFlowData(legend, data);
|
||||
name = unitName;
|
||||
data = xData;
|
||||
|
||||
return {
|
||||
animationDuration: 200,
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
...baseLineGrid,
|
||||
},
|
||||
xAxis: {
|
||||
splitLine: null,
|
||||
type: 'time',
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
...baseAxisStyle,
|
||||
...noAxis,
|
||||
name,
|
||||
nameTextStyle: {
|
||||
lineHeight: UNIT_HEIGHT,
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: legend,
|
||||
...baseLineLegend,
|
||||
bottom: '0',
|
||||
align: 'auto',
|
||||
},
|
||||
dataset: {
|
||||
source: data,
|
||||
},
|
||||
series: filterSeries,
|
||||
};
|
||||
};
|
||||
|
||||
export function isM(arr: number[]) {
|
||||
const filterData = arr.filter(i => i !== 0);
|
||||
if (filterData.length) return filterData.reduce((cur, pre) => cur + pre) / filterData.length >= 1000000;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isK(arr: number[]) {
|
||||
const filterData = arr.filter(i => i !== 0);
|
||||
if (filterData.length) return filterData.reduce((cur, pre) => cur + pre) / filterData.length >= 1000;
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user