У попередній статті ми створили базову структуру нашого плагіна. Тепер настав час реалізувати клас виводу для кожного з наших віджетів:

Нагадаємо, що всі провайдери віджетів повинні реалізовувати інтерфейс Provider. Вони також повинні розміщуватися всередині папки widget і в просторі імен AXStatBoardWidget.

Якщо ми хочемо додати новий вид метрики, то просто створюємо відповідний клас, а також об’єкт і додаємо його в клас Widget з методом add_provider.

Віджет використання оперативної пам’яті

Одним з перших видів інформації, яку ми хочемо показати, є те, яка частина оперативної пам’яті в даний час використовується і скільки пам’яті зараз не задіяно.

У цьому випадку нам допоможе free -m — таким чином, ми отримаємо дані про використання оперативної пам’яті. Перемикач -m задається для виведення результатів в мегабайтах:

[[email protected] ~]$ free -m
total used free shared buffers cached
Mem: 589 366 223 0 9 57
-/+ buffers/cache: 299 290
Swap: 0 0 0

Ми назвемо цей клас Ram. Відповідний йому файл — widget/ram.php. Ми просто додаємо в нього основу і реалізуємо get_title:

Далі, ми реалізуємо get_metric, щоб власне запустити необхідну команду shell і витягнути інформацію. Більш детально про get_metric я розповім трохи пізніше:

(int)$segment[1],
‘used’ => (int)$segment[2],
‘free’ => (int)$segment[3],
);
}, $df );
return $df;
}
return false;
}
?>

Ми виконуємо команду free -m | grep -E «Mem|Swap» | awk ‘{print $1, $2, $3, $4}’. Її результат виглядає приблизно так:

[[email protected] ~]$ free -m | grep -E «Mem|Swap» | awk ‘{print $1, $2, $3, $4}’
Mem: 589 541 47
Swap: 255 255 0
[[email protected] ~]$

Ми розбираємо кожен біт інформації за допомогою PHP шляхом поділу рядків в масив. Ми використовуємо array_map, щоб обробити через цикл всі елементи масиву і кожну рядок ми розбиваємо пробілами, потім повертаємо асоційований масив з елементами:

  • type: перше поле;
  • total: друге поле;
  • used: третє поле;
  • free: четверте поле.

Тепер настав час застосувати get_content:

public function get_content() {
$metric = $this->get_metric();
$data = array(
array(‘Type’, ‘Used(MB)’, ‘Free(MB)’)
);
foreach ($metric as $item) {
if (empty($item)) {
continue;
}
if ($item[‘type’] !== ‘Mem’ && $item[‘type’] !== ‘Swap’) {
continue;
}
if ( 0 == ($item[‘free’] + $item[‘used’])) {
continue;
}
$data[] = array(
$item[‘type’],$item[‘used’], $item[‘free’]
);
}
$data = json_encode($data);
echo <<Ми використовували столбчатую діаграму для відображення даних по використанню оперативної пам’яті.

Спочатку ми викликаємо get_metric(), щоб отримати необхідні дані. Після цього ми просто пропускаємо їх через цикл, щоб відформатувати дані у відповідності з вимогами діаграм Google.

Нарешті, ми використовуємо json_encode, щоб перетворити їх в об’єкт анотації JavaScript (або JSON). Після цього виводимо HTML-код, що містить елемент div для зберігання об’єкта діаграми.

В кінці ми викликаємо відповідне Google Chart API для візуалізації діаграми з цього елемента div:

Висновок віджета інформації про сервер в консолі WordPress

Віджет використання ОЗУ показує інформацію з фізичної пам’яті і файлу підкачки

Встановлене програмне забезпечення

Другий віджет, який ми розглянемо, буде відображати інформацію щодо встановленого програмного забезпечення. Його завдання — вивести дані про те, який прикладний пакет встановлений у нас на сервері і його версію.

Наприклад, встановлено у нас NodeJS, встановлений Ruby? Яку версію PHP ми використовуємо? І так далі.

Давайте створимо файл widget/software.php з таким вихідним вмістом:

‘-v’,
‘node’ => ‘-v’,
‘mysql’ => ‘-V’,
‘vim’ => ‘—version’,
‘python’ => ‘-V’,
‘рубін’ => ‘-v’,
‘java’ => ‘-version’,
‘curl’ => ‘-V’);
foreach ( $package as $cmd=>$version_query ) {
if ( NULL == $cmds[$cmd] = shell_exec( «which $cmd» ) ) {
$cmds[ $cmd ] = ‘Not installed’;
continue;
}
$version = shell_exec( «$cmd $version_query» );
$version = explode( «n», $version );
if ( is_array( $version ) ) {
$version = array_shift( $version );
}
$cmds[ $cmd ] .= ‘
‘. $version;
}
return $cmds;
}

Як і раніше, у нас є метод get_title, і він лише повертає просту рядок. Для get_metric(), нам необхідно знати, встановлена на сервері конкретна програма чи ні. Якщо це так, то отримати інформацію про її версії.

Для цього ми створюємо масив команд за допомогою перемикача, який показує версію програмного забезпечення. Наприклад, для PHP, php -v показує інформацію про версію пакету, mysql —version показує інформацію про версії MySQL.

