Skip to content

Commit

Permalink
hide diagnose and rename system report back to cluster diagnostic (#1138
Browse files Browse the repository at this point in the history
)

* add metrics relationship graph back

* hide diagnose app

* disable form is conprof is disabled

* revert i18n for system report app
  • Loading branch information
baurine authored Jan 12, 2022
1 parent 28d36cd commit ac4ddec
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 21 deletions.
113 changes: 113 additions & 0 deletions pkg/apiserver/diagnose/diagnose.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ package diagnose

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"sync"
"time"

"github.com/gin-gonic/gin"
"github.com/goccy/go-graphviz"
"github.com/pingcap/log"
"go.uber.org/zap"

Expand All @@ -24,6 +31,8 @@ const (
timeLayout = "2006-01-02 15:04:05"
)

var graphvizMutex sync.Mutex

type Service struct {
// FIXME: Use fx.In
config *config.Config
Expand Down Expand Up @@ -61,12 +70,116 @@ func RegisterRouter(r *gin.RouterGroup, auth *user.AuthService, s *Service) {
auth.MWAuthRequired(),
s.reportStatusHandler)

endpoint.POST("/metrics_relation/generate", auth.MWAuthRequired(), s.metricsRelationHandler)
endpoint.GET("/metrics_relation/view", s.metricsRelationViewHandler)

endpoint.POST("/diagnosis",
auth.MWAuthRequired(),
utils.MWConnectTiDB((s.tidbClient)),
s.genDiagnosisHandler)
}

func (s *Service) generateMetricsRelation(startTime, endTime time.Time, graphType string) (string, error) {
params := url.Values{}
params.Add("start", startTime.Format(time.RFC3339))
params.Add("end", endTime.Format(time.RFC3339))
params.Add("type", graphType)
encodedParams := params.Encode()

data, err := s.tidbClient.SendGetRequest("/metrics/profile?" + encodedParams)
if err != nil {
return "", err
}

file, err := ioutil.TempFile("", "metrics*.svg")
if err != nil {
return "", fmt.Errorf("failed to create temp file: %v", err)
}
_ = file.Close()

g := graphviz.New()
// FIXME: should share a global mutex for profiling.
graphvizMutex.Lock()
defer graphvizMutex.Unlock()
graph, err := graphviz.ParseBytes(data)
if err != nil {
_ = os.Remove(file.Name())
return "", fmt.Errorf("failed to parse DOT file: %v", err)
}

if err := g.RenderFilename(graph, graphviz.SVG, file.Name()); err != nil {
_ = os.Remove(file.Name())
return "", fmt.Errorf("failed to render SVG: %v", err)
}

return file.Name(), nil
}

type GenerateMetricsRelationRequest struct {
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
Type string `json:"type"`
}

// @Id diagnoseGenerateMetricsRelationship
// @Summary Generate metrics relationship graph.
// @Param request body GenerateMetricsRelationRequest true "Request body"
// @Router /diagnose/metrics_relation/generate [post]
// @Success 200 {string} string
// @Security JwtAuth
// @Failure 401 {object} rest.ErrorResponse
func (s *Service) metricsRelationHandler(c *gin.Context) {
var req GenerateMetricsRelationRequest
if err := c.ShouldBindJSON(&req); err != nil {
_ = c.Error(rest.ErrBadRequest.NewWithNoMessage())
return
}

startTime := time.Unix(req.StartTime, 0)
endTime := time.Unix(req.EndTime, 0)

path, err := s.generateMetricsRelation(startTime, endTime, req.Type)
if err != nil {
_ = c.Error(err)
return
}

token, err := utils.NewJWTString("diagnose/metrics", path)
if err != nil {
_ = c.Error(err)
return
}

c.JSON(http.StatusOK, token)
}

// @Summary View metrics relationship graph.
// @Produce image/svg
// @Param token query string true "token"
// @Failure 400 {object} rest.ErrorResponse
// @Failure 401 {object} rest.ErrorResponse
// @Failure 500 {object} rest.ErrorResponse
// @Router /diagnose/metrics_relation/view [get]
func (s *Service) metricsRelationViewHandler(c *gin.Context) {
token := c.Query("token")
path, err := utils.ParseJWTString("diagnose/metrics", token)
if err != nil {
_ = c.Error(rest.ErrBadRequest.NewWithNoMessage())
return
}

data, err := ioutil.ReadFile(filepath.Clean(path))
if err != nil {
_ = c.Error(err)
return
}

// Do not remove it? Otherwise the link will just expire..
// _ = os.Remove(path)

c.Data(http.StatusOK, "image/svg+xml", data)
}

