Skip to content

Commit 8e61ed1

Browse files
authored
feat: display cluster latency (#689)
## What type of PR is this? /kind feature ## What this PR does / why we need it: This PR shows cluster latency in summary card and cluster card. ![image](https://github.com/user-attachments/assets/962f55e6-fbab-4d2e-afea-b76829eb2f7b) --------- ![image](https://github.com/user-attachments/assets/6ae1a7b1-c6fe-4f26-96d5-9bd957ce82c6) ## Which issue(s) this PR fixes: Fixes #457
1 parent 59c967d commit 8e61ed1

6 files changed

Lines changed: 95 additions & 4 deletions

File tree

pkg/core/manager/insight/summary.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ const (
3636

3737
// GetDetailsForCluster returns ClusterDetail object for a given cluster
3838
func (i *InsightManager) GetDetailsForCluster(ctx context.Context, client *multicluster.MultiClusterClient, name string) (*ClusterDetail, error) {
39+
// get server version and measure latency
40+
start := time.Now()
3941
serverVersion, err := client.ClientSet.DiscoveryClient.ServerVersion()
4042
if err != nil {
4143
return nil, fmt.Errorf("failed to get server version: %w", err)
4244
}
45+
latency := time.Since(start).Milliseconds()
4346

4447
// Get the list of nodes
4548
nodes, err := client.ClientSet.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
@@ -144,6 +147,7 @@ func (i *InsightManager) GetDetailsForCluster(ctx context.Context, client *multi
144147
MetricsEnabled: metricsEnabled,
145148
CPUMetrics: cpuMetrics,
146149
MemoryMetrics: memoryMetrics,
150+
Latency: latency,
147151
}, nil
148152
}
149153

pkg/core/manager/insight/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ type ClusterDetail struct {
8282
PodsCapacity int64 `json:"podsCapacity"`
8383
PodsUsage int64 `json:"podsUsage"`
8484

85+
// Latency is the latency of the cluster in milliseconds
86+
Latency int64 `json:"latency"`
87+
8588
MetricsEnabled bool `json:"metricsEnabled"`
8689

8790
CPUMetrics ResourceMetrics `json:"cpuMetrics"`

ui/src/hooks/useClusterLatency.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { useAxios } from '@/utils/request'
2+
import { useState, useEffect, useRef, useCallback } from 'react'
3+
import axios from 'axios'
4+
5+
export const useClusterLatency = (cluster: string) => {
6+
const latencyRef = useRef<number>(0)
7+
const [loading, setLoading] = useState(true)
8+
const initialized = useRef(false)
9+
10+
const { response: summaryResponse, refetch: summaryRefetch } = useAxios({
11+
url: `${axios.defaults.baseURL}/rest-api/v1/insight/summary`,
12+
method: 'GET',
13+
manual: true,
14+
})
15+
16+
useEffect(() => {
17+
if (summaryResponse?.success) {
18+
latencyRef.current = summaryResponse?.data?.latency
19+
setLoading(false)
20+
} else {
21+
latencyRef.current = 0
22+
setLoading(true)
23+
}
24+
}, [summaryResponse])
25+
26+
const fetchLatency = useCallback(() => {
27+
if (cluster) {
28+
summaryRefetch({
29+
option: {
30+
params: {
31+
cluster,
32+
},
33+
},
34+
})
35+
}
36+
}, [cluster, summaryRefetch])
37+
38+
// Only execute once when component is first mounted
39+
useEffect(() => {
40+
if (!initialized.current) {
41+
initialized.current = true
42+
fetchLatency()
43+
}
44+
// eslint-disable-next-line react-hooks/exhaustive-deps
45+
}, [])
46+
47+
return { latency: latencyRef, loading, refetch: fetchLatency }
48+
}

ui/src/pages/cluster/components/clusterCard/index.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import React from 'react'
2-
import { Button, Popconfirm } from 'antd'
2+
import { Button, Popconfirm, Tag } from 'antd'
33
import { useSelector } from 'react-redux'
44
import { useTranslation } from 'react-i18next'
55
import { utcDateToLocalDate } from '@/utils/tools'
66
import k8sPng from '@/assets/kubernetes.png'
77
import EditPopForm from '../editPopForm'
8+
import { useClusterLatency } from '@/hooks/useClusterLatency'
9+
import { LoadingOutlined } from '@ant-design/icons'
810

911
import styles from './styles.module.less'
1012

@@ -30,6 +32,11 @@ const ClusterCard = (props: IProps) => {
3032
handleSubmit,
3133
customStyle,
3234
} = props
35+
36+
const { latency, loading: latencyLoading } = useClusterLatency(
37+
item?.metadata?.name,
38+
)
39+
3340
return (
3441
<div className={styles.card} style={customStyle}>
3542
<div className={styles.left} onClick={() => goDetailPage(item)}>
@@ -43,13 +50,36 @@ const ClusterCard = (props: IProps) => {
4350
<>
4451
{item?.spec?.displayName}
4552
<span style={{ color: '#808080' }}>
46-
{item?.metadata?.name}
53+
&nbsp;({item?.metadata?.name})
4754
</span>
4855
</>
4956
) : (
5057
<span>{item?.metadata?.name}</span>
5158
)}
5259
</div>
60+
<div className={styles.latency}>
61+
{latencyLoading ? (
62+
<LoadingOutlined
63+
style={{ fontSize: '14px', color: '#1890ff' }}
64+
spin
65+
/>
66+
) : (
67+
<span>
68+
<Tag
69+
className="ml-2"
70+
color={
71+
latency.current < 100
72+
? 'success'
73+
: latency.current < 300
74+
? 'warning'
75+
: 'error'
76+
}
77+
>
78+
{latency.current}ms
79+
</Tag>
80+
</span>
81+
)}
82+
</div>
5383
</div>
5484
<div className={styles.desc}>{item?.spec?.description || '--'}</div>
5585
<div className={styles.bottom}>

ui/src/pages/insightDetail/components/sourceTable/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const PodStatusCell = ({ cluster, namespace, name }) => {
3232
const color =
3333
{
3434
Running: 'success',
35-
Terminating: 'default',
35+
Terminated: 'default',
3636
Unknown: 'error',
3737
}[status.current] || 'warning'
3838

ui/src/pages/insightDetail/components/summaryCard/index.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ const SummaryCard = ({ auditStat, summary }: SummaryCardProps) => {
346346
color={
347347
{
348348
Running: 'success',
349-
Terminating: 'default',
349+
Terminated: 'default',
350350
Unknown: 'error',
351351
}[summary?.resource?.status] || 'warning'
352352
}
@@ -532,6 +532,12 @@ const SummaryCard = ({ auditStat, summary }: SummaryCardProps) => {
532532
</>
533533
)}
534534
{summary?.countByGVK ? renderStatistics(summary?.countByGVK) : null}
535+
{summary?.latency && (
536+
<div className={styles.item}>
537+
<div className={styles.label}>Latency</div>
538+
<div className={styles.value}>{summary?.latency}ms</div>
539+
</div>
540+
)}
535541
</div>
536542
</div>
537543
</div>

0 commit comments

Comments
 (0)