|
29 | 29 | </sba-panel> |
30 | 30 | </template> |
31 | 31 |
|
32 | | -<script> |
| 32 | +<script setup lang="ts"> |
33 | 33 | import { take } from 'rxjs/operators'; |
| 34 | +import { computed, onMounted, onUnmounted, ref } from 'vue'; |
| 35 | +import { useI18n } from 'vue-i18n'; |
34 | 36 |
|
35 | | -import subscribing from '@/mixins/subscribing'; |
36 | 37 | import sbaConfig from '@/sba-config'; |
37 | 38 | import Instance from '@/services/instance'; |
38 | 39 | import { concatMap, delay, retryWhen, timer } from '@/utils/rxjs'; |
39 | 40 | import processUptime from '@/views/instances/details/process-uptime'; |
40 | 41 | import { toMillis } from '@/views/instances/metrics/metric'; |
41 | 42 |
|
42 | | -export default { |
43 | | - components: { processUptime }, |
44 | | - mixins: [subscribing], |
45 | | - props: { |
46 | | - instance: { |
47 | | - type: Instance, |
48 | | - required: true, |
49 | | - }, |
50 | | - }, |
51 | | - data: () => ({ |
52 | | - hasLoaded: false, |
53 | | - error: null, |
54 | | - pid: null, |
55 | | - uptime: { value: null, baseUnit: null }, |
56 | | - systemCpuLoad: null, |
57 | | - processCpuLoad: null, |
58 | | - systemCpuCount: null, |
59 | | - }), |
60 | | - computed: { |
61 | | - tableData() { |
62 | | - return { |
63 | | - pid: { |
64 | | - label: this.$t('instances.details.process.pid'), |
65 | | - value: this.pid, |
66 | | - }, |
67 | | - uptime: { |
68 | | - label: this.$t('instances.details.process.uptime'), |
69 | | - value: toMillis(this.uptime.value, this.uptime.baseUnit), |
70 | | - }, |
71 | | - processCpuLoad: { |
72 | | - label: this.$t('instances.details.process.process_cpu_usage'), |
73 | | - value: this.processCpuLoad?.toFixed(2), |
74 | | - }, |
75 | | - systemCpuLoad: { |
76 | | - label: this.$t('instances.details.process.system_cpu_usage'), |
77 | | - value: this.systemCpuLoad?.toFixed(2), |
78 | | - }, |
79 | | - cpus: { |
80 | | - label: this.$t('instances.details.process.cpus'), |
81 | | - value: this.systemCpuCount, |
82 | | - }, |
83 | | - }; |
| 43 | +// Typdefinitionen |
| 44 | +interface UptimeData { |
| 45 | + value: number | null; |
| 46 | + baseUnit: string | null; |
| 47 | +} |
| 48 | +
|
| 49 | +interface MetricResponse { |
| 50 | + measurements: Array<{ value: number }>; |
| 51 | + baseUnit: string; |
| 52 | +} |
| 53 | +
|
| 54 | +interface CpuLoadMetrics { |
| 55 | + processCpuLoad: number | null; |
| 56 | + systemCpuLoad: number | null; |
| 57 | +} |
| 58 | +
|
| 59 | +interface TableData { |
| 60 | + label: string; |
| 61 | + value: number | string | null; |
| 62 | +} |
| 63 | +
|
| 64 | +interface TableDataMap { |
| 65 | + [key: string]: TableData; |
| 66 | +} |
| 67 | +
|
| 68 | +// Props Definition |
| 69 | +const props = defineProps<{ |
| 70 | + instance: Instance; |
| 71 | +}>(); |
| 72 | +
|
| 73 | +const { t, locale } = useI18n(); |
| 74 | +
|
| 75 | +// Reaktive Zustandsvariablen |
| 76 | +const hasLoaded = ref<boolean>(false); |
| 77 | +const error = ref<Error | null>(null); |
| 78 | +
|
| 79 | +const pid = ref<number | null>(null); |
| 80 | +const parentPid = ref<number | null>(null); |
| 81 | +const owner = ref<string | null>(null); |
| 82 | +const uptime = ref<UptimeData>({ value: null, baseUnit: null }); |
| 83 | +const systemCpuLoad = ref<number | null>(null); |
| 84 | +const processCpuLoad = ref<number | null>(null); |
| 85 | +const systemCpuCount = ref<number | null>(null); |
| 86 | +
|
| 87 | +// Berechnete Eigenschaften |
| 88 | +const tableData = computed<TableDataMap>(() => { |
| 89 | + const formatNumber = Intl.NumberFormat(locale.value, { |
| 90 | + maximumFractionDigits: 2, |
| 91 | + }); |
| 92 | +
|
| 93 | + return { |
| 94 | + pid: { |
| 95 | + label: t('instances.details.process.pid'), |
| 96 | + value: pid.value, |
84 | 97 | }, |
85 | | - }, |
86 | | - created() { |
87 | | - this.fetchPid(); |
88 | | - this.fetchUptime(); |
89 | | - this.fetchCpuCount(); |
90 | | - }, |
91 | | - methods: { |
92 | | - toMillis, |
93 | | - async fetchUptime() { |
94 | | - try { |
95 | | - const response = await this.fetchMetric('process.uptime'); |
96 | | - this.uptime = { |
97 | | - value: response.measurements[0].value, |
98 | | - baseUnit: response.baseUnit, |
99 | | - }; |
100 | | - } catch (error) { |
101 | | - this.error = error; |
102 | | - console.warn('Fetching Uptime failed:', error); |
103 | | - } finally { |
104 | | - this.hasLoaded = true; |
105 | | - } |
| 98 | + parentPid: { |
| 99 | + label: t('instances.details.process.parent_pid'), |
| 100 | + value: parentPid.value, |
106 | 101 | }, |
107 | | - async fetchPid() { |
108 | | - if (this.instance.hasEndpoint('env')) { |
109 | | - try { |
110 | | - const response = await this.instance.fetchEnv('PID'); |
111 | | - this.pid = response.data.property.value; |
112 | | - } catch (error) { |
113 | | - console.warn('Fetching PID failed:', error); |
114 | | - } finally { |
115 | | - this.hasLoaded = true; |
116 | | - } |
117 | | - } |
| 102 | + owner: { |
| 103 | + label: t('instances.details.process.owner'), |
| 104 | + value: owner.value, |
118 | 105 | }, |
119 | | - async fetchCpuCount() { |
120 | | - try { |
121 | | - this.systemCpuCount = ( |
122 | | - await this.fetchMetric('system.cpu.count') |
123 | | - ).measurements[0].value; |
124 | | - } catch (error) { |
125 | | - console.warn('Fetching Cpu Count failed:', error); |
126 | | - } finally { |
127 | | - this.hasLoaded = true; |
128 | | - } |
| 106 | + uptime: { |
| 107 | + label: t('instances.details.process.uptime'), |
| 108 | + value: toMillis(uptime.value.value, uptime.value.baseUnit), |
129 | 109 | }, |
130 | | - createSubscription() { |
131 | | - return timer(0, sbaConfig.uiSettings.pollTimer.process) |
132 | | - .pipe( |
133 | | - concatMap(this.fetchCpuLoadMetrics), |
134 | | - retryWhen((err) => { |
135 | | - return err.pipe(delay(1000), take(5)); |
136 | | - }), |
137 | | - ) |
138 | | - .subscribe({ |
139 | | - next: (data) => { |
140 | | - this.processCpuLoad = data.processCpuLoad; |
141 | | - this.systemCpuLoad = data.systemCpuLoad; |
142 | | - }, |
143 | | - error: (error) => { |
144 | | - this.hasLoaded = true; |
145 | | - console.warn('Fetching CPU Usage metrics failed:', error); |
146 | | - this.error = error; |
147 | | - }, |
148 | | - }); |
| 110 | + processCpuLoad: { |
| 111 | + label: t('instances.details.process.process_cpu_usage'), |
| 112 | + value: isNaN(processCpuLoad.value) |
| 113 | + ? '-' |
| 114 | + : `${formatNumber.format(processCpuLoad.value * 100)}%`, |
149 | 115 | }, |
150 | | - async fetchCpuLoadMetrics() { |
151 | | - const fetchProcessCpuLoad = this.fetchMetric('process.cpu.usage'); |
152 | | - const fetchSystemCpuLoad = this.fetchMetric('system.cpu.usage'); |
153 | | - let processCpuLoad; |
154 | | - let systemCpuLoad; |
155 | | - try { |
156 | | - processCpuLoad = (await fetchProcessCpuLoad).measurements[0].value; |
157 | | - } catch (error) { |
158 | | - console.warn('Fetching Process CPU Load failed:', error); |
159 | | - } |
160 | | - try { |
161 | | - systemCpuLoad = (await fetchSystemCpuLoad).measurements[0].value; |
162 | | - } catch (error) { |
163 | | - console.warn('Fetching Sytem CPU Load failed:', error); |
164 | | - } |
165 | | - return { |
166 | | - processCpuLoad, |
167 | | - systemCpuLoad, |
168 | | - }; |
| 116 | + systemCpuLoad: { |
| 117 | + label: t('instances.details.process.system_cpu_usage'), |
| 118 | + value: isNaN(systemCpuLoad.value) |
| 119 | + ? '-' |
| 120 | + : `${formatNumber.format(systemCpuLoad.value * 100)}%`, |
169 | 121 | }, |
170 | | - async fetchMetric(name) { |
171 | | - const response = await this.instance.fetchMetric(name); |
172 | | - return response.data; |
| 122 | + cpus: { |
| 123 | + label: t('instances.details.process.cpus'), |
| 124 | + value: systemCpuCount.value, |
173 | 125 | }, |
174 | | - }, |
| 126 | + }; |
| 127 | +}); |
| 128 | +
|
| 129 | +// Hilfsfunktionen |
| 130 | +const fetchMetric = async (name: string): Promise<MetricResponse> => { |
| 131 | + const response = await props.instance.fetchMetric(name); |
| 132 | + return response.data; |
175 | 133 | }; |
| 134 | +
|
| 135 | +const fetchUptime = async (): Promise<void> => { |
| 136 | + try { |
| 137 | + const response = await fetchMetric('process.uptime'); |
| 138 | + uptime.value = { |
| 139 | + value: response.measurements[0].value, |
| 140 | + baseUnit: response.baseUnit, |
| 141 | + }; |
| 142 | + } catch (err) { |
| 143 | + error.value = err instanceof Error ? err : new Error('Unknown error'); |
| 144 | + console.warn('Fetching Uptime failed:', err); |
| 145 | + } |
| 146 | +}; |
| 147 | +
|
| 148 | +const fetchPid = async (): Promise<void> => { |
| 149 | + if (props.instance.hasEndpoint('env')) { |
| 150 | + try { |
| 151 | + const response = await props.instance.fetchEnv('PID'); |
| 152 | + pid.value = response.data.property.value; |
| 153 | + } catch (err) { |
| 154 | + console.warn('Fetching PID failed:', err); |
| 155 | + } |
| 156 | + } |
| 157 | +}; |
| 158 | +
|
| 159 | +const fetchCpuCount = async (): Promise<void> => { |
| 160 | + try { |
| 161 | + const response = await fetchMetric('system.cpu.count'); |
| 162 | + systemCpuCount.value = response.measurements[0].value; |
| 163 | + } catch (err) { |
| 164 | + console.warn('Fetching Cpu Count failed:', err); |
| 165 | + } |
| 166 | +}; |
| 167 | +
|
| 168 | +const fetchProcessInfo = async (): Promise<void> => { |
| 169 | + try { |
| 170 | + const response = await props.instance.fetchInfo(); |
| 171 | + const processInfo = response.data.process; |
| 172 | + if (processInfo) { |
| 173 | + pid.value = processInfo.pid; |
| 174 | + parentPid.value = processInfo.parentPid; |
| 175 | + owner.value = processInfo.owner; |
| 176 | + } |
| 177 | + } catch (err) { |
| 178 | + console.warn('Fetching Process Info failed:', err); |
| 179 | + } |
| 180 | +}; |
| 181 | +
|
| 182 | +const fetchCpuLoadMetrics = async (): Promise<CpuLoadMetrics> => { |
| 183 | + const fetchProcessCpuLoad = fetchMetric('process.cpu.usage'); |
| 184 | + const fetchSystemCpuLoad = fetchMetric('system.cpu.usage'); |
| 185 | +
|
| 186 | + let processCpuLoadValue: number | null = null; |
| 187 | + let systemCpuLoadValue: number | null = null; |
| 188 | +
|
| 189 | + try { |
| 190 | + const response = await fetchProcessCpuLoad; |
| 191 | + processCpuLoadValue = response.measurements[0].value; |
| 192 | + } catch (err) { |
| 193 | + console.warn('Fetching Process CPU Load failed:', err); |
| 194 | + } |
| 195 | +
|
| 196 | + try { |
| 197 | + const response = await fetchSystemCpuLoad; |
| 198 | + systemCpuLoadValue = response.measurements[0].value; |
| 199 | + } catch (err) { |
| 200 | + console.warn('Fetching System CPU Load failed:', err); |
| 201 | + } |
| 202 | +
|
| 203 | + return { |
| 204 | + processCpuLoad: processCpuLoadValue, |
| 205 | + systemCpuLoad: systemCpuLoadValue, |
| 206 | + }; |
| 207 | +}; |
| 208 | +
|
| 209 | +onMounted(async () => { |
| 210 | + try { |
| 211 | + await Promise.allSettled([ |
| 212 | + fetchPid(), |
| 213 | + fetchUptime(), |
| 214 | + fetchCpuCount(), |
| 215 | + fetchProcessInfo(), |
| 216 | + ]); |
| 217 | + } finally { |
| 218 | + hasLoaded.value = true; |
| 219 | + } |
| 220 | +
|
| 221 | + const subscription = timer(0, sbaConfig.uiSettings.pollTimer.process) |
| 222 | + .pipe( |
| 223 | + concatMap(fetchCpuLoadMetrics), |
| 224 | + retryWhen((err) => err.pipe(delay(1000, take(5)))), |
| 225 | + ) |
| 226 | + .subscribe({ |
| 227 | + next: (data: CpuLoadMetrics) => { |
| 228 | + processCpuLoad.value = data.processCpuLoad; |
| 229 | + systemCpuLoad.value = data.systemCpuLoad; |
| 230 | + }, |
| 231 | + error: (err: Error) => { |
| 232 | + hasLoaded.value = true; |
| 233 | + console.warn('Fetching CPU Usage metrics failed:', err); |
| 234 | + error.value = rr; |
| 235 | + }, |
| 236 | + }); |
| 237 | +
|
| 238 | + onUnmounted(() => { |
| 239 | + subscription.unsubscribe(); |
| 240 | + }); |
| 241 | +}); |
176 | 242 | </script> |
0 commit comments