|
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