Рассматриваться будет работа на Ubuntu Server. Под другие nix-системы тоже должно работать, но, возможно, с доработками. Windows серверы не рассматриваются вовсе.
Все решения сделаны «в лоб», без изысков и фанатичной минимализации/оптимизации. Я использовал jQuery для того, чтобы получить json посредством Ajax, и вывести его на страницу. Примеры простые, и могут быть переделаны под любой другой способ передачи/вывода.
1. Загрузка CPU
Начнем с самого сложного. Сложного потому, что мне не сразу удалось найти способ получения информации о загрузке процессора, а впоследствии, и не сразу найти способ ее обрабатывать. Первой мыслью была «использовать
exec(»top -n 1")", однако top не писал в стандартный вывод, а сохранение его (вывод) в файл на диск через '>', приводило к появлению огромного количества 'мусора', что сильно затрудняло последующий парсинг. В итоге, все свелось к чтению нужных файлов в виртуальной файловой системе, подключенной в
/proc. Файл, в котором хранится информация о текущем использовании процессора называется /proc/stat. По сути, это не файл, а точка доступа к структурам данных ядра, но нам это знать не обязательно, потому что нам будет достаточно прочитать содержимое, а сделать это можно, как и в случае с простым файлом, через
file(). Теперь можно привести кусочек кода, который эту информацию достает. После него я объясню, что было сделано, и зачем.
$file=file("/proc/stat");
$tmp=explode(" ",$file[0]);
$cpu1=$this->session->userdata("cpu1");
$cpu2=$this->session->userdata("cpu2");
$cpu3=$this->session->userdata("cpu3");
$cpu4=$this->session->userdata("cpu4");
$cpu=(100/($tmp[5]-$cpu4))/(($tmp[2]-$cpu1)+($tmp[3]-$cpu2)+($tmp[4]-$cpu3))*100;
$this->session->set_userdata(array("cpu1"=>$tmp[2],"cpu2"=>$tmp[3],"cpu3"=>$tmp[4],"cpu4"=>$tmp[5]));
Объяснение начнем с содержимого файла:
> cat /proc/stat
cpu 2255 34 2290 22625563 6290 127 456 0 0
cpu0 1132 34 1441 11311718 3675 127 438 0 0
cpu1 1123 0 849 11313845 2614 0 18 0 0
intr 114930548 113199788 3 0 5 263 0 4 [... еще куча цифр ...]
...
В первой строчке /proc/stat содержится информация о количестве потраченного процессором времени (усредненное для всех ядер/потоков) на выполнение (по порядку): процессов пользователя, высокоприоритетных процессов пользователя, системных процессов, простоя, ожидания ввода/вывода, аппаратных и программных прерываний. В следующих строках, начинающихся на 'cpu', приведены те же данные для каждого ядра/потока в отдельности. В нашем случае вся интересующая информация содержится в первой строке, поэтому дальше разбирать файл не будем.
В приведенном кусочке кода так же есть сохранение этих данных в сессию
CodeIgniter. Это сделано для того, чтобы определять разницу (дельту) между текущими и предыдущими значениями показателей. Загрузка процессора представляет собой отношение дельты простоя к сумме дельт затрат на процессы. Другими словами, мы сравниваем количество простоя и работы с момента последнего запроса. Естественно, чем реже будут происходить эти запросы, тем сильнее будет усреднено значение загрузки процессора за это время.
2. Оперативная память
Информацию о количестве свободной оперативной памяти можно найти в файле /proc/meminfo:
> cat /proc/meminfo
MemTotal: 2052604 kB
MemFree: 246012 kB
Buffers: 792332 kB
Cached: 584716 kB
...
Отсюда мы будем брать две первые строчки, и извлекать из них цифры:
$file=file("/proc/meminfo");
$memory["total"]=substr($file[0],strpos($file[0]," "),strrpos($file[0]," ")-strpos($file[0]," "));
$memory["free"]=substr($file[1],strpos($file[1]," "),strrpos($file[1]," ")-strpos($file[1]," "));
Этот и последующие кусочки кода будут проще первого, и обширные пояснения им не потребуются. Здесь, например, все очевидно — мы просто «вырезаем» число, расположенное между двумя пробелами, для первой и второй строчки соответственно.
3. Swap file
Тут еще проще — берем строчку из /proc/swaps:
> cat /proc/swaps
Filename Type Size Used Priority
/dev/sda1 partition 7811064 2732 -1
...
В нем перечислены все подключенные своп-файлы, их типы, объемы и занятое место. Нам просто надо «выдернуть» нужные цифры из нужных строк. В моем случае своп один, и строчку я обрабатываю одну:
$file=file("/proc/swaps");
$tmp=explode("\t",substr($file[1],strpos($file[1],"partition")));
$swap["total"]=$tmp[1];
$swap["free"]=$tmp[1]-$tmp[2];
Здесь пояснения тоже не нужны.
4. Жесткие диски
В моем примере будет приведен код, который извлекает информацию о количестве свободного места на дисках, точки монтирования которых находятся в /mnt. Ухищрения типа чтения и парсинга файлов из /proc здесь использовать не будут — для этой цели достаточно стандартных
disk_free_space() и
disk_total_space():
$drives=array();
if($dir=opendir("/mnt")){
while(false !== ($file = readdir($dir))) {
$arr=array();
if(($file!=".")&&($file!="..")){
$arr["path"]="/mnt/".$file;
$arr["free"]=disk_free_space("/mnt/".$file);
$arr["total"]=disk_total_space("/mnt/".$file);
$drives[]=$arr;
}
}
}
5. Uptime
В качестве небольшого бонуса получим и продолжительность работы системы с последнего запуска:
$uptime=exec("uptime");
$uptime=explode(",",substr($uptime,strpos($uptime,"up")+3));
$time=explode(":",$uptime[1]);
$uptime=$uptime[0]." ".$time[0]." hours ".$time[1]." minutes";
Совсем банальный подход — вызов exec(), и форматирование результата.
Вывод
Мы смогли получить всю интересующую нас информацию — о заполненности жестких дисков, о загрузке процессора, о состоянии памяти и свопа и даже о продолжительности работы сервера. Как выводить эту информацию, каждый может придумать сам, в зависимости от требований. Я же поделюсь способом, который использую сам.
Сперва я собираю полученные данные в ассоциативный массив и вывожу его как json:
$result["cpu"]=$cpu;
$result["memory"]=$memory;
$result["swap"]=$swap;
$result["uptime"]=$uptime;
json_encode($result);
На выходе получается следующее:
{"uptime":"34 days 5 hours 45 minutes","cpu":1.7361111111111,"memory":{"total":"2052604","free":"191424"},"swap":{"total":"7811064","free":7808332}}
И, уже в браузере, я работаю с результатом при помощи jQuery:
var json=$.parseJSON(data);
$("#systemInfo").html("CPU: "+json.cpu+"<br />Memory free "+json.memory.free+" / "+json.memory.total);