type GenerateReportRequest struct {
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
Expand Down
3 changes: 2 additions & 1 deletion ui/dashboardApp/layout/main/Sider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ function Sider({
useAppMenuItem(registry, 'slow_query'),
useAppMenuItem(registry, 'keyviz'),
useAppMenuItem(registry, 'system_report'),
useAppMenuItem(registry, 'diagnose'),
// warning: "diagnose" app doesn't release yet
// useAppMenuItem(registry, 'diagnose'),
useAppMenuItem(registry, 'search_logs'),
// useAppMenuItem(registry, '__APP_NAME__'),
// NOTE: Don't remove above comment line, it is a placeholder for code generator
Expand Down
9 changes: 7 additions & 2 deletions ui/lib/apps/ContinuousProfiling/pages/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,18 @@ export default function Page() {
name="rangeEndTime"
label={t('conprof.list.toolbar.range_end')}
>
<DatePicker showTime />
<DatePicker showTime disabled={conprofIsDisabled} />
</Form.Item>
<Form.Item label={t('conprof.list.toolbar.range_duration')}>
<span>-2h</span>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" loading={listLoading}>
<Button
type="primary"
htmlType="submit"
loading={listLoading}
disabled={conprofIsDisabled}
>
{t('conprof.list.toolbar.query')}
</Button>
</Form.Item>
Expand Down
66 changes: 62 additions & 4 deletions ui/lib/apps/SystemReport/pages/ReportGenerator.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Button, Form, Input, InputNumber, Select, Switch } from 'antd'
import { Button, Form, Input, InputNumber, Select, Switch, Modal } from 'antd'
import { ScrollablePane } from 'office-ui-fabric-react/lib/ScrollablePane'
import React from 'react'
import React, { useState, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import { getValueFormat } from '@baurine/grafana-value-formats'

import client from '@lib/client'
import { Card } from '@lib/components'
import { DatePicker } from '@lib/components'
import { Card, Pre, DatePicker } from '@lib/components'

import ReportHistory from '../components/ReportHistory'

Expand Down Expand Up @@ -44,10 +43,61 @@ export default function ReportGenerator() {
const navigate = useNavigate()
const handleFinish = useFinishHandler(navigate)

const [form] = Form.useForm()
const [isGenerateRelationPosting, setGenerateRelationPosting] =
useState(false)

const handleMetricsRelation = useCallback(async () => {
try {
await form.validateFields()
} catch (e) {
return
}

const fieldsValue = form.getFieldsValue()

const start_time = fieldsValue['rangeBegin'].unix()
let range_duration = fieldsValue['rangeDuration']
if (fieldsValue['rangeDuration'] === 0) {
range_duration = fieldsValue['rangeDurationCustom']
}
const end_time = start_time + range_duration * 60

try {
setGenerateRelationPosting(true)

const resp = await client
.getInstance()
.diagnoseGenerateMetricsRelationship({
start_time,
end_time,
type: 'sum',
})
Modal.success({
title: t('system_report.metrics_relation.success.title'),
okText: t('system_report.metrics_relation.success.button'),
okButtonProps: {
target: '_blank',
href:
`${client.getBasePath()}/diagnose/metrics_relation/view?token=` +
encodeURIComponent(resp.data),
},
})
} catch (e: any) {
Modal.error({
title: 'Error',
content: <Pre>{e?.response?.data?.message ?? e.message}</Pre>,
})
}

setGenerateRelationPosting(false)
}, [t, form])

return (
<div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<Card title={t('system_report.generate.title')}>
<Form
form={form}
layout="inline"
onFinish={handleFinish}
initialValues={{ rangeDuration: 10, rangeDurationCustom: 10 }}
Expand Down Expand Up @@ -138,6 +188,14 @@ export default function ReportGenerator() {
{t('system_report.generate.submit')}
</Button>
</Form.Item>
<Form.Item>
<Button
onClick={handleMetricsRelation}
loading={isGenerateRelationPosting}
>
{t('system_report.generate.metrics_relation')}
</Button>
</Form.Item>
</Form>
</Card>

Expand Down
17 changes: 11 additions & 6 deletions ui/lib/apps/SystemReport/translations/en.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
system_report:
nav_title: System Report
nav_title: Cluster Diagnostics
generate:
title: New System Report
title: New Diagnostic Report
range_begin: Range Start Time
range_duration: Range Duration
is_compare: Compare by Baseline
compare_range_begin: Baseline Range Start Time
submit: Start
metrics_relation: Generate Metrics Relation
list_table:
id: Report ID
report_create_time: Report At
report_create_time: Diagnose At
status: Status
status_running: Running
status_finish: Finish
range: Range
compare_range: Baseline Range
status:
head:
title: Report Status
back: New System Report
view: View Full System Report
title: Diagnostic Status
back: New Diagnostic Report
view: View Full Report
range_begin: Range Start Time
range_end: Range End Time
baseline_begin: Baseline Range Start Time
progress: Progress
time_duration:
custom: Custom
metrics_relation:
success:
title: Generate metrics relation graph successfully
button: View Graph
19 changes: 12 additions & 7 deletions ui/lib/apps/SystemReport/translations/zh.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
system_report:
nav_title: 系统报告
nav_title: 集群诊断
generate:
title: 生成系统报告
title: 生成诊断报告
range_begin: 区间起始时间
range_duration: 区间长度
is_compare: 与基线区间对比
compare_range_begin: 基线区间起始时间
submit: 开始
metrics_relation: 生成监控关系图
list_table:
id: 报告 ID
report_create_time: 报告时间
report_create_time: 诊断时间
status: 状态
status_running: 诊断中
status_finish: 完成
range: 报告区间
range: 诊断区间
compare_range: 对比区间
status:
head:
title: 报告状态
back: 生成系统报告
view: 查看完整系统报告
title: 诊断状态
back: 生成诊断报告
view: 查看完整诊断报告
range_begin: 区间起始时间
range_end: 区间结束时间
baseline_begin: 基线区间起始时间
progress: 生成进度
time_duration:
custom: 自定义
metrics_relation:
success:
title: 监控耗时关系图生成成功
button: 查看关系图
2 changes: 1 addition & 1 deletion ui/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12129,7 +12129,7 @@ json-stable-stringify@~0.0.0:
dependencies:
jsonify "~0.0.0"

json-stringify-safe@~5.0.1:
json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
Expand Down

0 comments on commit ac4ddec

Please sign in to comment.