NodeJS -> Мониторинг состояния ПК - Сервера

Пример скрипта для Мониторинга ПК, ноутбука или сервера. Для сбора данных нам понадобится пакет NodeJS под названием systeminformation.

Что нам потребуется:

  • Операционная система: Любая ОС, в примере используется Debian.
  • Программы:
    • Nano — консольный текстовый редактор.
    • cURL — программа командной строки для работы с HTTP.
    • cron — демон, для периодического выполнения заданий.
    • NodeJS — серверная платформа для работы с JavaScript через движок V8.
    • systeminformation — пакет NodeJS для получения данных с ПК.

Добавление и настройка устройства:

  1. Добавим новое устройство в VizIoT с именем «VizIoTSystemInfo».
  2. В «Основных настройках» устройства скопируем Ключ доступа и Пароль доступа.

Установка NodeJS:

Смотрите в «документацию NodeJS». Стандартная установка для Ubuntu или Debian:

# Using Ubuntu
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
# Using Debian, as root
curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
apt-get install -y nodejs

Создание программы на NodeJS.

Программа будет получать данные от пакета systeminformation, собирать в пакет и отправлять его на сервер VizIoT каждые 15 секунд:

Создадим директорию:

mkdir /var/viziot/
mkdir /var/viziot/VizIoTSystemInfo

Перейдем в директорию:

cd /var/viziot/VizIoTSystemInfo

Создадим NodeJS проект:

npm init