shell_exec повертає false, якщо команда повертає помилку або команда не знайдено. У цьому випадку, ми знаємо, що програмне забезпечення не встановлено; у іншому випадку, ми можемо розібрати результат, щоб вивести інформацію про версію.

Після цього ми розбиваємо результат рядок за рядком, і отримуємо перший рядок у якості інформації про версії. Інформація, яка нам потрібна, повинна міститися тільки в першому рядку.

Для інших додатків, деякі команди достатньо складні і містять багато інформації. Після того, як ми отримаємо дані, ми створюємо метод get_content:

public function get_content() {
$cmds = $this->get_metric();
$content = «;
foreach ( $cmds as $cmd => $info ) {
$content .= «

$cmd $info

«;
}
echo $content;
}

Ми просто виводимо базову таблицю для цього типу даних. Ось приклад даних, що виводяться в консолі:

Висновок віджета інформації про сервер в консолі WordPress

Віджет показує інформацію щодо встановленого програмного забезпечення

Використання дискового простору

Тепер ми займемося використанням дискового простору. Ми називаємо клас, який обробляє цю задачу Disk. Давайте спочатку розробимо базову структуру:

Як завжди, ми повинні реалізувати інтерфейс Provider. Тут ми встановлюємо заголовок нашого віджета. Далі слід серці нашого класу: метод отримання даних про використання дискового простору:

=2) {
array_shift($df); //Get rid the first line
$df = array_map(function ($line) {
if (empty($line)) {
return NULL;
}
$segment=preg_split(‘/s+/’, $line);
return array(
‘filesystem’ => $segment[0],
‘size’ => $segment[1],
‘used’ => $segment[2],
‘available’ => $segment[3],
‘use_percent’ => $segment[4],
);
}, $df);
return $df;
}
return false;
}

У першій частині цієї серії, ми отримали деяке уявлення про df, тому вам повинно бути не складно розібратися з наведеною нижче командою.

Нагадаємо, результат виконання df виглядає наступним чином:

