Skip to content

Commit 0093ac7

Browse files
Kinplemelonysfscream
authored andcommittedMar 11, 2025
refactor(auth): some details of node cache
1 parent 3928040 commit 0093ac7

File tree

7 files changed

+236
-134
lines changed

7 files changed

+236
-134
lines changed
 

‎src/auto-imports.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ declare global {
322322
const useMockData: typeof import('./hooks/Rule/rule/useDebugRule')['useMockData']
323323
const useModel: typeof import('vue')['useModel']
324324
const useMove: typeof import('./hooks/useMove')['default']
325+
const useNodeOpts: typeof import('./hooks/useMetrics')['useNodeOpts']
325326
const useNodesGraph: typeof import('./hooks/Overview/useNodesGraph')['default']
326327
const useOperationConfirm: typeof import('./hooks/useOperationConfirm')['default']
327328
const usePagination: typeof import('./hooks/usePagination')['default']
@@ -360,6 +361,7 @@ declare global {
360361
const useSchemaRecord: typeof import('./hooks/Schema/useSchemaRecord')['default']
361362
const useShowLog: typeof import('./hooks/Rule/rule/useFormatDebugLog')['useShowLog']
362363
const useShowTextByDifferent: typeof import('./hooks/useShowTextByDifferent')['default']
364+
const useSizeMetric: typeof import('./hooks/useMetrics')['useSizeMetric']
363365
const useSlots: typeof import('vue')['useSlots']
364366
const useSortableTable: typeof import('./hooks/useSortableTable')['default']
365367
const useSourceList: typeof import('./hooks/Rule/action/useSourceList')['default']
@@ -753,6 +755,7 @@ declare module 'vue' {
753755
readonly useMockData: UnwrapRef<typeof import('./hooks/Rule/rule/useDebugRule')['useMockData']>
754756
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
755757
readonly useMove: UnwrapRef<typeof import('./hooks/useMove')['default']>
758+
readonly useNodeOpts: UnwrapRef<typeof import('./hooks/useMetrics')['useNodeOpts']>
756759
readonly useNodesGraph: UnwrapRef<typeof import('./hooks/Overview/useNodesGraph')['default']>
757760
readonly useOperationConfirm: UnwrapRef<typeof import('./hooks/useOperationConfirm')['default']>
758761
readonly usePagination: UnwrapRef<typeof import('./hooks/usePagination')['default']>
@@ -791,6 +794,7 @@ declare module 'vue' {
791794
readonly useSchemaRecord: UnwrapRef<typeof import('./hooks/Schema/useSchemaRecord')['default']>
792795
readonly useShowLog: UnwrapRef<typeof import('./hooks/Rule/rule/useFormatDebugLog')['useShowLog']>
793796
readonly useShowTextByDifferent: UnwrapRef<typeof import('./hooks/useShowTextByDifferent')['default']>
797+
readonly useSizeMetric: UnwrapRef<typeof import('./hooks/useMetrics')['useSizeMetric']>
794798
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
795799
readonly useSortableTable: UnwrapRef<typeof import('./hooks/useSortableTable')['default']>
796800
readonly useSourceList: UnwrapRef<typeof import('./hooks/Rule/action/useSourceList')['default']>

‎src/components/Metrics/OverviewMetrics.vue

+4-6
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,10 @@ const { t, tl } = useI18nTl('RuleEngine')
224224
225225
const metricsData = ref<MetricsData>({ metrics: {}, node_metrics: [] })
226226
227-
const CLUSTER = 'cluster'
228-
const clusterOpt = { label: t('BasicConfig.cluster'), value: CLUSTER }
229-
const nodeOpts = computed(() => [
230-
clusterOpt,
231-
...(metricsData.value?.node_metrics || []).map(({ node }) => ({ value: node, label: node })),
232-
])
227+
const { CLUSTER, getNodeOpts } = useNodeOpts()
228+
const nodeOpts = computed(() =>
229+
getNodeOpts((metricsData.value?.node_metrics || []).map(({ node }) => node)),
230+
)
233231
const selectedNode = ref(CLUSTER)
234232
const handleNodeChange = () => {
235233
rateData = getInitRateData()

‎src/hooks/useMetrics.ts

+33-4
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,38 @@ export const useChartDataUtils = (): {
319319
}
320320
}
321321

322+
export const useSizeMetric = () => {
323+
const getSizeStr = (bytes: number) => transMemorySizeNumToStr(bytes, 2)
324+
const numPartReg = /^-?\d+(\.\d+)?/
325+
const getSizeNumPart = (size: string) => numPartReg.exec(size)?.[0] || '0'
326+
const getSizeUnitPart = (size: string) => size.replace(numPartReg, '') || 'Bytes'
327+
328+
const getSizeNum = (size: number) => formatNumber(getSizeNumPart(getSizeStr(size)))
329+
const getSizeUnit = (size: number) => getSizeUnitPart(getSizeStr(size))
330+
331+
return {
332+
getSizeStr,
333+
getSizeNumPart,
334+
getSizeUnitPart,
335+
getSizeNum,
336+
getSizeUnit,
337+
}
338+
}
339+
340+
export const useNodeOpts = () => {
341+
const { tl } = useI18nTl('BasicConfig')
342+
const CLUSTER = 'cluster'
343+
const clusterOpt = { label: tl('cluster'), value: CLUSTER }
344+
const getNodeOpts = (nodes: Array<string>) => [
345+
clusterOpt,
346+
...nodes.map((node) => ({ value: node, label: node })),
347+
]
348+
return {
349+
CLUSTER,
350+
getNodeOpts,
351+
}
352+
}
353+
322354
interface Rate {
323355
unitKey: string
324356
current: string
@@ -392,10 +424,7 @@ export const useBridgeMetrics = (): {
392424
}
393425

394426
export const useActionQueueMetrics = () => {
395-
const getSizeStr = (bytes: number) => transMemorySizeNumToStr(bytes, 2)
396-
const numPartReg = /^-?\d+(\.\d+)?/
397-
const getSizeNumPart = (size: string) => numPartReg.exec(size)?.[0] || '0'
398-
const getSizeUnitPart = (size: string) => size.replace(numPartReg, '') || 'Bytes'
427+
const { getSizeStr, getSizeNumPart, getSizeUnitPart } = useSizeMetric()
399428

400429
const queueBytesDataLength = 20
401430
const completeQueueBytesDataData = (

‎src/i18n/Auth.ts

+18-10
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,8 @@ export default {
540540
en: 'Number of times client authorization data is not found. If the authorizer execution fails, the count will also increase',
541541
},
542542
rateUnit: {
543-
zh: '次/秒 | 次/秒',
544-
en: 'time/sec | times/sec',
543+
zh: '次/秒',
544+
en: 'times/sec | time/sec | times/sec',
545545
},
546546
authnRateBarDesc: {
547547
zh: '近一分钟内认证次数趋势',
@@ -641,10 +641,6 @@ export default {
641641
},
642642

643643
// Node Cache Metrics
644-
cacheMetrics: {
645-
zh: '缓存指标',
646-
en: 'Cache Metrics',
647-
},
648644
cacheCount: {
649645
zh: '缓存条目数',
650646
en: 'Cache Entries',
@@ -666,12 +662,16 @@ export default {
666662
en: 'Cache Misses',
667663
},
668664
currentRate: {
669-
zh: '(当前)',
670-
en: '(current)',
665+
zh: '当前',
666+
en: 'current',
671667
},
672668
last5mRate: {
673-
zh: '(5 分钟)',
674-
en: '(5 mins)',
669+
zh: '5 分钟',
670+
en: '5 mins',
671+
},
672+
insertUnit: {
673+
zh: '条/秒',
674+
en: 'entries/sec | entry/sec | entries/sec',
675675
},
676676
bytes: {
677677
zh: '字节',
@@ -681,4 +681,12 @@ export default {
681681
zh: '刷新',
682682
en: 'Refresh',
683683
},
684+
resetNodeCacheStatus: {
685+
zh: '重置节点缓存状态',
686+
en: 'Reset Node Cache Status',
687+
},
688+
resetNodeCacheStatusConfirm: {
689+
zh: '确定要重置节点缓存状态吗?',
690+
en: 'Are you sure you want to reset the node cache status?',
691+
},
684692
}

‎src/i18n/Base.ts

+4
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,10 @@ export default {
647647
zh: ',',
648648
en: ', ',
649649
},
650+
wordBdy: {
651+
zh: '',
652+
en: ' ',
653+
},
650654
lastModified: {
651655
zh: '更新时间',
652656
en: 'Last Modified',

‎src/views/Auth/components/AuthItemOverview.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
</el-table-column>
2727
<el-table-column
2828
:prop="isAuthn ? 'metrics.success' : 'metrics.allow'"
29-
:label="tl('success')"
29+
:label="t('Base.allow')"
3030
/>
3131
<el-table-column
3232
:prop="isAuthn ? 'metrics.failed' : 'metrics.deny'"
33-
:label="tl('ErrNum')"
33+
:label="t('Base.deny')"
3434
/>
3535
<el-table-column prop="metrics.rate" :label="`${$t('Base.rateNow')} (QPS)`" />
3636
</el-table>
@@ -114,7 +114,7 @@ const nodeStatusTableData = ({ node_metrics }: MetricsData) => {
114114
})
115115
}
116116
117-
const { tl } = useI18nTl('RuleEngine')
117+
const { t, tl } = useI18nTl('RuleEngine')
118118
119119
const setNodeConnectingStatusMap = () => {
120120
nodeConnectingStatusMap.value = props.metrics.node_status.reduce((obj, nodeStatusItem) => {

‎src/views/Auth/components/NodeCache.vue

+170-111
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
<template>
2-
<el-dropdown>
3-
<el-button @click="openNodeCacheSettings">{{ tl('nodeCacheSettings') }}</el-button>
2+
<el-dropdown
3+
split-button
4+
@click="openNodeCacheSettings"
5+
placement="bottom-end"
6+
class="node-cache-dropdown"
7+
>
8+
{{ tl('nodeCacheSettings') }}
49
<template #dropdown>
5-
<el-button @click="openNodeCacheStatus">{{ tl('nodeCacheStatus') }}</el-button>
10+
<el-button size="large" @click="openNodeCacheStatus">{{ tl('nodeCacheStatus') }}</el-button>
611
</template>
712
</el-dropdown>
813
<el-drawer
@@ -30,6 +35,7 @@
3035
v-model="record.max_count"
3136
:items="[{ type: 'number' }, { symbols: [UNLIMITED], type: 'enum' }]"
3237
:disabled="!record.enable"
38+
:disabled-label="t('Extension.unlimited')"
3339
/>
3440
</el-form-item>
3541

@@ -61,88 +67,119 @@
6167
class="node-cache-status-drawer"
6268
:size="900"
6369
:title="tl('nodeCacheStatus')"
64-
v-loading="isCacheMetricsLoading"
6570
>
66-
<div class="metrics-header">
67-
<h2 class="metrics-title">{{ tl('cacheMetrics') }}</h2>
68-
<RefreshButton @click="loadCacheMetrics" />
71+
<div v-loading="isCacheMetricsLoading">
72+
<div class="metrics-header">
73+
<div class="vertical-align-center">
74+
<el-select v-model="selectedNode">
75+
<el-option
76+
v-for="{ label, value } in nodeOpts"
77+
:key="value"
78+
:label="label"
79+
:value="value"
80+
/>
81+
</el-select>
82+
<el-tooltip :content="t('Base.refresh')" placement="top">
83+
<RefreshButton class="icon-button" no-text @click="loadCacheMetrics" />
84+
</el-tooltip>
85+
<el-tooltip :content="tl('resetNodeCacheStatus')" placement="top">
86+
<el-button class="icon-button" :icon="Close" @click="resetCacheMetrics"></el-button>
87+
</el-tooltip>
88+
</div>
89+
</div>
90+
<el-row :gutter="24">
91+
<el-col :span="12">
92+
<el-card>
93+
<p class="metric-label">{{ tl('cacheMemory') }}</p>
94+
<div class="metric-value">
95+
<p class="metric-value-num">
96+
{{ getSizeNum(metrics.memory) }}
97+
<span class="metric-unit">{{ getSizeUnit(metrics.memory) }}</span>
98+
</p>
99+
</div>
100+
</el-card>
101+
</el-col>
102+
<el-col :span="12">
103+
<el-card>
104+
<p class="metric-label">{{ tl('cacheCount') }}</p>
105+
<div class="metric-value">
106+
<p class="metric-value-num">{{ formatNumber(metrics.count) }}</p>
107+
</div>
108+
</el-card>
109+
</el-col>
110+
<el-col :span="12">
111+
<el-card>
112+
<p class="metric-label">{{ tl('cacheHits') }}</p>
113+
<div class="metric-value">
114+
<p class="metric-value-num">{{ formatNumber(metrics.hits.value) }}</p>
115+
</div>
116+
<div class="metric-rate">
117+
<span class="rate-item current">
118+
{{ getRateValueStr(metrics.hits.rate.current) }} ({{ tl('currentRate') }})
119+
</span>
120+
<span class="rate-item">
121+
{{ getRateValueStr(metrics.hits.rate.last5m) }} ({{ tl('last5mRate') }})
122+
</span>
123+
<span class="rate-item">
124+
{{ getRateValueStr(metrics.hits.rate.max) }} ({{ t('Dashboard.maximum') }})
125+
</span>
126+
</div>
127+
</el-card>
128+
</el-col>
129+
<el-col :span="12">
130+
<el-card>
131+
<p class="metric-label">{{ tl('cacheMisses') }}</p>
132+
<div class="metric-value">
133+
<p class="metric-value-num">{{ formatNumber(metrics.misses.value) }}</p>
134+
</div>
135+
<div class="metric-rate">
136+
<span class="rate-item current">
137+
{{ getRateValueStr(metrics.misses.rate.current) }} ({{ tl('currentRate') }})
138+
</span>
139+
<span class="rate-item">
140+
{{ getRateValueStr(metrics.misses.rate.last5m) }} ({{ tl('last5mRate') }})
141+
</span>
142+
<span class="rate-item">
143+
{{ getRateValueStr(metrics.misses.rate.max) }} ({{ t('Dashboard.maximum') }})
144+
</span>
145+
</div>
146+
</el-card>
147+
</el-col>
148+
<el-col :span="12">
149+
<el-card>
150+
<p class="metric-label">{{ tl('cacheInserts') }}</p>
151+
<div class="metric-value">
152+
<p class="metric-value-num">{{ formatNumber(metrics.inserts.value) }}</p>
153+
</div>
154+
<div class="metric-rate">
155+
<span class="rate-item current">
156+
{{ getRateValueStr(metrics.inserts.rate.current, 'Auth.insertUnit') }}
157+
({{ tl('currentRate') }})
158+
</span>
159+
<span class="rate-item">
160+
{{ getRateValueStr(metrics.inserts.rate.last5m, 'Auth.insertUnit') }}
161+
({{ tl('last5mRate') }})
162+
</span>
163+
<span class="rate-item">
164+
{{ getRateValueStr(metrics.inserts.rate.max, 'Auth.insertUnit') }}
165+
({{ t('Dashboard.maximum') }})
166+
</span>
167+
</div>
168+
</el-card>
169+
</el-col>
170+
</el-row>
171+
<el-table :data="nodeMetrics" style="width: 100%">
172+
<el-table-column prop="node" :label="t('Base.node')" />
173+
<el-table-column prop="metrics.memory" :label="tl('cacheMemory')">
174+
<template #default="{ row }">
175+
{{ getSizeNum(row.metrics.memory) }}
176+
<span class="metric-unit">{{ getSizeUnit(row.metrics.memory) }}</span>
177+
</template>
178+
</el-table-column>
179+
<el-table-column prop="metrics.count" :label="tl('cacheCount')" />
180+
<el-table-column prop="metrics.hits.value" :label="tl('cacheHits')" />
181+
</el-table>
69182
</div>
70-
<el-row :gutter="24">
71-
<el-col :span="12">
72-
<el-card>
73-
<p class="metric-label">{{ tl('cacheMemory') }}</p>
74-
<div class="metric-value">
75-
<p class="metric-value-num">
76-
{{ metrics.memory }} <span class="metric-unit">{{ tl('bytes') }}</span>
77-
</p>
78-
</div>
79-
</el-card>
80-
</el-col>
81-
<el-col :span="12">
82-
<el-card>
83-
<p class="metric-label">{{ tl('cacheCount') }}</p>
84-
<div class="metric-value">
85-
<p class="metric-value-num">{{ metrics.count }}</p>
86-
</div>
87-
</el-card>
88-
</el-col>
89-
<el-col :span="12">
90-
<el-card>
91-
<p class="metric-label">{{ tl('cacheHits') }}</p>
92-
<div class="metric-value">
93-
<p class="metric-value-num">{{ metrics.hits.value }}</p>
94-
</div>
95-
<div class="metric-rate">
96-
<span class="rate-item current">
97-
{{ getRateValueStr(metrics.hits.rate.current) }} {{ tl('currentRate') }}
98-
</span>
99-
<span class="rate-item">
100-
{{ getRateValueStr(metrics.hits.rate.last5m) }} {{ tl('last5mRate') }}
101-
</span>
102-
</div>
103-
</el-card>
104-
</el-col>
105-
<el-col :span="12">
106-
<el-card>
107-
<p class="metric-label">{{ tl('cacheMisses') }}</p>
108-
<div class="metric-value">
109-
<p class="metric-value-num">{{ metrics.misses.value }}</p>
110-
</div>
111-
<div class="metric-rate">
112-
<span class="rate-item current">
113-
{{ getRateValueStr(metrics.misses.rate.current) }} {{ tl('currentRate') }}
114-
</span>
115-
<span class="rate-item">
116-
{{ getRateValueStr(metrics.misses.rate.last5m) }} {{ tl('last5mRate') }}
117-
</span>
118-
</div>
119-
</el-card>
120-
</el-col>
121-
<el-col :span="12">
122-
<el-card>
123-
<p class="metric-label">{{ tl('cacheInserts') }}</p>
124-
<div class="metric-value">
125-
<p class="metric-value-num">{{ metrics.inserts.value }}</p>
126-
</div>
127-
<div class="metric-rate">
128-
<span class="rate-item current">
129-
{{ getRateValueStr(metrics.inserts.rate.current) }} {{ tl('currentRate') }}
130-
</span>
131-
<span class="rate-item">
132-
{{ getRateValueStr(metrics.inserts.rate.last5m) }} {{ tl('last5mRate') }}
133-
</span>
134-
</div>
135-
</el-card>
136-
</el-col>
137-
</el-row>
138-
<el-table :data="nodeMetrics" style="width: 100%">
139-
<el-table-column prop="node" :label="t('Base.node')" />
140-
<el-table-column prop="metrics.memory" :label="tl('cacheMemory')" />
141-
<el-table-column prop="metrics.count" :label="tl('cacheCount')" />
142-
<el-table-column prop="metrics.hits.value" :label="tl('cacheHits')" />
143-
<el-table-column prop="metrics.misses.value" :label="tl('cacheMisses')" />
144-
<el-table-column prop="metrics.inserts.value" :label="tl('cacheInserts')" />
145-
</el-table>
146183
<template #footer>
147184
<el-button @click="cancelSettings">
148185
{{ t('APIKey.close') }}
@@ -162,6 +199,8 @@ import {
162199
updateAuthnSettings,
163200
updateAuthzSettings,
164201
} from '@/api/auth'
202+
import { useSizeMetric } from '@/hooks/useMetrics'
203+
import { Close } from '@element-plus/icons-vue'
165204
166205
type NodeCacheConfig = {
167206
enable?: boolean
@@ -253,8 +292,19 @@ const totalMetrics = ref({
253292
node_metrics: [],
254293
})
255294
256-
const metrics = computed(() => totalMetrics.value.metrics)
295+
const { CLUSTER, getNodeOpts } = useNodeOpts()
296+
const nodeOpts = computed(() => getNodeOpts((nodeMetrics.value || []).map(({ node }) => node)))
297+
const selectedNode = ref(CLUSTER)
298+
257299
const nodeMetrics = computed(() => totalMetrics.value.node_metrics)
300+
const metrics = computed(() => {
301+
if (selectedNode.value === CLUSTER) {
302+
return totalMetrics.value.metrics
303+
}
304+
return nodeMetrics.value.find(({ node }) => node === selectedNode.value)?.metrics
305+
})
306+
307+
const { getSizeNum, getSizeUnit } = useSizeMetric()
258308
259309
const requestCacheMetrics = () => (isAuthz.value ? loadAuthnCacheStatus() : loadAuthzCacheStatus())
260310
const requestResetCacheMetrics = () =>
@@ -274,39 +324,53 @@ const loadCacheMetrics = async () => {
274324
275325
const resetCacheMetrics = async () => {
276326
try {
327+
await ElMessageBox.confirm(tl('resetNodeCacheStatusConfirm'))
277328
await requestResetCacheMetrics()
329+
ElMessage.success(t('RuleEngine.resetSuccessfully'))
330+
loadCacheMetrics()
278331
} catch (error) {
279332
//
280333
}
281334
}
282335
283-
const getRateValueStr = (val: number) => `${val}${tl('rateUnit', { val })}`
336+
const getRateValueStr = (val: number, unit = 'Auth.rateUnit') =>
337+
`${formatNumber(val)} ${t(unit, val)}`
284338
</script>
285339

286340
<style lang="scss">
341+
.node-cache-dropdown {
342+
.el-dropdown__caret-button {
343+
&:hover {
344+
border-left-width: 1px;
345+
border-left-style: solid;
346+
}
347+
}
348+
.el-button-group > .el-button:hover {
349+
z-index: 10;
350+
}
351+
}
287352
.node-cache-status-drawer {
288353
.el-card {
289-
margin-bottom: 20px;
290-
transition: all 0.3s;
354+
margin-bottom: 24px;
355+
}
356+
.el-select {
357+
width: 200px;
358+
margin-right: 12px;
291359
}
292-
293360
.metric-label {
294361
margin-top: 8px;
295362
margin-bottom: 12px;
296363
color: var(--el-text-color-secondary);
297364
}
298-
299365
.metric-value {
300366
display: flex;
301367
align-items: baseline;
302-
font-weight: 600;
303-
368+
font-weight: 400;
304369
.metric-value-num {
305370
font-size: 22px;
306371
color: var(--el-text-color-primary);
307372
margin: 0;
308373
}
309-
310374
.metric-unit {
311375
font-size: 14px;
312376
font-weight: normal;
@@ -319,36 +383,31 @@ const getRateValueStr = (val: number) => `${val}${tl('rateUnit', { val })}`
319383
margin-top: 12px;
320384
display: flex;
321385
align-items: center;
322-
323386
.rate-item {
387+
position: relative;
388+
margin-right: 12px;
324389
color: var(--el-text-color-secondary);
325-
390+
&:not(:last-child):after {
391+
position: absolute;
392+
content: '';
393+
width: 1px;
394+
height: 12px;
395+
background-color: var(--el-border-color);
396+
right: -6px;
397+
top: 50%;
398+
transform: translateY(-50%);
399+
opacity: 0.75;
400+
}
326401
&.current {
327-
margin-right: 12px;
328402
color: var(--el-color-primary);
329403
}
330404
}
331405
}
332406
333-
// 添加一个标题
334407
.metrics-header {
335408
display: flex;
336-
align-items: center;
337-
justify-content: space-between;
409+
justify-content: flex-end;
338410
margin-bottom: 20px;
339411
}
340-
341-
.metrics-title {
342-
font-size: 20px;
343-
font-weight: 600;
344-
margin: 0;
345-
color: var(--el-text-color-primary);
346-
}
347-
348-
// 添加刷新按钮样式
349-
.refresh-button {
350-
margin-left: 10px;
351-
font-size: 14px;
352-
}
353412
}
354413
</style>

0 commit comments

Comments
 (0)
Please sign in to comment.