fix(posimai-dev): accurate cpu_pct via 100ms dual-sample diff
Single snapshot returns lifetime average (near 0 on idle systems). Two samples 100ms apart gives real-time cpu usage per core, then averaged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c09d5defd3
commit
6c138981a7
|
|
@ -39,24 +39,35 @@ app.get('/api/sessions/:id', (req, res) => {
|
||||||
|
|
||||||
// ── ヘルス & メトリクス API (/api/health) ──────────────────────
|
// ── ヘルス & メトリクス API (/api/health) ──────────────────────
|
||||||
// Atlas など外部から参照される。CORS ヘッダーを付与して Vercel 上の Atlas からも取得可能にする
|
// Atlas など外部から参照される。CORS ヘッダーを付与して Vercel 上の Atlas からも取得可能にする
|
||||||
|
function getCpuSample() {
|
||||||
|
return os.cpus().map((c) => {
|
||||||
|
const total = Object.values(c.times).reduce((a, b) => a + b, 0);
|
||||||
|
return { total, idle: c.times.idle };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
app.get('/api/health', (req, res) => {
|
app.get('/api/health', (req, res) => {
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
|
||||||
const mem = os.freemem();
|
const mem = os.freemem();
|
||||||
const total = os.totalmem();
|
const total = os.totalmem();
|
||||||
const cpus = os.cpus();
|
|
||||||
|
|
||||||
// CPU 使用率: 全コアの平均(起動時 idle から差し引く簡易計算)
|
// CPU: 100ms 間隔の2サンプルで実使用率を計算
|
||||||
const cpuUsage = cpus.reduce((sum, c) => {
|
const s1 = getCpuSample();
|
||||||
const t = Object.values(c.times).reduce((a, b) => a + b, 0);
|
setTimeout(() => {
|
||||||
return sum + ((t - c.times.idle) / t) * 100;
|
const s2 = getCpuSample();
|
||||||
}, 0) / cpus.length;
|
const cpuPct = s1.reduce((sum, c1, i) => {
|
||||||
|
const c2 = s2[i];
|
||||||
|
const dIdle = c2.idle - c1.idle;
|
||||||
|
const dTotal = c2.total - c1.total;
|
||||||
|
return sum + (dTotal > 0 ? (1 - dIdle / dTotal) * 100 : 0);
|
||||||
|
}, 0) / s1.length;
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
hostname: os.hostname(),
|
hostname: os.hostname(),
|
||||||
uptime_s: Math.floor(os.uptime()),
|
uptime_s: Math.floor(os.uptime()),
|
||||||
cpu_pct: Math.round(cpuUsage),
|
cpu_pct: Math.round(cpuPct),
|
||||||
mem_used_mb: Math.round((total - mem) / 1024 / 1024),
|
mem_used_mb: Math.round((total - mem) / 1024 / 1024),
|
||||||
mem_total_mb: Math.round(total / 1024 / 1024),
|
mem_total_mb: Math.round(total / 1024 / 1024),
|
||||||
active_sessions: wss.clients ? wss.clients.size : 0,
|
active_sessions: wss.clients ? wss.clients.size : 0,
|
||||||
|
|
@ -64,6 +75,7 @@ app.get('/api/health', (req, res) => {
|
||||||
platform: os.platform(),
|
platform: os.platform(),
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tailscale証明書を自動検出
|
// Tailscale証明書を自動検出
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue