initial commit

This commit is contained in:
WeeXnes 2025-06-16 01:11:24 +02:00
commit f19370a802
7 changed files with 430 additions and 0 deletions

25
package.json Normal file
View file

@ -0,0 +1,25 @@
{
"name": "prometheus-node-exporter",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"scripts": {
"build": "tsc",
"start": "node dist/dev.js",
"dev": "ts-node src/dev.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@types/node": "^24.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.8.3"
},
"dependencies": {
"axios": "^1.10.0"
}
}

16
src/config.ts Normal file
View file

@ -0,0 +1,16 @@
export let urlEndpoint: string;
export let urlPath: string = "/api/v1/query";
export function setUrlEndpoint(url: string) {
urlEndpoint = url;
}
export function checkEndpoint() {
if(!urlEndpoint){
console.log('URL endpoint isnt set, use setUrlEndpoint(<url>) to set the url endpoint.');
process.exit(1);
}
}

178
src/cpu.ts Normal file
View file

@ -0,0 +1,178 @@
import axios from 'axios';
import {checkEndpoint, urlEndpoint, urlPath} from "./config";
export class CPU {
/**
* Retrieves the number of logical CPU cores on the system.
*
* Uses the `node_cpu_seconds_total` metric grouped by `cpu` label.
*
* @returns {Promise<number | null>} The number of logical CPUs, or null if unavailable.
*/
static async getLogicalCpuCount(): Promise<number | null> {
checkEndpoint();
try {
const query = 'count(count by (cpu) (node_cpu_seconds_total))';
const response = await axios.get(`${urlEndpoint}${urlPath}`, { params: { query } });
const result = response.data.data.result;
if (!result || result.length === 0) return null;
return parseInt(result[0].value[1], 10);
} catch (error) {
console.error('Failed to fetch logical CPU count:', (error as Error).message);
return null;
}
}
/**
* Calculates the average CPU load (usage) as a percentage over a 1-minute rate window.
*
* Uses the `node_cpu_seconds_total` metric, subtracting idle time.
*
* @returns {Promise<number | null>} CPU load percentage (0100), or null if unavailable.
*/
static async getCpuLoad(): Promise<number | null> {
checkEndpoint()
try {
const response = await axios.get(`${urlEndpoint}${urlPath}`, {
params: {
query: `100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[1m])) * 100)`
}
});
const result = response.data.data.result;
if (result.length === 0) return null;
const load = parseFloat(result[0].value[1]);
return load;
} catch (err) {
console.error('Error querying Prometheus:', (err as Error).message);
return null;
}
}
/**
* Retrieves the average CPU temperature in Celsius.
*
* Uses the `node_hwmon_temp_celsius` metric.
*
* @returns {Promise<number | null>} The average CPU temperature in °C, or null if unavailable.
*/
static async getAverageTemp(): Promise<number | null> {
checkEndpoint();
try {
const promQuery = 'avg(node_hwmon_temp_celsius)';
const response = await axios.get(`${urlEndpoint}${urlPath}`, {
params: { query: promQuery }
});
const result = response.data.data.result;
if (!result || result.length === 0) {
console.warn('No CPU temperature data found in Prometheus');
return null;
}
const avgTempStr = result[0].value[1];
const avgTemp = parseFloat(avgTempStr);
if (isNaN(avgTemp)) return null;
return parseFloat(avgTemp.toFixed(1));
} catch (error) {
console.error('Failed to fetch CPU temperatures from Prometheus:', (error as Error).message);
return null;
}
}
/**
* Retrieves the average minimum CPU clock speed in GHz.
*
* Uses the `node_cpu_scaling_frequency_min_hertz` metric.
*
* @returns {Promise<number | null>} The average minimum CPU clock in GHz, or null if unavailable.
*/
static async getMinCpuClockGHz(): Promise<number | null> {
checkEndpoint();
try {
const query = 'avg(node_cpu_scaling_frequency_min_hertz)';
const response = await axios.get(`${urlEndpoint}${urlPath}`, {
params: { query }
});
const result = response.data.data.result;
if (!result || result.length === 0) {
console.warn('No min CPU frequency data found in Prometheus');
return null;
}
const freqGHz = parseFloat(result[0].value[1]) / 1_000_000_000;
return parseFloat(freqGHz.toFixed(2));
} catch (error) {
console.error('Failed to fetch min CPU frequency from Prometheus:', (error as Error).message);
return null;
}
}
/**
* Retrieves the average maximum CPU clock speed in GHz.
*
* Uses the `node_cpu_scaling_frequency_max_hertz` metric.
*
* @returns {Promise<number | null>} The average maximum CPU clock in GHz, or null if unavailable.
*/
static async getMaxCpuClockGHz(): Promise<number | null> {
checkEndpoint();
try {
const query = 'avg(node_cpu_scaling_frequency_max_hertz)';
const response = await axios.get(`${urlEndpoint}${urlPath}`, {
params: { query }
});
const result = response.data.data.result;
if (!result || result.length === 0) {
console.warn('No max CPU frequency data found in Prometheus');
return null;
}
const freqGHz = parseFloat(result[0].value[1]) / 1_000_000_000;
return parseFloat(freqGHz.toFixed(2));
} catch (error) {
console.error('Failed to fetch max CPU frequency from Prometheus:', (error as Error).message);
return null;
}
}
/**
* Retrieves the average current CPU clock speed in GHz.
*
* Uses the `node_cpu_scaling_frequency_hertz` metric.
*
* @returns {Promise<number | null>} The average current CPU clock in GHz, or null if unavailable.
*/
static async getCurrentCpuClockGHz(): Promise<number | null> {
checkEndpoint();
try {
const query = 'avg(node_cpu_scaling_frequency_hertz)';
const response = await axios.get(`${urlEndpoint}${urlPath}`, {
params: { query }
});
const result = response.data.data.result;
if (!result || result.length === 0) {
console.warn('No current CPU frequency data found in Prometheus');
return null;
}
const freqGHz = parseFloat(result[0].value[1]) / 1_000_000_000;
return parseFloat(freqGHz.toFixed(2));
} catch (error) {
console.error('Failed to fetch current CPU frequency from Prometheus:', (error as Error).message);
return null;
}
}
}

4
src/index.ts Normal file
View file

@ -0,0 +1,4 @@
export { System } from './system'
export { CPU } from './cpu'
export { RAM } from './ram'
export { setUrlEndpoint } from './config';

71
src/ram.ts Normal file
View file

@ -0,0 +1,71 @@
import axios from 'axios';
import {urlEndpoint, checkEndpoint, urlPath} from './config';
export class RAM {
/**
* Retrieves the total system memory in gigabytes.
*
* Queries Prometheus metric `node_memory_MemTotal_bytes` and converts bytes to GB.
*
* @returns {Promise<number | null>} Total memory in GB, or null if unavailable.
*/
static async getTotalMemory(): Promise<number | null> {
checkEndpoint();
try {
const fullUrl = `${urlEndpoint}${urlPath}`;
const query = 'node_memory_MemTotal_bytes';
const response = await axios.get(fullUrl, { params: { query } });
const result = response.data?.data?.result;
if (!result || result.length === 0) {
console.warn('No data for node_memory_MemTotal_bytes');
return null;
}
const totalBytes = parseFloat(result[0].value[1]);
if (isNaN(totalBytes)) return null;
return totalBytes / (1024 ** 3);
} catch (err) {
console.error('Error fetching total memory from Prometheus:', (err as Error).message);
return null;
}
}
/**
* Retrieves the used system memory in gigabytes.
*
* Calculates used memory by subtracting `node_memory_MemAvailable_bytes`
* from `node_memory_MemTotal_bytes` and converts bytes to GB.
*
* @returns {Promise<number | null>} Used memory in GB, or null if unavailable.
*/
static async getUsedMemory(): Promise<number | null> {
checkEndpoint();
try {
const fullUrl = `${urlEndpoint}/api/v1/query`;
const query = 'node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes';
const response = await axios.get(fullUrl, { params: { query } });
const result = response.data?.data?.result;
if (!result || result.length === 0) {
console.warn('No data for used memory query');
return null;
}
const usedBytes = parseFloat(result[0].value[1]);
if (isNaN(usedBytes)) return null;
return usedBytes / (1024 ** 3);
} catch (err) {
console.error('Error fetching used memory from Prometheus:', (err as Error).message);
return null;
}
}
}

124
src/system.ts Normal file
View file

@ -0,0 +1,124 @@
import axios from 'axios';
import { checkEndpoint, urlEndpoint, urlPath } from './config';
export class System {
/**
* Fetches the OS name (sysname) from node_exporter metrics.
*
* @returns {Promise<string | null>} OS name (e.g., "Linux", "Windows_NT") or null if unavailable.
*/
static async getOsName(): Promise<string | null> {
checkEndpoint();
try {
const query = 'node_uname_info';
const response = await axios.get(`${urlEndpoint}${urlPath}`, { params: { query } });
const result = response.data?.data?.result;
if (!result || result.length === 0) return null;
return result[0].metric.sysname ?? null;
} catch (error) {
console.error('Failed to fetch OS name:', (error as Error).message);
return null;
}
}
/**
* Fetches the OS kernel version (release) from node_exporter metrics.
*
* @returns {Promise<string | null>} Kernel version string or null if unavailable.
*/
static async getKernelVersion(): Promise<string | null> {
checkEndpoint();
try {
const query = 'node_uname_info';
const response = await axios.get(`${urlEndpoint}${urlPath}`, { params: { query } });
const result = response.data?.data?.result;
if (!result || result.length === 0) return null;
return result[0].metric.release ?? null;
} catch (error) {
console.error('Failed to fetch kernel version:', (error as Error).message);
return null;
}
}
/**
* Fetches the OS kernel build version info (version) from node_exporter metrics.
*
* @returns {Promise<string | null>} Kernel build version string or null if unavailable.
*/
static async getKernelBuildVersion(): Promise<string | null> {
checkEndpoint();
try {
const query = 'node_uname_info';
const response = await axios.get(`${urlEndpoint}${urlPath}`, { params: { query } });
const result = response.data?.data?.result;
if (!result || result.length === 0) return null;
return result[0].metric.version ?? null;
} catch (error) {
console.error('Failed to fetch kernel build version:', (error as Error).message);
return null;
}
}
/**
* Fetches the machine architecture from node_exporter metrics.
*
* @returns {Promise<string | null>} Machine architecture (e.g., "x86_64") or null if unavailable.
*/
static async getMachineArchitecture(): Promise<string | null> {
checkEndpoint();
try {
const query = 'node_uname_info';
const response = await axios.get(`${urlEndpoint}${urlPath}`, { params: { query } });
const result = response.data?.data?.result;
if (!result || result.length === 0) return null;
return result[0].metric.machine ?? null;
} catch (error) {
console.error('Failed to fetch machine architecture:', (error as Error).message);
return null;
}
}
/**
* Retrieves the system uptime in seconds.
*
* Calculated as the difference between
* `node_time_seconds` and `node_boot_time_seconds` metrics.
*
* @returns {Promise<number | null>} Uptime in seconds, or null if unavailable.
*/
static async getUptimeSeconds(): Promise<number | null> {
checkEndpoint();
try {
const query = 'node_time_seconds - node_boot_time_seconds';
const response = await axios.get(`${urlEndpoint}${urlPath}`, {
params: { query }
});
const result = response.data.data.result;
if (!result || result.length === 0) {
console.warn('No uptime data found in Prometheus');
return null;
}
const uptimeStr = result[0].value[1];
const uptime = parseFloat(uptimeStr);
if (isNaN(uptime)) return null;
return uptime;
} catch (error) {
console.error('Failed to fetch system uptime from Prometheus:', (error as Error).message);
return null;
}
}
}

12
tsconfig.json Normal file
View file

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"declaration": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}