diff --git a/.eslintrc.js b/.eslintrc.js index 6d87fa92..55e6cdf2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -295,11 +295,15 @@ module.exports = { ], "space-infix-ops": "error", semi: 1, +<<<<<<< HEAD 'space-before-function-paren': ["error", { "anonymous": "never", "named": "never", "asyncArrow": "always" }], +======= + 'space-before-function-paren': ["error", "never"], +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) 'object-curly-spacing': ['error','always'], 'use-isnan': 'error', 'valid-typeof': 'off', diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 0186536c..e4542f89 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -1,8 +1,14 @@ name: Dashboard tar Release on: +<<<<<<< HEAD release: types: - published +======= + push: + branches: + - nico-dev +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) jobs: package: name: build package @@ -16,13 +22,20 @@ jobs: steps: - uses: actions/checkout@v2 with: +<<<<<<< HEAD ref: 'master' +======= + ref: 'nico-dev' +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) path: source/nebula-graph-dashboard - uses: actions/checkout@v2 with: repository: vesoft-inc/nebula-http-gateway path: source/nebula-http-gateway +<<<<<<< HEAD ##ToDO: add nebula-stats-exporter、node-exporter and prometheus +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) - uses: actions/setup-go@v2 with: go-version: '^1.13.1' @@ -32,8 +45,14 @@ jobs: - name: ls run: ls -a - name: Package +<<<<<<< HEAD run: bash ./source/nebula-graph-dashboard/scripts/package.sh ${{ secrets.GA_ID }} - name: Upload to OSS run: bash ./source/nebula-graph-dashboard/scripts/upload.sh ${{ secrets.OSS_ENDPOINT }} ${{ secrets.OSS_ID }} ${{ secrets.OSS_SECRET }} ${{ secrets.OSS_URL }} +======= + run: bash ./source/nebula-graph-dashboard/scripts/package.sh + - name: Upload to OSS + run: ls -a & ossutil64 -e ${{ secrets.OSS_ENDPOINT }} -i ${{ secrets.OSS_ID }} -k ${{ secrets.OSS_SECRET }} -f cp ./ ${{ secrets.OSS_URL }} --include "nebula-graph-dashboard-beta.tar.gz" --only-current-dir -r +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) diff --git a/DEPLOY.md b/DEPLOY.md index f4352421..30170e09 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # Nebula Graph Dashboard Production Guide(Linux) ## Environment @@ -50,20 +51,79 @@ Attention: the file under these packages is compiled under Linux environment, ca - location:in the same machine with nebula-graph-dashboard - dependency:modify :`./vendors/prometheus/prometheus.yaml` according to node-exporter and nebula-stats-exporter service address - Start: +======= +# Nebula Dashboard 部署文档(Linux) + +## 下载 +` wget https://oss-cdn.nebula-graph.com.cn/nebula-graph-dashboard/nebula-graph-dashboard-beta.tar.gz` + +## 解压 +`tar -xvf nebula-graph-dashboard-beta.tar.gz` + + +## 目录结构说明 +根目录 nebula-graph-dashboard 下一共五个安装包 +- nebula-graph-dashboard ------------------------- 监控平台服务 +- nebula-stats-exporter --------------------- Nebula Graph指标采集服务 +- node-exporter ----------------------------- 机器指标采集服务 +- prometheus -------------------------------- 监控指标存储服务平台 +- nebula-http-gateway + + +## 开始部署 + +1. 部署 node-exporter 服务采集机器指标 +- 安装包:使用 `node-exporter` +- 部署位置:集群里每个需要监控节点机器均需要部署 +- 启动方式: + ```bash + // 把对应 node-exporter 包放到需要监控采集指标的机器上,启动采集服务 + $ cd node-exporter + $ nohup ./node-exporter --web.listen-address=:9200 & + ``` + 启动服务本机地址: http://127.0.0.1:9200 + +2. 部署服务 nebula-stats-exporter 采集nebula指标 +- 安装包: `nebula-stats-exporter` +- 部署位置:与nebula-graph-dashboard部署在同一台机器即可 +- 依赖配置: 需要根据nebula服务部署的节点地址来配 `config.yml` + 启动方式: + ```bash + $ cd nebula-stats-exporter + $ nohup ./nebula-stats-exporter --bare-metal --bare-metal-config=./config.yaml & + ``` + 启动服务本机地址: http://127.0.0.1:9100 + +3. 部署服务 prometheus +- 安装包:`prometheus` +- 部署位置:与nebula-graph-dashboard部署在同一台机器即可 +- 依赖配置:需要根据实际 node-exporter 和 nebula-stats-exporter 的服务ip地址,修改:`./vendors/prometheus/prometheus.yml` +- 启动方式: +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) ```bash $ cd prometheus $ nohup ./prometheus --config.file=./prometheus.yaml & ``` +<<<<<<< HEAD Service address: http://127.0.0.1:9090 4. Nebula-http-gateway - packages: `nebula-http-gateway` - location:in the same machine with nebula-graph-dashboard - Start: +======= + 启动服务地址: http://127.0.0.1:9090 + +4. 部署 nebula-http-gateway +- 安装包: `nebula-http-gateway` +- 部署位置:与nebula-graph-dashboard部署在同一台机器即可 +- 启动方式: +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) ```bash $ cd nebula-http-gateway $ nohup ./nebula-httpd & ``` +<<<<<<< HEAD - Service address: http://127.0.0.1:8090 5. nebula-graph-dashboard @@ -76,10 +136,18 @@ Attention: the file under these packages is compiled under Linux environment, ca }, ``` - Start: +======= +- 启动服务地址: http://127.0.0.1:8090 + +5. 部署 nebula-graph-dashboard +- 安装包: `nebula-graph-dashboard` +- 启动方式: +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) ```bash $ cd nebula-graph-dashboard $ npm run start ``` +<<<<<<< HEAD - service address: http://127.0.0.1:7003 1. Open Nebula Graph Dashboard in browser @@ -96,6 +164,24 @@ $ kill $(lsof -t -i :9090) # stop prometheus service $ kill $(lsof -t -i :8090) # stop nebula-http-gateway $ cd nebula-graph-dashboard $ npm run stop # stop nebula-graph-dashboard +======= +- 启动服务地址: http://127.0.0.1:7003 + +6. 浏览器访问 Nebula Dashboard +访问 http://{{ip}}:7003 + + +## 停止服务 +目前先通过 `kill -9 pid` 的方式来关停服务: + +```bash +$ kill -9 $(lsof -t -i :9200) # 停止 node-exporter 服务 +$ kill -9 $(lsof -t -i :9100) # 停止 nebula-stats-exporter 服务 +$ kill -9 $(lsof -t -i :9090) # 停止 prometheus 服务 +$ kill -9 $(lsof -t -i :8090) # 停止 nebula-http-gateway +$ cd nebula-graph-dashboard +$ npm run stop # 停止 nebula-graph-dashboard +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) ``` diff --git a/README.md b/README.md index d580e79b..85c6a7e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Nebula Graph Dashboard +<<<<<<< HEAD Nebula Graph Dashboard is a tool that assists Nebula Graph in daily service monitoring and management ![](introduction.png) @@ -111,3 +112,47 @@ If you plan to set up dashboard in production, refer to:[production guide](DEP + [中文](https://docs.nebula-graph.com.cn/2.5.0/nebula-dashboard/1.what-is-dashboard/) + [ENGLISH](https://docs.nebula-graph.io/2.5.0/nebula-dashboard/1.what-is-dashboard/) +======= + +## 简介 +用于 Nebula Graph 服务及机器监控 + +## 生产使用 +参考:[安装部署指南](DEPLOY.md) + +## 本地开发 + +### 环境准备 +- node.js +- Linux + +### 服务依赖 +- [nebula-http-gateway](https://github.com/vesoft-inc/nebula-http-gateway) - nebula-graph 网关服务 + 需要配置启动8090的端口服务,将 [gateway.conf](./vendors/gateway.conf) 替换掉 gateway 项目中的 [app.conf](https://github.com/vesoft-inc/nebula-http-gateway/blob/master/conf/app.conf) 即可。 + +- [node-exporter](./vendors/node-exporter/) - 机器指标采集服务 + 启动命令:`./vendors/node-exporter/node-exporter --web.listen-address=:9200` + +- [nebula-stats-exporter](./vendors/nebula-stats-exporter) - nebula graph 指标采集服务 + 从nebula服务中找到对应的metrics接口,文档可参考[Metrics Exporter](https://docs.nebula-graph.io/1.1/manual-EN/3.build-develop-and-administration/7.monitor/1.metrics-exposer/),修改 [nebula-stats-exporter](./vendors/nebula-stats-exporter/config.yaml) + 比如: + ``` + version: v0.0.3 + nebulaItems: + - instanceName: metad0 // 标识 + endpointIP: 10.17.101.126 // 将其换成对应IP + endpointPort: 32839 // 找到对应metrics的端口号 + componentType: metad // 确定当前填写metrics接口的类型 + ``` + 启动命令:`./vendors/nebula-stats-exporter/nebula-stats-exporter --bare-metal --bare-metal-config=./config.yaml` + + +- [prometheus](./vendors/prometheus/prometheus) - 监控指标存储服务 + 修改配置:需要根据实际部署的 node-exporter 和 nebula-stats-exporter 的服务ip,修改[prometheus.yaml](./vendors/prometheus/prometheus.yaml) + +### 启动 nebula-graph-dashboard +``` +$ npm install +$ npm run dev +``` +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) diff --git a/app/assets/components/Charts/LineChart.tsx b/app/assets/components/Charts/LineChart.tsx index 9c37ced7..1393da56 100644 --- a/app/assets/components/Charts/LineChart.tsx +++ b/app/assets/components/Charts/LineChart.tsx @@ -5,10 +5,14 @@ import { ChartCfg } from '@antv/g2/lib/interface'; export interface IProps { renderChart: (chartInstance: Chart) => void; options?: Partial +<<<<<<< HEAD tickInterval?: number baseLine?: number yAxisMaximum?:number isDefaultScale?: boolean +======= + baseLineNum?: number +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) } class LineChart extends React.Component { @@ -77,17 +81,28 @@ class LineChart extends React.Component { } renderChart = () => { +<<<<<<< HEAD const { options, baseLine } = this.props; +======= + const { options, baseLineNum } = this.props; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) this.chartInstance = new Chart({ container: this.chartRef.current, autoFit: true, padding: [20, 0, 0, 0], ...options, }); +<<<<<<< HEAD if(baseLine){ this.chartInstance.annotation().line({ start: ['min', baseLine], end: ['max', baseLine], +======= + if(baseLineNum){ + this.chartInstance.annotation().line({ + start: ['min', baseLineNum], + end: ['max', baseLineNum], +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) style: { stroke: '#e6522b', lineWidth: 1, @@ -95,7 +110,10 @@ class LineChart extends React.Component { }, }); } +<<<<<<< HEAD this.showScaleByBaseLine(); +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) this.chartInstance.interaction('brush'); this.props.renderChart(this.chartInstance); this.chartInstance.render(); diff --git a/app/assets/components/DashboardCard/LineCard.tsx b/app/assets/components/DashboardCard/LineCard.tsx index 0c2b0499..0115cec7 100644 --- a/app/assets/components/DashboardCard/LineCard.tsx +++ b/app/assets/components/DashboardCard/LineCard.tsx @@ -5,14 +5,22 @@ import { Chart, Geometry } from '@antv/g2'; import { ILineChartMetric, IStatSingleItem } from '@assets/utils/interface'; import { configDetailChart } from '@assets/utils/chart/chart'; import { VALUE_TYPE } from '@assets/utils/promQL'; +<<<<<<< HEAD import { getMaxNumAndLength } from '@assets/utils/dashboard'; +======= +import { getProperByteDesc } from '@assets/utils/dashboard'; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) import { Spin } from 'antd'; interface IProps { data: ILineChartMetric[]; valueType: VALUE_TYPE; sizes?: IStatSingleItem[] loading: boolean; +<<<<<<< HEAD baseLine?: number; +======= + baseLineNum?: number; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) } class LineCard extends React.Component { @@ -46,6 +54,7 @@ class LineCard extends React.Component { this.chartInstance.changeData(data); } +<<<<<<< HEAD render() { const { loading, data, valueType, baseLine } = this.props; const { maxNum, maxNumLen } = getMaxNumAndLength({ @@ -64,6 +73,39 @@ class LineCard extends React.Component { renderChart={this.renderLineChart} options={{ padding: [20, 20, 60, 6 * maxNumLen + 30 ] }} /> +======= + getMaxLength = () => { + const { data = [], valueType } = this.props; + const max = _.maxBy(data, item => item.value); + const maxNum = max ? max.value : 0; + const maxNumLen = maxNum.toString().length; + + switch (valueType) { + case VALUE_TYPE.percentage: + return 5; + case VALUE_TYPE.byte: + case VALUE_TYPE.byteSecond: + const { value, unit } = getProperByteDesc(maxNum); + if (valueType === VALUE_TYPE.byteSecond) { + return unit.length + value.toString().length+2; + } + return unit.length + value.toString().length; + case VALUE_TYPE.numberSecond: + return maxNumLen + 2; + default: + return maxNumLen; + } + } + + render() { + const { loading, baseLineNum } = this.props; + if (loading) { + return ; + } + + return ( + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) ); } } diff --git a/app/assets/components/DashboardCard/index.tsx b/app/assets/components/DashboardCard/index.tsx index fe9a4912..7a126f1e 100644 --- a/app/assets/components/DashboardCard/index.tsx +++ b/app/assets/components/DashboardCard/index.tsx @@ -23,7 +23,11 @@ class DashboardCard extends React.PureComponent { } render() { +<<<<<<< HEAD const { title, children, onConfigPanel } = this.props; +======= + const { title, children } = this.props; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) return
diff --git a/app/assets/components/MachineDetail/index.less b/app/assets/components/MachineDetail/index.less index a4aa5a94..19636d2f 100644 --- a/app/assets/components/MachineDetail/index.less +++ b/app/assets/components/MachineDetail/index.less @@ -45,6 +45,7 @@ margin-left: 16px; } +<<<<<<< HEAD:app/assets/components/MachineDetail/index.less .filter-in-icon { margin-right: 16px; } @@ -53,6 +54,8 @@ margin-right: 5px; } +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/DashboardDetail/index.less .metric { margin-right: 30px; } @@ -60,6 +63,7 @@ .metric-info-icon { position: absolute; font-size: 16px; +<<<<<<< HEAD:app/assets/components/MachineDetail/index.less margin: 8px 10px 0 10px; } } @@ -68,6 +72,11 @@ position: absolute; top: 50px; right: 20px; +======= + margin-top: 8px; + margin-left: 10px; + } +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/DashboardDetail/index.less } } diff --git a/app/assets/components/MachineDetail/index.tsx b/app/assets/components/MachineDetail/index.tsx index 3792b7f4..9a158bd2 100644 --- a/app/assets/components/MachineDetail/index.tsx +++ b/app/assets/components/MachineDetail/index.tsx @@ -1,5 +1,5 @@ import { DETAIL_DEFAULT_RANGE, TIMEOPTIONS } from '@assets/utils/dashboard'; -import { DatePicker, Form, Radio } from 'antd'; +import { DatePicker, Form, Popover, Radio } from 'antd'; import React, { HTMLProps } from 'react'; import dayjs from 'dayjs'; @@ -44,6 +44,7 @@ class MachineDetail extends React.PureComponent { } } +<<<<<<< HEAD:app/assets/components/MachineDetail/index.tsx handleBaseLineEdit= () => { const { onBaseLineEdit } = this.props; if(onBaseLineEdit ){ @@ -55,6 +56,8 @@ class MachineDetail extends React.PureComponent { return current < dayjs().subtract(14, 'days').endOf('day') || current > dayjs().endOf('day'); } +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/DashboardDetail/index.tsx render() { const now = Date.now(); const { @@ -108,7 +111,13 @@ class MachineDetail extends React.PureComponent { metricOptions.map(option => ) } +<<<<<<< HEAD:app/assets/components/MachineDetail/index.tsx +======= + + + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/DashboardDetail/index.tsx }
diff --git a/app/assets/components/Service/ServiceCard/Card.tsx b/app/assets/components/Service/ServiceCard/Card.tsx index f3b68f5c..28c3eb18 100644 --- a/app/assets/components/Service/ServiceCard/Card.tsx +++ b/app/assets/components/Service/ServiceCard/Card.tsx @@ -5,14 +5,24 @@ import { ILineChartMetric } from '@assets/utils/interface'; interface IProps { data: ILineChartMetric[]; loading: boolean; +<<<<<<< HEAD baseLine?: number; +======= + baseLineNum?: number; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) } class Card extends React.Component { render() { +<<<<<<< HEAD const { data, baseLine, loading } = this.props; return (>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) data = {data} valueType ={VALUE_TYPE.number} loading= {loading} diff --git a/app/assets/components/Service/ServiceCardEdit/index.tsx b/app/assets/components/Service/ServiceCardEdit/index.tsx index d8c684db..410dc360 100644 --- a/app/assets/components/Service/ServiceCardEdit/index.tsx +++ b/app/assets/components/Service/ServiceCardEdit/index.tsx @@ -1,8 +1,13 @@ import React from 'react'; +<<<<<<< HEAD import { Button, Form, InputNumber } from 'antd'; +======= +import { Button, Form, Popover } from 'antd'; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) import { FormInstance } from 'antd/lib/form'; import { TIME_INTERVAL_OPTIONS } from '@assets/utils/dashboard'; import { SERVICE_SUPPORT_METRICS } from '@assets/utils/promQL'; +import Icon from '@assets/components/Icon'; import { cloneDeep } from 'lodash'; import intl from 'react-intl-universal'; import { DashboardSelect, Option } from '@assets/components/DashboardSelect'; @@ -49,8 +54,13 @@ class ServiceCardEdit extends React.Component { this.props.onClose(); } render() { +<<<<<<< HEAD const { editIndex, editType, panelConfig, onClose } = this.props; const editItem = panelConfig[editType][editIndex]; +======= + const { editIndex, editType, servicePanelConfig, onClose } = this.props; + const editItem = servicePanelConfig[editType][editIndex]; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) return (
{ } +<<<<<<< HEAD +======= + + + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) { diff --git a/app/assets/components/Service/ServiceOverview/index.less b/app/assets/components/Service/ServiceOverview/index.less new file mode 100644 index 00000000..b86d9d58 --- /dev/null +++ b/app/assets/components/Service/ServiceOverview/index.less @@ -0,0 +1,7 @@ + + +.btn-icon-with-desc { + float: right; + margin-top: 5px; +} + diff --git a/app/assets/components/StatusPanel/index.tsx b/app/assets/components/StatusPanel/index.tsx index 8ae7e0c4..14486b6d 100644 --- a/app/assets/components/StatusPanel/index.tsx +++ b/app/assets/components/StatusPanel/index.tsx @@ -55,7 +55,7 @@ class StatusPanel extends React.PureComponent { } } - asyncGetStatus = async () => { + asyncGetStatus = async() => { const { type } = this.props; const { normal, abnormal } = await this.props.getStatus({ query: NEBULA_COUNT[type], diff --git a/app/assets/config/service.ts b/app/assets/config/service.ts index 3995c11f..212d8330 100644 --- a/app/assets/config/service.ts +++ b/app/assets/config/service.ts @@ -9,7 +9,11 @@ const execPromQL = get('/api-metrics/query'); const execPromQLByRange = get('/api-metrics/query_range'); const getAppInfo = get('/api/app'); +<<<<<<< HEAD const getCustomConfig = get('/api/config/custom'); +======= +const getAliasConfig = get('/api/config/alias'); +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) const getAnnotationLineConfig = get('/api/config/annotation_line'); export default { @@ -18,6 +22,10 @@ export default { getAppInfo, execPromQL, execPromQLByRange, +<<<<<<< HEAD getCustomConfig, +======= + getAliasConfig, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) getAnnotationLineConfig }; diff --git a/app/assets/modules/LeaderDistribution/index.tsx b/app/assets/modules/LeaderDistribution/index.tsx index 0ab0f812..c0b135f9 100644 --- a/app/assets/modules/LeaderDistribution/index.tsx +++ b/app/assets/modules/LeaderDistribution/index.tsx @@ -43,7 +43,7 @@ class LeaderDistribution extends React.Component { componentDidMount() { this.getStorageInfo(); } - getStorageInfo = async () => { + getStorageInfo = async() => { const res = await this.props.asyncGetHostsInfo(); const data = res.map((item: any) => ({ name: item.Host, diff --git a/app/assets/modules/Login/index.tsx b/app/assets/modules/Login/index.tsx index de764f72..68fd5787 100644 --- a/app/assets/modules/Login/index.tsx +++ b/app/assets/modules/Login/index.tsx @@ -40,9 +40,14 @@ class ConfigServerForm extends React.Component { this.props.asyncGetCustomConfig(); } +<<<<<<< HEAD onConfig = async (values: any) => { const { connection } = this.props; const ok = await this.props.asyncLogin({ ip: connection.ip, port: connection.port, ...values }); +======= + onConfig = async(values: any) => { + const ok = await this.props.asyncLogin(values); +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) if (ok) { this.props.history.push('/machine/overview'); } diff --git a/app/assets/modules/MachineDashboard/Cards/CPUCard.tsx b/app/assets/modules/MachineDashboard/Cards/CPUCard.tsx index 1e5fd02a..f142a41d 100644 --- a/app/assets/modules/MachineDashboard/Cards/CPUCard.tsx +++ b/app/assets/modules/MachineDashboard/Cards/CPUCard.tsx @@ -7,10 +7,16 @@ import { VALUE_TYPE } from '@assets/utils/promQL'; const mapState = (state: IRootState) => { const { cpuStat } = state.machine; +<<<<<<< HEAD const { cpuBaseLine } = state.setting; const { aliasConfig } = state.app; return { baseLine:cpuBaseLine, +======= + const { aliasConfig, annotationLine } = state.app; + return { + baseLineNum: annotationLine.cpu, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) data: getDataByType({ data:cpuStat, type:'all', name: 'instance', aliasConfig }), valueType: VALUE_TYPE.percentage, loading: !!state.loading.effects.machine.asyncGetCPUStatByRange, diff --git a/app/assets/modules/MachineDashboard/Cards/LoadCard.tsx b/app/assets/modules/MachineDashboard/Cards/LoadCard.tsx index 628f4f28..60653845 100644 --- a/app/assets/modules/MachineDashboard/Cards/LoadCard.tsx +++ b/app/assets/modules/MachineDashboard/Cards/LoadCard.tsx @@ -7,10 +7,16 @@ import { VALUE_TYPE } from '@assets/utils/promQL'; const mapState = (state: IRootState) => { const { loadStat } = state.machine; +<<<<<<< HEAD const { loadBaseLine } = state.setting; const { aliasConfig } = state.app; return { baseLine: loadBaseLine, +======= + const { aliasConfig, annotationLine } = state.app; + return { + baseLineNum: annotationLine.load, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) data: getDataByType({ data:loadStat, type:'all', name: 'instance', aliasConfig }), valueType: VALUE_TYPE.number, loading: !!state.loading.effects.machine.asyncGetLoadByRange, diff --git a/app/assets/modules/MachineDashboard/Cards/MemoryCard.tsx b/app/assets/modules/MachineDashboard/Cards/MemoryCard.tsx index 779b5a35..e719351e 100644 --- a/app/assets/modules/MachineDashboard/Cards/MemoryCard.tsx +++ b/app/assets/modules/MachineDashboard/Cards/MemoryCard.tsx @@ -6,12 +6,21 @@ import { VALUE_TYPE } from '@assets/utils/promQL'; const mapState = (state: IRootState) => { const { memoryStat, memorySizeStat } = state.machine; +<<<<<<< HEAD const { memoryBaseLine } = state.setting; const { aliasConfig } = state.app; return { data: getDataByType({ data:memoryStat, type:'all', name: 'instance', aliasConfig }), sizes: memorySizeStat, baseLine: memoryBaseLine, +======= + const { aliasConfig, annotationLine } = state.app; + console.log(annotationLine.memory); + return { + data: getDataByType({ data:memoryStat, type:'all', name: 'instance', aliasConfig }), + sizes: memorySizeStat, + lineNum: annotationLine.memory, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) valueType: VALUE_TYPE.percentage, loading: !!state.loading.effects.machine.asyncGetMemorySizeStat && !!state.loading.effects.machine.asyncGetMemoryStatByRange diff --git a/app/assets/modules/MachineDashboard/Cards/NetworkIn.tsx b/app/assets/modules/MachineDashboard/Cards/NetworkIn.tsx index 5c2088b5..7d367a38 100644 --- a/app/assets/modules/MachineDashboard/Cards/NetworkIn.tsx +++ b/app/assets/modules/MachineDashboard/Cards/NetworkIn.tsx @@ -7,10 +7,16 @@ import { VALUE_TYPE } from '@assets/utils/promQL'; const mapState = (state: IRootState) => { const { networkInStat } = state.machine; +<<<<<<< HEAD const { networkInBaseLine } = state.setting; const { aliasConfig } = state.app; return { baseLine: networkInBaseLine, +======= + const { aliasConfig, annotationLine } = state.app; + return { + baseLineNum: annotationLine.network, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) data: getDataByType({ data:networkInStat, type:'all', name: 'instance', aliasConfig }), valueType: VALUE_TYPE.byteSecond, loading: !!state.loading.effects.machine.asyncGetNetworkStatByRange, diff --git a/app/assets/modules/MachineDashboard/Cards/NetworkOut.tsx b/app/assets/modules/MachineDashboard/Cards/NetworkOut.tsx index 4aa7d053..be5d9945 100644 --- a/app/assets/modules/MachineDashboard/Cards/NetworkOut.tsx +++ b/app/assets/modules/MachineDashboard/Cards/NetworkOut.tsx @@ -7,10 +7,16 @@ import { getDataByType } from '@assets/utils/dashboard'; const mapState = (state: IRootState) => { const { networkOutStat } = state.machine; +<<<<<<< HEAD const { networkOutBaseLine } = state.setting; const { aliasConfig } = state.app; return { baseLine: networkOutBaseLine, +======= + const { aliasConfig, annotationLine } = state.app; + return { + baseLineNum: annotationLine.network, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) data: getDataByType({ data:networkOutStat, type:'all', name: 'instance', aliasConfig }), valueType: VALUE_TYPE.byteSecond, loading: !!state.loading.effects.machine.asyncGetNetworkStatByRange, diff --git a/app/assets/modules/MachineDashboard/Detail/index.tsx b/app/assets/modules/MachineDashboard/Detail/index.tsx index 91195895..abf51427 100644 --- a/app/assets/modules/MachineDashboard/Detail/index.tsx +++ b/app/assets/modules/MachineDashboard/Detail/index.tsx @@ -27,11 +27,15 @@ const mapDispatch = (dispatch: IDispatch) => { const mapState = (state: IRootState) => { return { aliasConfig: state.app.aliasConfig, +<<<<<<< HEAD cpuBaseLine: state.setting.cpuBaseLine, memoryBaseLine: state.setting.memoryBaseLine, loadBaseLine: state.setting.loadBaseLine, diskBaseLine: state.setting.diskBaseLine, networkBaseLine: state.setting.networkBaseLine, +======= + annotationLine: state.app.annotationLine, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) }; }; interface IProps extends ReturnType, @@ -57,7 +61,11 @@ interface IState { class Detail extends React.Component { pollingTimer: any; chartInstance: Chart; +<<<<<<< HEAD modalHandler; +======= + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) constructor(props: IProps) { super(props); const endTimestamps = Date.now(); @@ -80,7 +88,7 @@ class Detail extends React.Component { } } - getData = async () => { + getData = async() => { const { startTimestamps, endTimestamps, currentMetricOption } = this.state; await this.props.asyncGetDataSourceByRange({ start: startTimestamps, @@ -168,8 +176,13 @@ class Detail extends React.Component { } render() { +<<<<<<< HEAD const { maxNum, startTimestamps, endTimestamps, currentInstance, currentMetricOption } = this.state; const { dataSource, metricOptions, loading, aliasConfig, type } = this.props; +======= + const { startTimestamps, endTimestamps, currentInstance, currentMetricOption } = this.state; + const { dataSource, metricOptions, loading, aliasConfig, annotationLine, type } = this.props; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) const instances = uniq(dataSource.map(instance => instance.metric.instance)); const typeOptions = [ { @@ -181,7 +194,11 @@ class Detail extends React.Component { value: instance, })) ]; +<<<<<<< HEAD const baseLine = this.props[`${type}BaseLine`]; +======= + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) return ( { handlerRef={handler => (this.modalHandler = handler)} footer={null} > +<<<<<<< HEAD { onBaseLineChange={this.handleBaseLineChange} /> +======= + + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) ); } diff --git a/app/assets/modules/MachineDashboard/index.tsx b/app/assets/modules/MachineDashboard/index.tsx index b4ffe487..9bde23ac 100644 --- a/app/assets/modules/MachineDashboard/index.tsx +++ b/app/assets/modules/MachineDashboard/index.tsx @@ -50,6 +50,7 @@ interface IState { } class MachineDashboard extends React.Component { pollingTimer: any; +<<<<<<< HEAD modalHandler; constructor(props: IProps) { super(props); @@ -57,6 +58,9 @@ class MachineDashboard extends React.Component { editPanelType: '', }; } +======= + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) componentDidMount() { this.props.asyncGetMemorySizeStat(); this.props.asyncGetDiskSizeStat(); @@ -134,6 +138,7 @@ class MachineDashboard extends React.Component { }, CARD_POLLING_INTERVAL); } +<<<<<<< HEAD getValueType=(type) => { switch (type) { case MACHINE_TYPE.cpu: @@ -151,6 +156,9 @@ class MachineDashboard extends React.Component { render() { const { editPanelType } = this.state; +======= + render() { +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) return
diff --git a/app/assets/modules/MainPage/index.tsx b/app/assets/modules/MainPage/index.tsx index d7fa57a6..177c192c 100644 --- a/app/assets/modules/MainPage/index.tsx +++ b/app/assets/modules/MainPage/index.tsx @@ -26,7 +26,12 @@ const mapDispatch = (dispatch: IDispatch) => { return { asyncLogout: dispatch.app.asyncLogout, asyncGetAppInfo: dispatch.app.asyncGetAppInfo, +<<<<<<< HEAD asyncGetCustomConfig: dispatch.app.asyncGetCustomConfig, +======= + asyncGetAliasConfig: dispatch.app.asyncGetAliasConfig, + asyncGetAnnotationLineInfo: dispatch.app.asyncGetAnnotationLineInfo, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) }; }; @@ -52,7 +57,12 @@ class MainPage extends React.Component { componentDidMount() { const { appVersion } = this.props; +<<<<<<< HEAD this.props.asyncGetCustomConfig(); +======= + this.props.asyncGetAliasConfig(); + this.props.asyncGetAnnotationLineInfo(); +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) if(appVersion === '') { this.props.asyncGetAppInfo(); } diff --git a/app/assets/modules/PartitionDistribution/index.tsx b/app/assets/modules/PartitionDistribution/index.tsx index eae38a96..d2953df2 100644 --- a/app/assets/modules/PartitionDistribution/index.tsx +++ b/app/assets/modules/PartitionDistribution/index.tsx @@ -52,7 +52,14 @@ class PartitionDistribution extends React.Component { }; } +<<<<<<< HEAD async componentDidMount() { +======= + componentDidMount() { + this.getSpaces(); + } + getSpaces = async() => { +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) await this.props.asyncGetSpaces(); const { currentSpace } = this.props; if(currentSpace){ diff --git a/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.less b/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.less index 55b023b2..30b79d88 100644 --- a/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.less +++ b/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.less @@ -34,10 +34,13 @@ >span { font-weight: bold; } +<<<<<<< HEAD:app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.less } .btn-icon-with-desc { margin-top: 0; +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/Service/CustomServiceQueryPanel/index.less } } } diff --git a/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.tsx b/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.tsx index 9c7ce824..16dbaf60 100644 --- a/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.tsx +++ b/app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.tsx @@ -4,6 +4,7 @@ import intl from 'react-intl-universal'; import { IServicePanelConfig, IStatRangeItem } from '@assets/utils/interface'; import { getDataByType } from '@assets/utils/dashboard'; import { SERVICE_DEFAULT_RANGE, SERVICE_POLLING_INTERVAL } from '@assets/utils/service'; +import { METRICS_DESCRIPTION } from '@assets/utils/metric'; import Card from '@assets/components/Service/ServiceCard/Card'; import { IDispatch, IRootState } from '@assets/store'; import { connect } from 'react-redux'; @@ -28,7 +29,11 @@ interface IProps extends ReturnType, ReturnType { onConfigPanel: () => void; config: IServicePanelConfig; +<<<<<<< HEAD:app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.tsx aliasConfig: any; +======= + baseLineNum?: number; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/Service/CustomServiceQueryPanel/index.tsx } interface IState { @@ -66,7 +71,7 @@ class CustomServiceQueryPanel extends React.Component { this.pollingData(); } - getMetricsData = async () => { + getMetricsData = async() => { const { config } = this.props; const { period: metricPeriod, metricFunction } = config; const end = Date.now(); @@ -85,12 +90,22 @@ class CustomServiceQueryPanel extends React.Component { this.pollingTimer = setTimeout(this.pollingData, SERVICE_POLLING_INTERVAL); } +<<<<<<< HEAD:app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.tsx render() { const { data } = this.state; const { config: { metric, period, metricType, baseLine }, aliasConfig } = this.props; return
{metric} +======= + + render() { + const { data } = this.state; + const { config: { metric, period, metricType }, aliasConfig, baseLineNum } = this.props; + return
+
+

{metric}

+>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/Service/CustomServiceQueryPanel/index.tsx
{intl.get('service.period')}: {period} {intl.get('service.metricParams')}: {metricType} @@ -101,7 +116,11 @@ class CustomServiceQueryPanel extends React.Component {
+<<<<<<< HEAD:app/assets/modules/ServiceDashboard/ServiceOverview/CustomServiceQueryPanel/index.tsx {data.length > 0 && } +======= + {data.length > 0 && } +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/Service/CustomServiceQueryPanel/index.tsx
; } diff --git a/app/assets/modules/ServiceDashboard/ServiceOverview/index.tsx b/app/assets/modules/ServiceDashboard/ServiceOverview/index.tsx index 188adc38..98480834 100644 --- a/app/assets/modules/ServiceDashboard/ServiceOverview/index.tsx +++ b/app/assets/modules/ServiceDashboard/ServiceOverview/index.tsx @@ -8,13 +8,17 @@ import { RouteComponentProps, withRouter } from 'react-router-dom'; import { trackPageView } from '@assets/utils/stat'; import intl from 'react-intl-universal'; import _ from 'lodash'; +<<<<<<< HEAD:app/assets/modules/ServiceDashboard/ServiceOverview/index.tsx import CustomServiceQueryPanel from './CustomServiceQueryPanel'; +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/Service/ServiceOverview/index.tsx import './index.less'; interface IProps extends RouteComponentProps { serviceType: string; icon: string; configs: IServicePanelConfig[], + baseLineNum?:number, onConfigPanel: (serviceType: string, index: number)=>void; getStatus: (payload)=> void; } @@ -31,7 +35,11 @@ class ServiceOverview extends React.PureComponent { serviceType, icon, configs, +<<<<<<< HEAD:app/assets/modules/ServiceDashboard/ServiceOverview/index.tsx getStatus, +======= + baseLineNum +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)):app/assets/components/Service/ServiceOverview/index.tsx } = this.props; return (
@@ -49,6 +57,7 @@ class ServiceOverview extends React.PureComponent { {configs.map((config, index) => this.props.onConfigPanel(serviceType, index)} /> )} diff --git a/app/assets/modules/ServiceDashboard/index.tsx b/app/assets/modules/ServiceDashboard/index.tsx index 2fcafec0..bb19cfe6 100644 --- a/app/assets/modules/ServiceDashboard/index.tsx +++ b/app/assets/modules/ServiceDashboard/index.tsx @@ -19,8 +19,13 @@ const mapDispatch = (dispatch: IDispatch) => { const mapState = (state: IRootState) => { return { +<<<<<<< HEAD panelConfig: state.service.panelConfig, aliasConfig: state.app.aliasConfig, +======= + servicePanelConfig: state.service.servicePanelConfig, + annotationLine: state.app.annotationLine, +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) }; }; @@ -60,13 +65,19 @@ class ServiceDashboard extends React.Component { render() { const { editPanelType, editPanelIndex } = this.state; const { +<<<<<<< HEAD panelConfig, updatePanelConfig, asyncGetStatus, +======= + servicePanelConfig, + annotationLine +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) } = this.props; // TODO: Use hooks to resolve situations where render is jamming return (
+<<<<<<< HEAD {METRIC_SERVICE_TYPES.map(type => { getStatus={asyncGetStatus} onConfigPanel={this.handleConfigPanel} />)} +======= + + + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) { } render() { +<<<<<<< HEAD const { configs, loading } = this.props; const columns = [ +======= + const { configs, loading }=this.props; + const columns =[ +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) { title: , dataIndex: 'module', diff --git a/app/assets/modules/ServiceManage/PartitionInfo/index.tsx b/app/assets/modules/ServiceManage/PartitionInfo/index.tsx index 93966da8..df814da2 100644 --- a/app/assets/modules/ServiceManage/PartitionInfo/index.tsx +++ b/app/assets/modules/ServiceManage/PartitionInfo/index.tsx @@ -32,7 +32,11 @@ interface IProps extends ReturnType, class PartitionInfo extends React.Component { +<<<<<<< HEAD componentDidMount() { +======= + componentDidMount(){ +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) this.props.asyncGetSpaces(); } diff --git a/app/assets/modules/ServiceManage/Snapshot/index.tsx b/app/assets/modules/ServiceManage/Snapshot/index.tsx new file mode 100644 index 00000000..363ccccb --- /dev/null +++ b/app/assets/modules/ServiceManage/Snapshot/index.tsx @@ -0,0 +1,61 @@ +import _ from 'lodash'; +import React from 'react'; +import { Table } from 'antd'; +import { IDispatch, IRootState } from '@assets/store'; +import { connect } from 'react-redux'; +import intl from 'react-intl-universal'; +import { TitleInstruction } from '@assets/components/Instruction'; + +import './index.less'; + +const mapState = (state: IRootState) => ({ + loading: state.loading.effects.nebula.asyncGetSnapshots, + snapshots: state.nebula.snapshots, +}); + +const mapDispatch = (dispatch: IDispatch) => ({ + asyncGetSnapshots: dispatch.nebula.asyncGetSnapshots, +}); +interface IProps extends ReturnType, + ReturnType{ +} + +class Snapshot extends React.Component { + + componentDidMount(){ + this.props.asyncGetSnapshots(); + } + + render() { + const { snapshots, loading } = this.props; + const columns =[ + { + title: , + dataIndex: 'Name', + width:'30%', + }, + { + title: , + dataIndex: 'Status', + width:'30%', + render: status => {status}, + }, + { + title: , + dataIndex: 'Hosts', + }, + ]; + return ( +
+ record.Name} + dataSource={snapshots} + columns={columns} + /> + + ); + } +} + +export default connect(mapState, mapDispatch)(Snapshot); diff --git a/app/assets/modules/ServiceMetrics/index.tsx b/app/assets/modules/ServiceMetrics/index.tsx new file mode 100644 index 00000000..3ff66905 --- /dev/null +++ b/app/assets/modules/ServiceMetrics/index.tsx @@ -0,0 +1,315 @@ +import { DatePicker, Form, Popover, Radio, Row, Spin } from 'antd'; +import { CARD_POLLING_INTERVAL, DETAIL_DEFAULT_RANGE, NEED_ADD_SUM_QUERYS, TIMEOPTIONS, TIME_INTERVAL_OPTIONS, getDataByType, getProperTickInterval } from '@assets/utils/dashboard'; +import { FormInstance } from 'antd/lib/form'; +import { updateQueryStringParameter } from '@assets/utils/url'; +import React from 'react'; +import intl from 'react-intl-universal'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; +import { IDispatch, IRootState } from '@assets/store'; +import { connect } from 'react-redux'; +import { SERVICE_SUPPORT_METRICS, VALUE_TYPE } from '@assets/utils/promQL'; +import { SERVICE_QUERY_PERIOD } from '@assets/utils/service'; +import { Chart } from '@antv/g2'; +import StatusPanel from '@assets/components/StatusPanel'; +import { IStatRangeItem } from '@assets/utils/interface'; +import { DashboardSelect, Option } from '@assets/components/DashboardSelect'; +import dayjs from 'dayjs'; +import ServiceHeader from '@assets/components/Service/ServiceHeader'; + +import LineChart from '@assets/components/Charts/LineChart'; +import { configDetailChart, updateDetailChart } from '@assets/utils/chart/chart'; +import Icon from '@assets/components/Icon'; + +import './index.less'; + +interface IState { + serviceType: string, + metricsValueType: VALUE_TYPE; + defaultFormParams: { + interval: number, + instance: string, + metric: string, + metricFunction: string, + period: number, + timeRange: dayjs.Dayjs[] + }, + instanceList: string[], + data: IStatRangeItem[], + totalData: IStatRangeItem[], +} + +const mapDispatch = (dispatch: IDispatch) => { + return { + asyncGetMetricsData: dispatch.service.asyncGetMetricsData, + asyncGetMetricsSumData: dispatch.service.asyncGetMetricsSumData, + }; +}; + +const mapState = (state: IRootState) => { + return { + loading: state.loading.models.service, + aliasConfig: state.app.aliasConfig, + annotationLine: state.app.annotationLine, + }; +}; + +interface IProps extends ReturnType, + ReturnType, RouteComponentProps {} + +class ServiceMetrics extends React.Component { + chartInstance: Chart; + pollingTimer: any; + formRef = React.createRef(); + constructor(props: IProps) { + super(props); + this.state = { + serviceType: 'graph', + defaultFormParams: { + interval: DETAIL_DEFAULT_RANGE, + instance: 'all', + metric: SERVICE_SUPPORT_METRICS.graph[0].metric, + metricFunction: SERVICE_SUPPORT_METRICS.graph[0].metricType[0].value, + period: SERVICE_QUERY_PERIOD, + timeRange: this.getDefaultTimeRange() + }, + metricsValueType: SERVICE_SUPPORT_METRICS.graph[0].valueType, + data: [], + totalData: [], + instanceList: [] + }; + } + componentDidMount() { + this.initialConfig(); + } + + getDefaultTimeRange = (interval?: number) => { + const end = Date.now(); + const start = interval ? end - interval : end - DETAIL_DEFAULT_RANGE; + return [dayjs(start), dayjs(end)]; + } + initialConfig = () => { + const { location: { pathname } } = this.props; + const regx = /(\w+)-metrics/g; + const match = regx.exec(pathname); + let serviceType = ''; + if(match){ + serviceType = match[1]; + } + if(serviceType) { + const metricsList = SERVICE_SUPPORT_METRICS[serviceType]; + const timeRange = this.getDefaultTimeRange(); + const defaultFormParams = { + interval: DETAIL_DEFAULT_RANGE, + instance: 'all', + metric: metricsList[0].metric, + metricFunction: metricsList[0].metricType[0].value, + period: SERVICE_QUERY_PERIOD, + timeRange + }; + if(this.formRef.current!) { + this.formRef.current!.setFieldsValue(defaultFormParams); + } + this.setState({ + serviceType, + defaultFormParams, + metricsValueType: metricsList[0].valueType, + }, this.pollingData); + } + } + componentDidUpdate(prevProps) { + if(prevProps.location.pathname !== this.props.location.pathname) { + this.initialConfig(); + } + } + componentWillUnmount() { + this.clearPolling(); + } + + pollingData = async() => { + await this.asyncGetMetricsData(); + this.pollingTimer = setTimeout(this.pollingData, CARD_POLLING_INTERVAL); + } + + clearPolling = () => { + if (this.pollingTimer) { + clearTimeout(this.pollingTimer); + } + } + resetPollingData = () => { + this.clearPolling(); + this.pollingData(); + } + + handleServiceTypeChange = value => { + window.location.href = updateQueryStringParameter( + window.location.href, + 'type', + value + ); + } + + asyncGetMetricsData = async() => { + const { timeRange, metric, metricFunction, period } = this.formRef.current!.getFieldsValue(); + const [startTime, endTime] = timeRange; + let data = await this.props.asyncGetMetricsData({ + query: metricFunction+period, + metric, + start: startTime, + end: endTime, + timeInterval: period + }); + if(NEED_ADD_SUM_QUERYS.includes(metric)){ + const totalData = await this.props.asyncGetMetricsSumData({ + query: metricFunction+period, + metric, + start: startTime, + end: endTime, + timeInterval: period + }); + data = data.concat(totalData); + } + const instanceList = data.map(item => item.metric.instanceName); + this.setState({ + data, + instanceList + }); + this.updateChart(); + } + + updateChart = () => { + const { serviceType, data } = this.state; + const { aliasConfig } = this.props; + const { timeRange, instance } = this.formRef.current!.getFieldsValue(); + const [startTime, endTime] = timeRange; + const _data = getDataByType({ data, type: instance, name: 'instanceName', aliasConfig }); + updateDetailChart(this.chartInstance, { + type: serviceType, + tickInterval: getProperTickInterval(endTime - startTime), + }).changeData(_data); + } + + renderChart = (chartInstance: Chart) => { + const { metricsValueType } = this.state; + const { timeRange } = this.formRef.current!.getFieldsValue(); + const [startTime, endTime] = timeRange; + this.chartInstance = chartInstance; + configDetailChart(chartInstance, { + tickInterval: getProperTickInterval(endTime - startTime), + valueType: metricsValueType + }); + } + + handleUpdateMetricType = (value: string) => { + const { serviceType } = this.state; + const selectedMetrics = SERVICE_SUPPORT_METRICS[serviceType].filter(item => item.metric === value)[0]; + this.formRef.current!.setFieldsValue({ + metricFunction: selectedMetrics.metricType[0].value + }); + this.setState({ metricsValueType: selectedMetrics.valueType }); + } + + handleConfigUpdate = (changedValues) => { + if(changedValues.interval) { + const timeRange = this.getDefaultTimeRange(changedValues.interval); + this.formRef.current!.setFieldsValue({ timeRange }); + } else if (changedValues.timeRange) { + this.formRef.current!.setFieldsValue({ interval: null }); + } else if (changedValues.metric) { + this.handleUpdateMetricType(changedValues.metric); + } + this.resetPollingData(); + } + render() { + const { serviceType, defaultFormParams, instanceList } = this.state; + const { loading, aliasConfig, annotationLine } = this.props; + return (
+ +
+ + +
+ + + { + TIMEOPTIONS.map(option => ( + {intl.get(`component.dashboardDetail.${option.name}`)} + )) + } + + + + + +
+ + + +
+ + + + + { + instanceList.map(value => ( + + )) + } + + + + + { + SERVICE_SUPPORT_METRICS[serviceType].map(metric => ( + + )) + } + + + + + + prevValues.metric !== currentValues.metric} + > + {({ getFieldValue }) => { + const metric = getFieldValue('metric'); + const typeList = SERVICE_SUPPORT_METRICS[serviceType].filter(item => item.metric === metric)[0].metricType; + return getFieldValue('metric') ? + + { + typeList.map(params => ( + + )) + } + + : null;} + } + + + + { + TIME_INTERVAL_OPTIONS.map(value => ( + + )) + } + + + + + + + +
+
); + } +} +export default connect(mapState, mapDispatch)(withRouter(ServiceMetrics)); \ No newline at end of file diff --git a/app/assets/modules/VersionStatistic/index.tsx b/app/assets/modules/VersionStatistic/index.tsx index 6eabe83a..8019bbac 100644 --- a/app/assets/modules/VersionStatistic/index.tsx +++ b/app/assets/modules/VersionStatistic/index.tsx @@ -36,7 +36,7 @@ class VersionStatistic extends React.Component { this.getVersion(); } - getVersion = async () => { + getVersion = async() => { const graph = await this.props.asyncGetServiceVersion('GRAPH'); const storage = await this.props.asyncGetServiceVersion('STORAGE'); const meta = await this.props.asyncGetServiceVersion('META'); diff --git a/app/assets/store/models/app.ts b/app/assets/store/models/app.ts index 91143edc..d5de7c6d 100644 --- a/app/assets/store/models/app.ts +++ b/app/assets/store/models/app.ts @@ -8,14 +8,21 @@ interface IState { version: string; username: string; aliasConfig: any; + annotationLine: any; } export const app = createModel({ state: { version: '', username: cookies.get('nu'), +<<<<<<< HEAD aliasConfig: {} as any, connection: {} as any, +======= + password: cookies.get('np'), + aliasConfig: {}, + annotationLine: {} as any +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) }, reducers: { update: (state: IState, payload: any) => { @@ -34,8 +41,22 @@ export const app = createModel({ }); }, +<<<<<<< HEAD async asyncGetCustomConfig() { const { code, data:{ connection, alias } } = (await service.getCustomConfig()) as any; +======= + async asyncGetAnnotationLineInfo() { + const { code, data } = await service.getAnnotationLineConfig() as any; + if(code === 0){ + this.update({ + annotationLine:data, + }); + } + }, + + async asyncGetAliasConfig() { + const { code, data } = (await service.getAliasConfig()) as any; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) if (code === 0) { this.update({ aliasConfig : alias, @@ -44,11 +65,17 @@ export const app = createModel({ } }, +<<<<<<< HEAD async asyncLogin(payload: { password:string, username: string, ip: string, port: number, +======= + async asyncLogin({ + username, + password +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) }){ const { password, username, ip, port } = payload; const { code, message: errorMessage } = (await service.connectDB( diff --git a/app/assets/store/models/machine.ts b/app/assets/store/models/machine.ts index 30d9e5d9..0ac0a42c 100644 --- a/app/assets/store/models/machine.ts +++ b/app/assets/store/models/machine.ts @@ -154,6 +154,7 @@ export const machine = createModel({ }else{ diskStat = data.result; } +<<<<<<< HEAD diskStat = diskStat.map((stat:any) => { if(stat.metric.device){ return{ @@ -167,6 +168,8 @@ export const machine = createModel({ return stat; } }); +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) } this.update({ @@ -287,12 +290,20 @@ export const machine = createModel({ end, step, })) as any; +<<<<<<< HEAD if(code === 0 && dataStat.result.length !== 0){ +======= + if(code ===0){ +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) const sumData = { metric:{ instance: 'total', job: 'total' +<<<<<<< HEAD }, +======= + } +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) } as any; sumData.values = dataStat.result[0].values; return data.concat(sumData); diff --git a/app/assets/store/models/nebula.ts b/app/assets/store/models/nebula.ts index 269a4342..23df28b4 100644 --- a/app/assets/store/models/nebula.ts +++ b/app/assets/store/models/nebula.ts @@ -42,6 +42,20 @@ export const nebula = createModel({ } }, +<<<<<<< HEAD +======= + async asyncGetSnapshots() { + const { code, data } = (await service.execNGQL({ + gql: 'SHOW SNAPSHOTS' + })) as any; + if (code === 0) { + this.update({ + snapshots: data.tables ? data.tables : [], + }); + } + }, + +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) async asyncGetJobs() { const { code, data } = (await service.execNGQL({ gql: 'SHOW JOBS' diff --git a/app/assets/store/models/service.ts b/app/assets/store/models/service.ts index 44441f52..3ff579b5 100644 --- a/app/assets/store/models/service.ts +++ b/app/assets/store/models/service.ts @@ -28,6 +28,42 @@ export const service = createModel({ }, effects: () => ({ async asyncGetMetricsSumData(payload: { +<<<<<<< HEAD +======= + query:string, + metric: string, + start: number, + end: number, + timeInterval: number, + }) { + const { start, end, query, metric, timeInterval } = payload; + const step = getProperStep(start, end); + const _start = start / 1000; + const _end = end / 1000; + const { code, data } = (await serviceApi.execPromQLByRange({ + query:`sum(${query})`, + start: _start, + end: _end, + step, + })) as any; + const sumData = { + metric:{ + instanceName: 'total', + instance: 'total', + } + } as any; + if (code === 0) { + if(metric === SERVICE_SUPPORT_METRICS.graph[0].metric || metric===SERVICE_SUPPORT_METRICS.graph[1].metric){ + sumData.values = getQPSData(data, timeInterval)[0].values; + }else{ + sumData.values = data.result[0].values; + } + } + return sumData; + }, + + async asyncGetMetricsData(payload: { +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) query:string, start: number, end: number, diff --git a/app/assets/utils/dashboard.ts b/app/assets/utils/dashboard.ts index 7b45abd7..27ad7b46 100644 --- a/app/assets/utils/dashboard.ts +++ b/app/assets/utils/dashboard.ts @@ -198,6 +198,7 @@ export const NEED_ADD_SUM_QUERYS = [ // For Nebula Graph Service 'num_queries', 'num_slow_queries' +<<<<<<< HEAD ]; export enum MACHINE_TYPE { @@ -248,4 +249,7 @@ export const getMaxNumAndLength = (payload:{ break; } return { maxNum, maxNumLen }; -}; \ No newline at end of file +}; +======= +]; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) diff --git a/app/assets/utils/metric.ts b/app/assets/utils/metric.ts index 698791e5..073e5fa6 100644 --- a/app/assets/utils/metric.ts +++ b/app/assets/utils/metric.ts @@ -13,6 +13,10 @@ export const METRICS_DESCRIPTION = { get_neighbors_latency_us: 'get_neighbors_latency_us description', heartbeat_latency_us: 'heartbeat_latency_us description', num_heartbeats: 'num_heartbeats description', +<<<<<<< HEAD }; -export const METRIC_SERVICE_TYPES = ['graph', 'storage', 'meta']; \ No newline at end of file +export const METRIC_SERVICE_TYPES = ['graph', 'storage', 'meta']; +======= +}; +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) diff --git a/app/controller/home.ts b/app/controller/home.ts index 43572505..0c4387cc 100644 --- a/app/controller/home.ts +++ b/app/controller/home.ts @@ -22,7 +22,11 @@ export default class HomeController extends Controller { }; } +<<<<<<< HEAD async getCustomizeConfig() { +======= + async getAliasConfig() { +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) const { ctx } = this; const data = await fs.readFileSync(path.join(__dirname, '../../static/custom.json'), 'utf8'); if(data) { @@ -53,4 +57,20 @@ export default class HomeController extends Controller { }; } } + + async getAnnotationLineConfig() { + const { ctx } = this; + const data = await fs.readFileSync(path.join(__dirname, '../../static/annotationLine.json'), 'utf8'); + if(data) { + ctx.response.body = { + code: 0, + data: JSON.parse(data) + }; + } else { + ctx.response.body = { + code: -1, + data: null + }; + } + } } diff --git a/app/middleware/proxy.ts b/app/middleware/proxy.ts index 443d807a..438ccfb8 100644 --- a/app/middleware/proxy.ts +++ b/app/middleware/proxy.ts @@ -10,6 +10,10 @@ export default () => { if (metricsProxyPath.test(ctx.request.url)) { const importProxy = k2c( createProxyMiddleware({ +<<<<<<< HEAD +======= + // target: 'http://localhost:8090', +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) target: `http://${(ctx.request.header.host as string).split(':')[0]}:9090`, pathRewrite: { '/api-metrics': '/api/v1', diff --git a/app/router.ts b/app/router.ts index d5a4cd93..b42825c7 100644 --- a/app/router.ts +++ b/app/router.ts @@ -3,7 +3,11 @@ import { Application } from 'egg'; export default (app: Application) => { const { controller, router } = app; router.get('/api/app', controller.home.getAppInfo); +<<<<<<< HEAD router.get('/api/config/custom', controller.home.getCustomizeConfig); +======= + router.get('/api/config/alias', controller.home.getAliasConfig); +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) router.get('/api/config/annotation_line', controller.home.getAnnotationLineConfig); router.get(/^(?!^\/api\/)/, controller.home.index); }; diff --git a/scripts/package.sh b/scripts/package.sh index ad7b162d..cb1105d9 100644 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -19,7 +19,10 @@ mv $DASHBOARD/vendors/gateway.conf $TARGET_GATEWAY/conf/app.conf mv $GATEWAY/nebula-httpd $TARGET_GATEWAY/ ### nebula-stat-exporter build ### +<<<<<<< HEAD chmod 755 $DASHBOARD/vendors/nebula-stats-exporter/nebula-stats-exporter +======= +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) mv $DASHBOARD/vendors/nebula-stats-exporter/ $TARGET/ ### node-exporter @@ -28,11 +31,16 @@ mv $DASHBOARD/vendors/node-exporter/ $TARGET/ # prometheus mv $DASHBOARD/vendors/prometheus/ $TARGET/ +<<<<<<< HEAD ### Nebula Graph Dashboard relative ### cd $DASHBOARD VERSION=`cat package.json | grep '"version":' | awk 'NR==1{print $2}' | awk -F'"' '{print $2}'` bash ./scripts/setEventTracking.sh $1 +======= +### nebula dashboard relative ### +cd $DASHBOARD +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) npm install --unsafe-perm npm run build npm run tsc @@ -49,4 +57,8 @@ cp $DASHBOARD/app/assets/index.html ./app/assets/ ### tar cd $DIR -tar -czf nebula-graph-dashboard-$VERSION.x86_64.tar.gz nebula-graph-dashboard \ No newline at end of file +<<<<<<< HEAD +tar -czf nebula-graph-dashboard-$VERSION.x86_64.tar.gz nebula-graph-dashboard +======= +tar -czf nebula-graph-dashboard-beta.tar.gz nebula-graph-dashboard +>>>>>>> 8b2e53a (mod: fix issue & chore nebula-stats-exporter (#55)) diff --git a/scripts/postinst.sh b/scripts/postinst.sh new file mode 100644 index 00000000..496ef963 --- /dev/null +++ b/scripts/postinst.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# will exec when dashboard rpm installed +cd /usr/local/nebula-dashboard/ +chmod 755 ./vendors/nebula-http-gateway/nebula-http-gateway +chmod 777 ./tmp/ +chmod 777 ./static/customize.json +chmod 777 ./static/annotationLine.json +tar -xzvf node_modules.tar.gz diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100644 index 00000000..06206bb6 --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd /usr/local/nebula-dashboard/ +nohup ./vendors/nebula-http-gateway/nebula-httpd & +nohup ./vendors/prometheus/prometheus --storage.tsdb.path=/prometheus --web.console.libraries=/usr/share/prometheus/console_libraries --web.console.templates=/usr/share/prometheus/consoles --config.file=./vendors/prometheus/prometheus.yml & +nohup ./vendors/nebula-stats-exporter/nebula-stats-exporter --bare-metal --bare-metal-config=./vendors/nebula-stats-exporter/config.yaml & +npm run start diff --git a/scripts/stop.sh b/scripts/stop.sh new file mode 100644 index 00000000..0f6202bd --- /dev/null +++ b/scripts/stop.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# stop nebula-http-gateway +kill -9 $(lsof -t -i :8090) + +# stop nebula-dashboard +kill -9 $(lsof -t -i :7003) + +# stop nebula-stats-exporter +kill -9 $(lsof -t -i :9100) + +# stop node-exporter +kill -9 $(lsof -t -i :9200) + +# stop prometheus +kill -9 $(lsof -t -i :9090) +