[[email protected] ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 7.3 G 1.4 G 5.6 G 20% /
tmpfs 295M 0 295M 0% /dev/shm
/vagrant 60G 55G 4.9 G 92% /vagrant
/data/GeoIP 60G 55G 4.9 G 92% /data/GeoIP
/var/webapps 60G 55G 4.9 G 92% /var/webapps
/var/www/html 60G 55G 4.9 G 92% /var/www/html

Розбиваємо його рядок за рядком, щоб перетворити масив. Ми пропускаємо через цикл кожного рядка, відокремлюючи їх пропусками, щоб знову перетворити масив.

Після цього ми просто переводимо значення в асоційований масив з більш зрозумілим, зручним для читання форматі. Коли ми отримали ці дані, ми можемо розмістити їх в get_content:

public function get_content() {
$metric = $this->get_metric();
$data = array(
array( ‘Disk’, ‘Space’ )
);
$disk_container = array();
$data_partition = array(
array(‘Filesystem’, ‘Free(GB)’, ‘Used(GB)’)
);
foreach ( $metric as $disk ) {
$size = intval( $disk[‘size’] );
if ( ‘M’ == substr( $disk[‘size’], -1 ) ) {
$size = round( $size / 1024, 2 );
}
$used = intval( $disk[‘used’] );
if (‘M’ == substr( $disk[‘used’], -1 ) ) {
$used = round( $used / 1024, 2 );
}
if ( empty( $size ) ) {
continue;
}
$data[] = array( $disk[‘filesystem’], $size );
$data_partition[] = array($disk[‘filesystem’], $size — $used, $used);
}
}

Ми пропускаємо через цикл масив метрики, щоб перевести мегабайти в гігабайти. І створюємо масив відповідно до вимог до формату даних діаграми. Масив даних повинен виглядати наступним чином:

[
[‘File System’, ‘Free’, ‘Used’,
[‘/dev/sda1’, 10, 24],
[‘/dev/sda2’, 28, 19]
]

Після того, як ми отримали дані, ми виводимо діаграми. Створюємо дві діаграми:

  • На першій діаграмі буде виводитися частка дискового простору, зайнятого кожної змонтованій файловій системою. Для цих даних, ми будемо використовувати кругову діаграму;
  • Друга діаграма — для відображення обсягу використовуваного кожної змонтованій файловій системою дискового простору. Для цього ми будемо використовувати гістограму.

З цією метою, давайте змінимо наш метод наступним чином:

public function get_content() {
$metric = $this->get_metric();
$data = array(
array(‘Disk’, ‘Space’)
);
$disk_container = array();
$data_partition = array(
array(‘Filesystem’, ‘Free(GB)’, ‘Used(GB)’)
);
foreach ($metric as $disk) {
$size = intval($disk[‘size’]);
if (‘M’ == substr($disk[‘size’], -1)) {
$size = round($size / 1024, 2);
}
$used = intval($disk[‘used’]);
if (‘M’ == substr($disk[‘used’], -1)) {
$used = round($used / 1024, 2);
}
if (empty($size)) {
continue;
}
$data[] = array($disk[‘filesystem’], $size);
$data_partition[] = array($disk[‘filesystem’], $size — $used, $used);
}
$data = json_encode($data);
$data_partition = json_encode($data_partition);
echo <<Ми створили два елемента div для зберігання інформації:

Після цього діаграма буде відображатися усередині цих елементів за допомогою методу вилучення Chart API. Найбільш складною тут є формат даних для нашої діаграми.

Ось як буде виглядати результат:

Висновок віджета інформації про сервер в консолі WordPress

Використання дискового простору

Інформація про сервер

Цей віджет буде виводити наступну інформацію: ядро Linux, архітектура процесора, час роботи, IP-адресу. Для цього нам не потрібна діаграма, простої таблиці даних буде достатньо. Викликається клас буде називатися Server. Для початку вставити в файл widget/server.php наступний код:

diff(new DateTime(«@$total_uptime_sec»))->format(‘%a days, %h hours, %i minutes and %s seconds’);
// Отримання розширеного ip ifconfig.me, сайт, який показує ip-адресу
// відкритим текстом при виконанні запиту з допомогою заголовка curl
$server[‘ip’] = `curl ifconfig.me`;
$server[‘ram’] = `free -m | grep Mem | awk ‘{print $2}»;
$server[‘cpu’] =`cat /proc/cpuinfo | grep «model name» | awk ‘{print $4,$5,$6,$7}»;
return $server;
}
}

До цього моменту, ви вже повинні добре уявляти собі, що робить метод get_title(). Ми просто повертаємо заголовок віджета.

По-перше, ми використовуємо оператор use DateTime, тому що перебуваємо всередині простору імен AXStatBoardWidget, а клас DateTime належить глобального простору імен.

Кожен раз, коли ми хочемо використовувати DateTime ми повинні ввести DateTime. Тому ми використовуємо імпорт простору імен, щоб DateTime були доступні в нашому поточному просторі імен.

Це свого роду посилання. Всередині get_metric ми запускаємо команду оболонки, щоб отримати результат і просто знову його привласнити.

hostname

Виводимо ім’я проксі-сервера.

uname -sr

Виводимо інформацію про ядрі Linux:

[[email protected] ~]$ uname -sr
Linux 2.6.32-358.23.2.el6.x86_64

grep -c ^processor /proc/cpuinfo

Перемикач -c виводить кількість співпадаючих записів у вхідному рядку. /proc/cpuinfo містить інформацію про процесор. Ми виокремлює цю інформацію і підраховуємо кількість ядер. Ось дані мого сервера з 32 ядрами процесора:

$ grep -c ^processor /proc/cpuinfo
32

cut -d. -f1 /proc/uptime

Ця команда показує, скільки секунд працює сервер. Щоб зробити виводяться дані більш зручними для користувачів, ми конвертуємо це кількість секунд у формат «x днів y годин z хвилин«.

З допомогою DateTime::diff ми можемо легко цього досягти. Ми створюємо об’єкт DateTime з поточної тимчасовою міткою, а також ще один об’єкт з відміткою часу дорівнює поточному часу мінус кількість секунд безперервної роботи. Потім, використовуємо метод форматування, щоб перевести результат у більш зручний для користувача форматі.

Ось дані серверу — 26194091 секунд безперервної роботи:

$ cut -d. -f1 /proc/uptime
26194091

curl ifconfig.me

ifconfig.me — це сервіс, який показує ваш IP адреса. Якщо ви відправляєте запит за допомогою curl, він повертає IP-адресу у вигляді одного рядка:

[[email protected] ~]$ curl ifconfig.me
76.102.253.237

Модель процесора

Як зазначалося вище, в /proc/cpuinfo зберігається інформація про процесор. Відповідно, ми можемо витягти модель процесора. Наприклад:

[[email protected] ~]$ cat /proc/cpuinfo | grep «model name» | awk ‘{print $4,$5,$6,$7}’
Intel(R) Core(TM) i5-4250U CPU
Після того, як ми отримали в своє розпорядження масив цих даних, ми повертаємо їх і вставляємо в метод get_content необхідні нам частини. Ось приклад виводу даних get_content:
public function get_content() {
$server = $this->get_metric();
echo <<
CPU {$server[‘cpu’]}
Number of Core {$server[‘core’]}
Ram {$server[‘ram’]}
Hostname {$server[‘hostname’]}
OS {$server[‘os’]}
Uptime {$server[‘uptime’]}
EOD;
}

А ось скріншот відповідного віджета з інформацією:

Висновок віджета інформації про сервер в консолі WordPress
Інформація про сервер

Процесор

Параметри роботи процесора — це одна з найбільш важливих показників, які ми можемо вивести. Ми хочемо знати, яка частина ресурсу процесора задіяна і / або обсяг пам’яті, споживаний конкретним процесом.

Ми називаємо наш клас Process і для початку розміщуємо в ньому методи get_title і get_metric. Більш детально про метод get_metric я розповім нижче:

ps — це команда, яка виводить інформацію про запущених процесах.

Вона надає докладну інформацію про процесор — для цього потрібно встановити перемикач -e, який дозволяє бачити всі процеси. Для нашого віджета, нам потрібні параметри COU, memory, PID, users, args, time і start.

Для виведення даних в більш зрозумілому користувачеві форматі ми можемо поєднати команду з -o: ps -eo pcpu,pmem,pid,user,args,time,start. Якщо ви спробуєте виконати цю команду, то отримаєте деякий набір не дуже зрозумілої інформації про процеси:

[[email protected] ~]$ ps -eo pcpu,pmem,pid,user,args,time,start
%CPU %MEM PID USER COMMAND TIME STARTED
0.0 0.2 1 root /sbin/init 00:00:00 06:50:39
0.0 0.0 2 root [kthreadd] 00:00:00 06:50:39
0.0 0.0 3 root [migration/0] 00:00:00 06:50:39

Зверніть увагу на рядки [kthread], [migration/0]. Як правило, це означає, що команда не прив’язана до файлової системи. Це може бути який-небудь внутрішній системний процес або потік ядра, і нам, можливо, інформація про них не потрібна.

Тому ми повинні прибрати ці процеси з допомогою grep. grep дозволить нам з перемикачем -v прибрати деякі рядки. В результаті ми повертаємо дані, які не містять рядків, переданих в grep:

[[email protected] ~]$ ps -eo pcpu,pmem,pid,user,args,time,start | grep -v ‘[‘
%CPU %MEM PID USER COMMAND TIME STARTED
0.0 0.2 1 root /sbin/init 00:00:00 06:50:39
0.0 0.1 292 root /sbin/udevd -d 00:00:00 06:50:41
0.0 0.1 811 root /sbin/dhclient -H vagrant-c 00:00:00 06:50:48
0.0 0.2 948 root /sbin/rsyslogd -i /var/run/ 00:00:00 06:50:50
0.0 0.1 966 rpc rpcbind 00:00:00 06:50:50
0.0 0.2 984 rpcuser rpc.statd 00:00:00 06:50:50
0.0 0.0 1011 root rpc.idmapd 00:00:00 06:50:51
0.0 0.2 1073 root /usr/sbin/VBoxService 00:00:00 06:50:51

Щоб дані виглядали більш інформативно, нам потрібно відсортувати процеси за критерієм використання пам’яті і ресурсів процесора. В даному випадку, давайте відсортуємо їх за значенням поля %MEM. Це можна зробити за допомогою команди сортування Linux. %MEM — це другий стовпець, його ми використовуємо в якості бази для сортування даних.

Так як масив має нульовий початковий індекс, то доступ до другого елементу здійснюється за ключем індексу 1. Ми можемо використовувати команду sort -k 1. Сортування буде проводитися за зростанням. Однак насправді найбільше нас цікавить процес, який споживає найбільше пам’яті. Тому ми повинні змінити порядок сортування sort -k 1 -r.

Після того, як ми отримали результат, швидше за все, нам будуть цікаві тільки перші 30 процесів. Звичайно, це залежить від вас, ви можете включити їх все, але я виходжу з міркувань розумної достатності. Перших 30 процесів, думаю, буде цілком достатньо.

Нарешті, ми задіємо awk для формування звіту. Нижче наведена команда і зразок виводяться нею даних:

[[email protected] ~]$ ps -eo pcpu,pmem,pid,user,args,time,start | grep -v ‘[‘ | sort -k 1 | head -30 | awk ‘{print $4,$3,$1,$2,$7,$6,$5}’
root 1151 0.0 0.0 00:00:00 -d /sbin/udevd
root 1152 0.0 0.0 00:00:00 -d /sbin/udevd
root 292 0.0 0.0 00:00:00 -d /sbin/udevd
root 811 0.0 0.0 vagrant-c -H /sbin/dhclient
root 1 0.0 0.1 06:50:39 00:00:00 /sbin/init
root 2153 0.0 0.1 -q -1 /sbin/dhclient
root 3642 0.0 0.1 00:00:00 -s /usr/sbin/anacron
vagrant 3808 0.0 0.1 pcpu,pmem,pid,user,a -eo ps
vagrant 3810 0.0 0.1 1 -k sort
vagrant 3811 0.0 0.1 00:00:00 -30 head
vagrant 3812 0.0 0.1 $4,$3,$1,$2,$7,$ {print awk
root 948 0.0 0.1 /var/run/ -i /sbin/rsyslogd
rpc 966 0.0 0.1 06:50:50 00:00:00 rpcbind
root 1073 0.0 0.2 06:50:51 00:00:00 /usr/sbin/VBoxService
root 1105 0.0 0.2 06:50:51 00:00:00 /usr/sbin/sshd
root 1121 0.0 0.2 06:50:52 00:00:00 crond
rpcuser 984 0.0 0.2 06:50:50 00:00:00 rpc.statd
496 1088 0.0 0.3 -p -d memcached
vagrant 3544 0.0 0.3 00:00:00 [email protected]/0 sshd:
vagrant 3545 0.0 0.3 06:59:27 00:00:00 -bash
root 1113 0.0 1.7 06:50:52 00:00:00 /usr/sbin/httpd
apache 1157 0.0 4.2 06:50:53 00:00:01 /usr/sbin/httpd
apache 3438 0.0 4.2 06:55:39 00:00:01 /usr/sbin/httpd

Після того, як ми повернули результати, ми поділяємо їх на масив і цикл з допомогою foreach. Ми групуємо процеси з однаковими іменами в елементи та визначаємо їх частку в завантаженні процесора:

count( $line ) ) {
continue;
}
if ( empty( $processes[ $line[6] ] ) ) {
$processes[ $line[6]] = array_combine( array( ‘user’, ‘pid’, ‘%cpu’, ‘%mem’,’start’,’time’, ‘command’ ), $line );
} else {
$processes[ $line[6] ][‘%cpu’] += $line[2];
$processes[ $line[6] ][‘%mem’] += $line[3];
}
}
//…

Ми використовуємо array_combine для створення об’єднаного масиву з двох інших масивів: ключів і значень.
Тепер нам залишилося лише реалізувати метод get_content.

Просто нагадаю, що ми повинні обов’язково реалізувати три методу: get_title, get_metric і get_content. Для даного параметра нам буде достатньо простої таблиці.

Ось як виглядає наш метод get_content:

public function get_content() {
$processes = $this->get_metric();
$html = ‘

‘;
foreach ($processes as $process) {
$html .= «

«;
}
$html .= ‘

User Pid %CPU %Mem Command
{$process[‘user’]} {$process[‘pid’]} {$process[‘%cpu’]} {$process[‘%mem’]} {$process[‘command’]}

‘;
echo $html;
}

А ось, що ми в результаті отримуємо:

Висновок віджета інформації про сервер в консолі WordPress
Віджет показує, які процеси запущені на сервері, і скільки ресурсів процесора і пам’яті вони споживають

Середня навантаження

В Linux є команда, яка показує середнє завантаження процесора і IO протягом останньої хвилини, 5 і 15 хвилин. Давайте заженемо її в віджет. Назвемо цей віджет Cpuload і створимо файл widget/cpuload.php:

$number_of_core = intval(`/bin/grep -c processor /proc/cpuinfo`);
$loadAvg = `cat /proc/loadavg | /usr/bin/awk ‘{print $1,$2,$3}»;
$loadAvg = explode(‘ ‘, $loadAvg);
if ($loadAvg <3) {
return false;
}
$loadTimes = array(‘1 min’, ‘5 mins’, ’15 mins’);
return array_map(
function ($loadtime, $value, $number_of_core) {
return array($loadtime, round($value * 100 / $number_of_core, 2), $value);
},
$loadTimes,
$loadAvg,
array_fill(0, 3, $number_of_core)
);

}
}

Перше, що ми визначаємо — це кількість ядер процесора, для цього ми зчитуємо /proc/cpuinfo і вважаємо кількість рядків, у яких міститься слово «процесор«. Ми розглядали цю тему в розділі «Інформація про сервер«.

В Linux інформація про середньої навантаженні міститься в /proc/loadavg. Перші три стовпці — це навантаження за одну хвилину, п’ять хвилин і за п’ятнадцять хвилин відповідно. awk ми використовуємо, щоб відфільтрувати тільки ті поля, які нам потрібні:

➜ ~ cat /proc/loadavg
0.01 0.04 0.05 1/217 16089
➜ ~ cat /proc/loadavg | awk ‘{print $1, $2, $3}’
0.01 0.04 0.05

Отриманий результат поділяється пробілами, в результаті чого ми отримуємо масив з трьома елементами. Середня навантаження розраховується для всіх ядер. Таким чином, щоб отримати результат, ми з допомогою array_map обробляємо через цикл масив $loadAvg і значення ділимо на кількість ядер.

Зверніть увагу, що ми створюємо два додаткових масиву тієї ж довжини, що і $loadAvg: один ключ, інший — для кількості ядер, — вони один за іншим передаються у зворотний виклик array_map.

Пора задіяти get_content:

public function get_content() {
$metrics = $this->get_metric();
if ( ! $metrics ) {
return false;
}
// ознайомтеся з інформацією за адресою https://google-developers.appspot.com/chart/interactive/docs/gallery/barchart#Data_Format for more detai of format
$data = array( array( ‘Тривалість’, ‘% Load’ ) );
foreach ( $metrics as $key=>$metric ) {
array_push( $data, array( $metric[0], $metric[1] ) );
}
$data = json_encode( $data );
echo <<Ми використовуємо bar chart і створюємо з нашого масиву масив даних, використовуємо json_encode, щоб перетворити його в масив анотацій JavaScript, який відповідає формату даних гістограми.

Приклад:

[
[«Duration»,»% Load»],
[«1 min»,20],
[«5 mins»,11],
[«15 mins»,3]
]

Ось як виглядає сама гістограма:

Висновок віджета інформації про сервер в консолі WordPress

Інтерфейс Ethernet

Наступний віджет буде відображати дані по інтерфейсу Ethernet. Деякі сервери можуть використовувати кілька інтерфейсів Ethernet з різними IP-адресами.

Ця інформація може виявитися нам вельми корисною. Назвемо цей клас Ethernet, і почнемо з створення базового файлу widget/ethernet.php:

Отже, наш віджет називається — Ethernet. Для get_metric нам потрібно отримати всі імена інтерфейсів Ethernet, після цього ми отримаємо IP-адреса кожного з них і об’єднаємо імена пристроїв і IP-адреси, щоб повернути цю інформацію.

Нам потрібно враховувати два випадки: коли сервер використовує ifconfig і коли сервер використовує ip-утиліти. Нові сервера, швидше за все, використовують замість ifconfig; ip; тому в першу чергу ми повинні запускати ip, щоб отримати інформацію про пристрої Ethernet:

$output = shell_exec(«ip -oneline link show | awk ‘{print $2}’ | sed ‘s/://'»);

Використання IP-утиліти

Команда ip з перемикачем -oneline видає результат, що складається всього з одного рядка, в якій в якості link і show представлений список всіх пристроїв.

Ми використовуємо awk, щоб отримати другий стовпець-з назвами пристроїв; однак він містить символ :. Ми використовуємо sed, щоб замінити : порожнім рядком.

Ось результат виконання команди з командного рядка:

[[email protected] sbin]$ ip -oneline link show
1: lo: mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:08:c2:e4 brd ff:ff:ff:ff:ff:ff
3: eth1: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:eb:11:e4 brd ff:ff:ff:ff:ff:ff
[[email protected] sbin]$ ip -oneline link show | awk ‘{print $2}’
lo:
eth0:
eth1:
[[email protected] sbin]$ ip -oneline link show | awk ‘{print $2}’ | sed ‘s/://’
lo
eth0
eth1
[[email protected] sbin]$

Якщо проходить виконання shell_exec, значить, ми маємо справу з IP-утилітою. Наведені вище дані розбиваються в масив рядок за рядком:

$output = trim($output, «n»);
$interfaces = explode(«n», $output);
Після ми пропускаємо цей масив через цикл, і знову виконуємо ip-команду ip -oneline -family inet addr, щоб отримати IP-адресу, присвоєний пристрою.
$addreses = array();
foreach ($interfaces as $interface) {
$output = shell_exec(«ip -oneline -family inet addr show $interface | awk ‘{print $4}’ | cut -d’/’ -f1»);
$addreses[] = $output;
}

IP-адреса відображається в четвертому стовпці, і ми використовуємо awk, щоб вивести це значення. Тоді ми поділяємо цю команду і отримуємо перший елемент з допомогою перемикача -f1.

Розгляньте наведений нижче результат, отриманий після виконання команди з командного рядка, щоб зрозуміти, як це все працює:

[[email protected] sbin]$ ip -oneline -family inet addr show eth1
3: eth1 inet 192.168.1.111/24 brd 192.168.1.255 scope global eth1
[[email protected] sbin]$ ip -oneline -family inet addr show eth1 | awk ‘{print $4}’
192.168.1.111/24
[[email protected] sbin]$ ip -oneline -family inet addr show eth1 | awk ‘{print $4}’ | cut -d’/’ -f1
192.168.1.111
[[email protected] sbin]$

Після того, як ми отримали назви пристроїв в масиві інтерфейсів і IP-адреси в масиві адрес, створюємо асоційований масив, в якому в якості ключа використовується назва інтерфейсу, IP-адреса — як значення:

return array_combine($interfaces, $addreses);

Сервери, що використовують Ifconfig

Якщо сервер використовує Ifconfig, команда shell_exec поверне значення false. У цьому випадку, ми обробляємо сценарій, пов’язаний з Ifconfig.

Логіка, яку ми розглянули вище, залишається тією ж — це всього лише різні утиліти для захоплення інформації:

if (!$output) { // It didn’t work with «ip» , so we do it with ifconfig
$output = `ifconfig | grep «Link euroncap» | awk ‘{ print $1 }»;
$interfaces = explode(«n», $output);
$output = `ifconfig | grep «inet addr» | awk ‘{ print $2 }’ | sed ‘s/addr://»;
$addreses = explode(«n», $output);
$output = trim($output, «n»);
return array_combine($interfaces, $addreses);
}

Давайте запустимо наведену вище команду в терміналі.
Зверніть увагу, що ifconfig показує IP-адреси безпосередньо в результаті виведення, тому ми можемо відразу ж їх отримати, замість того, щоб пропускати через цикл масив пристроїв і отримувати IP-адресу кожного пристрою:

[[email protected] sbin]$ ifconfig
eth0 Link euroncap:Ethernet HWaddr 08:00:27:08:C2:E4
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe08:c2e4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4230 errors:0 dropped:0 overruns:0 frame:0
TX packets:2575 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:444488 (434.0 KiB) TX bytes:2288676 (2.1 MiB)
eth1 Link euroncap:Ethernet HWaddr 08:00:27:EB:11:E4
inet addr:192.168.1.111 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feeb:11e4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4470 errors:0 dropped:0 overruns:0 frame:0
TX packets:2449 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1689803 (1.6 MiB) TX bytes:271675 (265.3 KiB)
lo Link euroncap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:264 errors:0 dropped:0 overruns:0 frame:0
TX packets:264 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:15840 (15.4 KiB) TX bytes:15840 (15.4 KiB)
[[email protected] sbin]$ ifconfig | grep «Link euroncap»
eth0 Link euroncap:Ethernet HWaddr 08:00:27:08:C2:E4
eth1 Link euroncap:Ethernet HWaddr 08:00:27:EB:11:E4
lo Link euroncap:Local Loopback
[[email protected] sbin]$ ifconfig | grep «Link euroncap» | awk ‘{ print $1 }’
eth0
eth1
lo
[[email protected] sbin]$ ifconfig | grep «inet addr»
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet addr:192.168.1.111 Bcast:192.168.1.255 Mask:255.255.255.0
inet addr:127.0.0.1 Mask:255.0.0.0
[[email protected] sbin]$ ifconfig | grep «inet addr» | awk ‘{ print $2 }’
addr:10.0.2.15
addr:192.168.1.111
addr:127.0.0.1
[[email protected] sbin]$ ifconfig | grep «inet addr» | awk ‘{ print $2 }’ | sed ‘s/addr://’
10.0.2.15
192.168.1.111
127.0.0.1
[[email protected] sbin]$

Після того, як отримані дані, ми можемо легко помістити їх в get_content; так як нам не потрібна діаграма, ми виводимо просту таблицю:

public function get_content() {
$interfaces = $this->get_metric();
$html = ‘

‘;
foreach ( $interfaces as $interface => $ip ) {
$html .= «

«;
}
$html .= ‘

Interface IP
{$interface} {$ip}

‘;
echo $html;
}

Ось як виглядають отримані дані в консолі адміністратора:

Висновок віджета інформації про сервер в консолі WordPress

Мережевий трафік

Мережевий трафік або Network IO — це параметр, що показує статус передачі пакетів у мережі комп’ютерів. Інформація знімається з netstat:

[[email protected] sbin]$ netstat -i
Kernel Interface table
Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 0 4828 0 0 0 2933 0 0 0 BMRU
eth1 1500 0 4806 0 0 0 2679 0 0 0 BMRU
lo 16436 0 276 0 0 0 276 0 0 0 LRU

Давайте створимо базовий клас Networkio у файлі widget/networkio.php:

function get_metric() {
$ethernet = array();

$output = `netstat -i | grep -v -E ‘(Iface|Interface)’ | awk ‘{print $1″,»$4″,»$8}»;

$lines = explode(«n», $output);
foreach ($lines as $line) {
$line = explode(‘,’, $line);
if (count($line)<3) {
continue;
}
$ethernet[] = array($line[0], intval($line[1]), intval($line[2]));
}
return $ethernet;
}

}

