add app monitoring charts and runtime metrics
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-07-09 13:09:41 +09:00
parent f142de8763
commit fbefc08b85
+52 -7
View File
@@ -62,14 +62,59 @@ export class RuntimeService {
} }
async listPodMetrics(namespace?: string) { async listPodMetrics(namespace?: string) {
const output = await this.kubectl([ try {
'top', const output = await this.kubectl([
'pods', 'top',
...(namespace ? ['-n', namespace] : ['--all-namespaces']), 'pods',
'--no-headers', ...(namespace ? ['-n', namespace] : ['--all-namespaces']),
]); '--no-headers',
]);
return parsePodMetrics(output, Boolean(namespace), namespace); return parsePodMetrics(output, Boolean(namespace), namespace);
} catch {
return this.listRunningPodMetrics(namespace);
}
}
private async listRunningPodMetrics(namespace?: string) {
const pods = await this.kubectlJson([
'get',
'pods',
'-o',
'json',
...(namespace ? ['-n', namespace] : ['--all-namespaces']),
]);
const runningPods = (pods.items ?? [])
.filter((pod: KubectlJson) => pod.status?.phase === 'Running')
.map((pod: KubectlJson) => ({
namespace: pod.metadata?.namespace,
name: pod.metadata?.name,
}))
.filter((pod: { namespace?: string; name?: string }) => pod.namespace && pod.name);
if (!runningPods.length) {
return [];
}
const byNamespace = new Map<string, string[]>();
runningPods.forEach((pod: { namespace: string; name: string }) => {
byNamespace.set(pod.namespace, [...(byNamespace.get(pod.namespace) ?? []), pod.name]);
});
const outputs = await Promise.all([...byNamespace.entries()].map(([podNamespace, podNames]) => (
this.kubectl([
'top',
'pods',
...podNames,
'-n',
podNamespace,
'--no-headers',
])
.then((output) => parsePodMetrics(output, true, podNamespace))
.catch(() => [])
)));
return outputs.flat();
} }
async getClusterMetrics() { async getClusterMetrics() {