Установим пакеты для работы:

  • systeminformation (https://github.com/sebhildebrandt/systeminformation) - пакет для сбора информации с ПК, ноутбука или сервера с операционными системами: Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, SunOS;
    npm install systeminformation --save
  • viziot-mqtt-client-nodejs (https://www.npmjs.com/package/viziot-mqtt-client-nodejs) - модуль позволяет быстро и легко отправлять данные на сервер VizIoT по протоколу MQTT:
    npm install viziot-mqtt-client-nodejs --save

Создадим файл скрипта:

nano ./index.js

Содержание скрипта:

'use strict';
//#ключ и пароль доступа VizIoT
let keyDevice = "_______________";
let passDevice = "_____________________";
let idIntervalSend = 0;
let viziotMQTT = require('viziot-mqtt-client-nodejs');
let viziotMQTTClient = new viziotMQTT(keyDevice, passDevice);
viziotMQTTClient.connect(function () {
	clearInterval(idIntervalSend);
	idIntervalSend = setInterval(function () {
		getPacketAndSendToServer();
	}, 15000);
});

//https://github.com/sebhildebrandt/systeminformation
const si = require('systeminformation');
console.log("systeminformation version", si.version());

//TODO Укажите сетевой интерфейс для мониторинга сетевого трафика
let networkInterface = "Ethernet 5";
//для просмотра всех сетевых интерфейсов
// si.networkInterfaces(function(data){console.log(data); })

//необходимо при старте программы один раз прочитывать статус сетевого интерфейса для того была начальная точка отсчета, если это не делать, то первые данные будут нулевые
if(networkInterface != null && networkInterface.length > 0){
	si.networkStats(networkInterface, function(data) {});
}

//настроим какие параметры мы хотим мониторить
let listGetData = {
	'currentLoadCPU' : true,
	'currentLoadCPUCore' : false,
	'memRAMTotal_Gb' : false,
	'memRAMUsed_Gb' : true,
	'memRAMFree_Gb' : true,
	'memRAMUsed_Percent' : true,
	'memRAMFree_Percent' : true,
	'logicDiskTotal_Gb' : false,
	'logicDiskUsed_Gb' : true,
	'logicDiskFree_Gb' : true,
	'logicDiskUsed_Percent' : true,
	'logicDiskFree_Percent' : true,
	'countProcesses' : true,
	'mostActiveProcesses' : true, //укажите минимальную нагрузку приложением на CPU в процентах, чтобы отслеживать приложение которые сильно загрузили CPU
	'networkStatsInterface' : true,
	'time' : true,
	'uptimeDays' : true,
	'countUsers' : true,
	'countOnlineUsers' : true,
	'cpuTemperature' : true,
	'battery' : true,
};
let maxCPUUsed = 50; // разрешенный диапазон от 10 до 100. Если вы поставите 1, то программа будет отслеживать почти все процессы в ПК
let maxMEMUsed = 50; // разрешенный диапазон от 10 до 100. Если вы поставите 1, то программа будет отслеживать почти все процессы в ПК

//подсчитываем сколько нужно получить результатов от пакета systeminformation для отправки на сервер VizIoT.
let countResultsForSendPacket = 0;
for(let key in listGetData){
	if(listGetData[key] == true){
		countResultsForSendPacket++;
	}
}

function getRoundData(data, digits){
	if (data == undefined){
		return undefined;
	}
	if (digits == undefined){
		digits = 2;
	}
	return +(data).toFixed(digits);
}
function sendPacketToServer(packet, countResults) {
	if(countResults == countResultsForSendPacket){
		viziotMQTTClient.sendDataToVizIoT(packet, function (err) {
			if (err) {
				console.log("publish", err);
			}
		});
	}
}
function getPacketAndSendToServer() {
	let packet ={};
	let countResults = 0;
	let timePC = si.time();

	if(listGetData['currentLoadCPU'] || listGetData['currentLoadCPUCore'] ){
		si.currentLoad(function(data) {
			if(listGetData['currentLoadCPU']){
				packet.loadCPU = getRoundData(data.currentload);
				packet.loadUserCPU = getRoundData(data.currentloadUser);
				packet.loadSystemCPU = getRoundData(data.currentloadSystem);
				countResults++;
			}
			if(listGetData['currentLoadCPUCore']){
				for (let jj = 0; jj < data.cpus.length; jj++) {
					let core = data.cpus[jj];
					packet["loadCore" + jj] = getRoundData(core.load);
					packet["loadUserCore" + jj] = getRoundData(core.loadUser);
					packet["loadSystemCore" + jj] = getRoundData(core.loadSystem);
				}
				countResults++;
			}
			sendPacketToServer(packet, countResults);
		});
	}
	if(listGetData['memRAMTotal_Gb'] || listGetData['memRAMUsed_Gb'] || listGetData['memRAMFree_Gb'] || listGetData['memRAMUsed_Percent'] || listGetData['memRAMFree_Percent']){
		si.mem(function(data) {
			if(listGetData['memRAMTotal_Gb']){
				packet.memRAMTotal_Gb = getRoundData(data.total/1073741824);
				countResults++;
			}
			if(listGetData['memRAMUsed_Gb']){
				packet.memRAMUsed_Gb = getRoundData(data.used/1073741824);
				countResults++;
			}
			if(listGetData['memRAMFree_Gb']){
				packet.memRAMFree_Gb = getRoundData(data.free/1073741824);
				countResults++;
			}
			if(listGetData['memRAMUsed_Percent']){
				packet.memRAMUsed_Percent = getRoundData(data.used / data.total * 100);
				countResults++;
			}
			if(listGetData['memRAMFree_Percent']){
				packet.memRAMFree_Percent = getRoundData(data.free / data.total * 100);
				countResults++;
			}
			sendPacketToServer(packet, countResults);
		});
	}
	if(listGetData['logicDiskTotal_Gb'] || listGetData['logicDiskUsed_Gb'] || listGetData['logicDiskFree_Gb'] || listGetData['logicDiskUsed_Percent'] || listGetData['logicDiskFree_Percent']){
		si.fsSize(function(data) {
			if(listGetData['logicDiskTotal_Gb']){
				for (let jj = 0; jj < data.length; jj++) {
					let disc = data[jj];
					if(disc.type != undefined){
						let discName = disc.fs.replace(/\W/g, '');
						packet["logicDisk" + discName + "Total_Gb"] = getRoundData(disc.size/1073741824);
					}
				}
				countResults++;
			}
			if(listGetData['logicDiskUsed_Gb']){
				for (let jj = 0; jj < data.length; jj++) {
					let disc = data[jj];
					if(disc.type != undefined){
						let discName = disc.fs.replace(/\W/g, '');
						packet["logicDisk" + discName + "Used_Gb"] = getRoundData(disc.used/1073741824);
					}
				}
				countResults++;
			}
			if(listGetData['logicDiskFree_Gb']){
				for (let jj = 0; jj < data.length; jj++) {
					let disc = data[jj];
					if(disc.type != undefined){
						let discName = disc.fs.replace(/\W/g, '');
						packet["logicDisk" + discName + "Free_Gb"] = getRoundData((disc.size - disc.used)/1073741824);
					}
				}
				countResults++;
			}
			if(listGetData['logicDiskUsed_Percent']){
				for (let jj = 0; jj < data.length; jj++) {
					let disc = data[jj];
					if(disc.type != undefined){
						let discName = disc.fs.replace(/\W/g, '');
						packet["logicDisk" + discName + "Used_Percent"] = getRoundData(disc.use);
					}
				}
				countResults++;
			}
			if(listGetData['logicDiskFree_Percent']){
				for (let jj = 0; jj < data.length; jj++) {
					let disc = data[jj];
					if(disc.type != undefined){
						let discName = disc.fs.replace(/\W/g, '');
						packet["logicDisk" + discName + "Free_Percent"] = getRoundData(100 - disc.use);
					}
				}
				countResults++;
			}
			sendPacketToServer(packet, countResults);
		});
	}
	if(listGetData['countProcesses'] || listGetData['mostActiveProcesses']){
		si.processes(function(data) {
			if(listGetData['countProcesses']){
				packet.countProceses = data.all;
				countResults++;
			}
			if(listGetData['mostActiveProcesses']){
				for (let jj = 0; jj < data.list.length; jj++) {
					let process = data.list[jj];
					let processName = process.name.replace(/\W/g, '');
					if(process.pcpu >= maxCPUUsed || process.pmem >= maxMEMUsed){
						packet["p_" + processName + "_cpu"] = getRoundData(process.pcpu);
						packet["p_" + processName + "_mem"] = getRoundData(process.pmem);
					}
				}
				countResults++;
			}
			sendPacketToServer(packet, countResults);
		});
	}
	if(listGetData['networkStatsInterface']){
		if(networkInterface != undefined && networkInterface.length > 0){
			si.networkStats(networkInterface, function(data) {
				packet.networkReadSpeed = getRoundData(data[0].rx_sec * 8 / 1024 / 1024);
				packet.networkWriteSpeed = getRoundData(data[0].tx_sec * 8 / 1024 / 1024);
				countResults++;
				sendPacketToServer(packet, countResults);
			});
		}else{
			countResults++;
			sendPacketToServer(packet, countResults);
		}
	}
	if(listGetData['time']) {
		packet.date = parseInt(timePC.current / 1000);
		countResults++;
		sendPacketToServer(packet, countResults);
	}
	if(listGetData['uptimeSeconds']){
		packet.uptimeSeconds = getRoundData(timePC.uptime, 3);
		countResults++;
		sendPacketToServer(packet, countResults);
	}
	if(listGetData['uptimeMinutes']){
		packet.uptimeMinutes = getRoundData(timePC.uptime/60, 3);
		countResults++;
		sendPacketToServer(packet, countResults);
	}
	if(listGetData['uptimeHours']){
		packet.uptimeHours = getRoundData(timePC.uptime/3600, 3);
		countResults++;
		sendPacketToServer(packet, countResults);
	}
	if(listGetData['uptimeDays']){
		packet.uptimeDays = getRoundData(timePC.uptime/86400, 3);
		countResults++;
		sendPacketToServer(packet, countResults);
	}
	if(listGetData['countUsers'] || listGetData['countOnlineUsers']){
		si.users(function(data) {
			if(Array.isArray(data)){
				if(listGetData['countUsers']){
					packet.countUsers = data.length;
					countResults++;
				}
				if(listGetData['countOnlineUsers']){
					packet.countOnlineUsers = data.filter(user => user.tty.length > 0).length;
					countResults++;
				}
			}else{
				packet.countUsers = -1;
				packet.countOnlineUsers = -1;
				countResults++;
			}
			sendPacketToServer(packet, countResults);
		});
	}
	if(listGetData['cpuTemperature']){
		si.cpuTemperature(function(data) {
			packet.temperatureCPU = data.main;
			for (let jj = 0; jj < data.cores.length; jj++) {
				packet["temperatureCore" + jj] = data.cores[jj];
			}
			countResults++;
			sendPacketToServer(packet, countResults);
		});
	}
	if(listGetData['battery']){
		si.battery(function(data) {
			if(data.hasbattery ==  true){
				packet.batIsCharg = (data.ischarging == true) ? 1 : 0;
				packet.batMaxCapacit = data.maxcapacity;
				packet.batCapacit = data.currentcapacity;
				packet.batPercent = data.percent;
				packet.batCycleCount = data.cyclecount;
			}
			countResults++;
			sendPacketToServer(packet, countResults);
		});
	}
}

Данный скрипт будем запускать при старте системы. Для этого добавим запись в cron. Запустим редактор cron:

crontab -e

И в самый конец добавим строку, которая будет запускать скрипт «/var/viziot/VizIoTSystemInfo/index.js»:

@reboot node /var/viziot/VizIoTSystemInfo/index.js > /var/viziot/VizIoTSystemInfo/output.txt &
Добавление виджета:
  1. Создадим новую панель с именем «Информация о ПК»
  2. Добавим виджет «CPU»
    1. тип: «График с областями суммирующий»;
    2. устройство: «VizIoTSystemInfo;
    3. параметры: loadUserCPU, loadSystemCPU;
  3. Добавим виджет «RAM»
    1. тип: «График с областями суммирующий»;
    2. устройство: «VizIoTSystemInfo;
    3. параметры: memRAMUsed_Gb, memRAMFree_Gb;
  4. Добавим виджет «Disk C»
    1. тип: «График с областями суммирующий»;
    2. устройство: «VizIoTSystemInfo;
    3. параметры: logicDiskCUsed_Gb, logicDiskCFree_Gb;
  5. Добавим виджет «Скорость Интернета»
    1. тип: «График с областями»;
    2. устройство: «VizIoTSystemInfo;
    3. параметры: networkReadSpeed, networkWriteSpeed;
  6. Теперь все настроено - можно наблюдать за состоянием ПК.