Ці дані я поясню трохи пізніше. А зараз давайте спробуємо розібрати команду, яку ми використовували у наведеному вище коді.

Я хочу запустити відразу кілька команд, щоб ви розуміли, у чому полягає різниця:

[[email protected] sbin]$ netstat -i
Kernel Interface table
Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 0 5727 0 0 0 3400 0 0 0 BMRU
eth1 1500 0 5004 0 0 0 2797 0 0 0 BMRU
lo 16436 0 292 0 0 0 292 0 0 0 LRU
[[email protected] sbin]$ netstat -i | grep -v -E ‘(Iface|Interface)’
eth0 1500 0 5736 0 0 0 3405 0 0 0 BMRU
eth1 1500 0 5004 0 0 0 2797 0 0 0 BMRU
lo 16436 0 292 0 0 0 292 0 0 0 LRU
[[email protected] sbin]$ netstat -i | grep -v -E ‘(Iface|Interface)’ | awk ‘{print $1″,»$4″,»$8}’
eth0,5760,3420
eth1,5004,2797
lo,292,292
[[email protected] sbin]$

netstat повертає багато показників, ми використовували grep, щоб видалити рядки, що містять слова Iface або Kernel (перші два рядки).

Нам потрібні тільки останні три рядки з інформацією про пристрої локальної мережі і переданих ними пакетах. awk використовується, щоб вивести дані першого, четвертого і восьмого стовпців, в яких містяться назва інтерфейсу, RX-OK і TX-OK.

