mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 23:24:52 +09:00
173 lines
4.8 KiB
TypeScript
173 lines
4.8 KiB
TypeScript
import fs from "fs-extra";
|
|
import os from "os";
|
|
import util from "util";
|
|
import { Gauge } from "./prometheus";
|
|
import { SystemInfo } from "./data";
|
|
|
|
function filterCpuModel() {
|
|
const model = os.cpus()[0].model;
|
|
// Remove irelevant clutter
|
|
return model
|
|
.replace(/\(R\)/gi, "®") // Intel CPUs use (R) instead of ®
|
|
.replace(/\(TM\)/gi, "™") // Intel and AMD CPUs use (TM) instead of ™
|
|
.replace(/ CPU /, " ") // Intel CPUs add redundant "CPU" in the model.
|
|
.replace(/ @ [0-9]+\.[0-9]+GHz/, "") // Intel CPUs add GHz after the model.
|
|
.replace(/ (Dual|Quad|Six|[0-9]+)-Core Processor/, "") // AMD CPUs add cores after the model.
|
|
.trim() // AMD CPUs may have trailing spaces in the model.
|
|
;
|
|
}
|
|
const cpuModel = filterCpuModel();
|
|
|
|
export const systemInfo = new Gauge(
|
|
"system_info",
|
|
"Static info about the system.",
|
|
{
|
|
labels: ["kernel", "machine", "cpu_model", "hostname", "node"],
|
|
}
|
|
);
|
|
systemInfo.labels({
|
|
"kernel": os.type(),
|
|
"machine": os.machine(),
|
|
"cpu_model": cpuModel,
|
|
"hostname": os.hostname(),
|
|
"node": process.version,
|
|
}).set(1);
|
|
|
|
export const systemCpuSecondsTotal = new Gauge(
|
|
"system_cpu_seconds_total",
|
|
"Total system CPU time spent in seconds.",
|
|
{
|
|
labels: ["core"],
|
|
callback: function(collector) {
|
|
const cpus = os.cpus();
|
|
for (let i = 0; i < cpus.length; i++) {
|
|
const times = cpus[i].times;
|
|
collector.labels(String(i)).set(
|
|
(times.user + times.idle + times.irq + times.nice + times.sys) / 1000
|
|
);
|
|
}
|
|
},
|
|
},
|
|
);
|
|
|
|
export const systemCpuIdleSecondsTotal = new Gauge(
|
|
"system_cpu_idle_seconds_total",
|
|
"Total system CPU time spent being idle in seconds.",
|
|
{
|
|
labels: ["core"],
|
|
callback: function(collector) {
|
|
const cpus = os.cpus();
|
|
for (let i = 0; i < cpus.length; i++) {
|
|
const times = cpus[i].times;
|
|
collector.labels(String(i)).set(
|
|
times.idle / 1000
|
|
);
|
|
}
|
|
},
|
|
},
|
|
);
|
|
|
|
export const systemMemoryCapacityBytes = new Gauge(
|
|
"system_memory_capacity_bytes",
|
|
"Total system memory installed",
|
|
{
|
|
callback: function(collector) {
|
|
collector.set(os.totalmem());
|
|
},
|
|
},
|
|
);
|
|
|
|
export const systemMemoryAvailableBytes = new Gauge(
|
|
"system_memory_available_bytes",
|
|
"Total system memory available for use",
|
|
{
|
|
callback: function(collector) {
|
|
collector.set(os.freemem());
|
|
},
|
|
},
|
|
);
|
|
|
|
export const systemDiskCapacityBytes = new Gauge(
|
|
"system_disk_capacity_bytes",
|
|
"Size of the filesystem of the current working directory Node.js runs on",
|
|
{
|
|
callback: async function(collector) {
|
|
// statfs was added in Node.js v18.15.0 and may not be present.
|
|
// TODO: remove this check once minimum supported Node.js >= v18.15.0.
|
|
if (!fs.statfs) {
|
|
collector.set(0);
|
|
return;
|
|
}
|
|
const statFsAsync = util.promisify(fs.statfs);
|
|
const stats = await statFsAsync(".");
|
|
collector.set(stats.blocks * stats.bsize);
|
|
},
|
|
},
|
|
);
|
|
|
|
export const systemDiskAvailableBytes = new Gauge(
|
|
"system_disk_available_bytes",
|
|
"Available space on the filesystem of the current working directory Node.js runs on",
|
|
{
|
|
callback: async function(collector) {
|
|
// TODO: remove this check once minimum supported Node.js >= v18.15.0.
|
|
if (!fs.statfs) {
|
|
collector.set(0);
|
|
return;
|
|
}
|
|
const statFsAsync = util.promisify(fs.statfs);
|
|
const stats = await statFsAsync(".");
|
|
collector.set(stats.bavail * stats.bsize);
|
|
},
|
|
},
|
|
);
|
|
|
|
function minZip<T>(a: T[], b: T[]): [T, T][] {
|
|
const length = Math.min(a.length, b.length);
|
|
const result = [];
|
|
result.length = length;
|
|
for (let i = 0; i < length; i++) {
|
|
result[i] = [a[i], b[i]] as [T, T];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
let previousTotalCpuMs: number[] = [];
|
|
let previousIdleCpuMs: number[] = [];
|
|
export async function gatherSystemInfo(id: SystemInfo["id"], canRestart: boolean, restartRequired: boolean) {
|
|
const cpus = os.cpus();
|
|
const currentTotalCpuMs = cpus.map(({ times }) => times.user + times.idle + times.irq + times.nice + times.sys);
|
|
const currentIdleCpuMs = cpus.map(({ times }) => times.idle);
|
|
const deltaTotalCpuMs = minZip(previousTotalCpuMs, currentTotalCpuMs).map(([prev, curr]) => curr - prev);
|
|
const deltaIdleCpuMs = minZip(previousIdleCpuMs, currentIdleCpuMs).map(([prev, curr]) => curr - prev);
|
|
const cpuUsage = minZip(deltaTotalCpuMs, deltaIdleCpuMs).map(([total, idle]) => (total - idle) / total);
|
|
previousTotalCpuMs = currentTotalCpuMs;
|
|
previousIdleCpuMs = currentIdleCpuMs;
|
|
let diskCapacity = 0;
|
|
let diskAvailable = 0;
|
|
if (fs.statfs) { // TODO: remove this check once minimum supported Node.js >= v18.15.0.
|
|
const statFsAsync = util.promisify(fs.statfs);
|
|
const stats = await statFsAsync(".");
|
|
diskCapacity = stats.blocks * stats.bsize;
|
|
diskAvailable = stats.bavail * stats.bsize;
|
|
}
|
|
|
|
return new SystemInfo(
|
|
id,
|
|
os.hostname(),
|
|
process.version,
|
|
os.type(),
|
|
os.machine(),
|
|
cpuModel,
|
|
cpuUsage,
|
|
os.totalmem(),
|
|
os.freemem(),
|
|
diskCapacity,
|
|
diskAvailable,
|
|
canRestart,
|
|
restartRequired,
|
|
Date.now(),
|
|
false,
|
|
);
|
|
}
|