У нашому методі get_metric ми розбиваємо рядка результату в масив. Оскільки кожна з рядків містить дані, розділені комою, кожна з них відповідно теж розбивається на масив.

Ми повинні забезпечити, щоб створювався масив тільки з трьох елементів. Ми також хочемо перетворити цифровий рядок в ціле число. Дані, які в свою чергу будуть передаватися в get_content:

public function get_content() {
$interfaces = $this->get_metric();
$data = array_merge(array(array(‘Interface’, ‘Receive(package)’, ‘Transfer(package)’)), $interfaces);
$data = json_encode($data);
echo <<

Ми вже використовували гістограму раніше, тепер ми знову формуємо масив даних метрики згідно з форматом даних гістограми, а потім виводимо їх.

Кожен рядок масиву даних являє собою розділ групи з ім’ям розділу і відповідними йому значеннями. В нашому випадку, кожен рядок містить ім’я користувача та стовпці RX і TX.

Ось що ми отримали:

Висновок віджета інформації про сервер в консолі WordPress

Статистика вводу / виводу даних

Тепер, ми займемося віджетом io stat. IO — означає введення / виведення (input/output). Ми дізнаємося, скільки операцій читання / запису виконується в секунду. Ми також отримаємо метрику io_wait. Це час, який процесор простоює в очікуванні результату, який зчитується з жорсткого диска.

Наприклад, ви прочитаєте дані MySQL, і процесор простоює в очікуванні результату. io wait розраховується в 1 секунду або за 1000 мілісекунд. Якщо зчитування коду з жорсткого диска займає 100 мілісекунд, то значення io_wait одно 100/1000 = 10%. Чим менше io_wait, тим вище продуктивність системи.

Для того щоб перейти до розробки наступного віджета, будь ласка, переконайтеся, що у вас встановлений пакет Sysstat.

  • Для Arch Linux він повинен бути встановлений з pacman -S sysstat;
  • Для Debian / Ubuntu — з apt-get install sysstat;
  • Для Fedora / Centos — з yum install sysstat;
  • Для інших дистрибутивів — ласка, використовуйте менеджер пакетів дистрибутива.

Тепер давайте розглянемо деякі команди, які ми будемо використовувати:

[[email protected] sbin]$ iostat
Linux 2.6.32-358.23.2.el6.x86_64 (vagrant-centos64.vagrantup.com) 04/27/2014 _x86_64_ (1 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.05 0.00 0.25 0.04 0.00 99.66
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
sda 0.18 7.62 1.04 157826 21584

Четвертий рядок містить дані стану IO. Нам потрібно значення iowait в четвертому стовпці. Дані сьомий рядки містять блок кількості зчитувань / записів на жорсткий диск в секунду.

Якщо у вас є багато жорстких дисків, підключених до сервера, ви будете мати більше одного пристрою: sdb, sdc і так далі.

Дані представляють кількість блоків, а не об’єм у мегабайтах. Щоб розрахувати загальний обсяг, ми повинні отримати розмір одного блоку.

Розмір блоку зберігається в /sys/block/sda/queue/physical_block_size:

[[email protected] ~]$ cat /sys/block/sda/queue/physical_block_size
512
[[email protected]tos64 ~]$

Таким чином, розмір блоку sda становить 512. Множимо кількість блоків, прочитуваних в секунду на розмір блоку, щоб отримати реальний обсяг зчитування / запису даних.

Ґрунтуючись на наведеній вище інформації, давайте створимо клас Iostat у файлі widget/iostat.php:

floatval($avg_cpu[2]) * $number_of_core,
‘io_wait’ => floatval($avg_cpu[3]) * $number_of_core,
‘other’ => 100 — ($avg_cpu[0] + $avg_cpu[2] + $avg_cpu[3])
);
if (sizeof($lines) >=7) {
for ($i=6,$l = sizeof($lines);$i<$l; $i++) {
$line = preg_split(«/s+/», $lines[$i]);
if (!is_array($line) || sizeof($line) floatval($line[2]) * $block_size / 1024,
‘write’ => floatval($line[3]) * $block_size / 1024,
);
}
}
return $metric;
}
}

Ми просто реалізували наведену вище теорію через PHP-код. І отримали вихідні дані iostat. Перетворюємо їх в масив, де кожен рядок являє собою елемент масиву.

Четвертий рядок розділяється пробілами і перетворюється в дійсний масив. Всі рядки нижче сьомий поміщені в інший асоційований масив, для якого ключем є ім’я пристрою (sda, sdb, sdc тощо), а значенням — масив обсягу зчитувань або записи даних на диск в мегабайтах.

Після того, як ми отримали метрику, відправляємо її в метод get_content і створюємо діаграму:

public function get_content() {
$metric = $this->get_metric();
$disk_io = array(
array(‘Disk’, ‘Read(MB)’, ‘Write(MB)’),
);
foreach ($metric[‘disk’] as $disk=>$stat) {
$disk_io[] = array($disk, $stat[‘read’], $stat[‘write’]);
}
$disk_io = json_encode($disk_io);
$cpu_io = json_encode(array(
array(‘CPU Time’, ‘Percent’),
array(‘IO Wait’, $metric[‘cpu’][‘io_wait’]),
));
echo <<Для даних за обсягом зчитування / запису на диск ми використовуємо гістограму. Для часу очікування ми використовуємо діаграму — датчик, щоб результат виглядав красиво.

Ми враховуємо, що середнє значення часу очікування в діапазоні 80-100 є тривожним сигналом, і виділяємо цей сектор червоним кольором.

Сектор 50-80 ми виділяємо жовтим кольором. Датчик дозволяє нам зробити це з допомогою опції:

var goptions = {
redFrom: 80, redTo: 100,
yellowFrom:50, yellowTo: 80,
minorTicks: 5
};

Ось як виглядає результат наших старань:

Висновок віджета інформації про сервер в консолі WordPress

Дані зчитування / запису даних на диск виводяться в гістограмі, час очікування — датчику

Що далі?

На даний момент ми створили всі віджети нашого плагіна. Ви можете завантажити весь код плагіна цієї статті, щоб не вводити його вручну. Встановіть плагін, а потім оновіть сторінку консолі та встановіть відповідні опції екрану, щоб визначити, який саме віджет ви хочете вивести:

Висновок віджета інформації про сервер в консолі WordPress

Наш плагін вже зараз чудово працює; однак, ми можемо піти ще далі і реалізувати перевірку користувача і його ролі, щоб відображати дані в залежності від її результатів.

Ми також повинні використовувати для отримання цих метрик cronjob. Не пропустіть наступну частину цієї серії.
Як завжди, не забудьте залишити коментар, дайте нам знати, що ви думаєте про плагіні, а також про те, як вам вдалося його налаштувати.

Переклад статті «Turning a WordPress Server into a Dashboard Widget» був підготовлений дружною командою проекту Сайтостроение від А до Я.

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here