Статьи

Превращение панели инструментов сервера WordPress в виджет

Конечный продукт
Что вы будете создавать

В предыдущей статье мы создали базовую структуру нашего плагина. Теперь пришло время реализовать класс рендеринга для каждого из наших виджетов.

Напомним, что все провайдеры виджетов должны реализовывать интерфейс Provider . Они также должны находиться внутри папки с именем widget и под пространством имен AX\StatBoard\Widget . Если мы хотим добавить метрику нового типа, просто создайте соответствующий класс, создайте объект и добавьте его в класс Widget с add_provider метода add_provider .

Одной из первых частей информации, которую мы хотим отобразить, является объем оперативной памяти, используемой в настоящее время, и объем свободной памяти.

В этом случае free -m — наш друг — он говорит нам об использовании оперативной памяти. ключ -m для вывода результата в мегабайтах.

1
2
3
4
5
[vagrant@vagrant-centos64 ~]$ 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 .

01
02
03
04
05
06
07
08
09
10
11
12
<?php
namespace AX\StatBoard\Widget;
 
class Ram implements Provider {
  function __construct() {
  }
 
  public function get_title() {
    return «Ram Usage»;
  }
 
?>

Далее мы реализуем get_metric для фактического запуска необходимой команды оболочки и извлечения информации. Я объясню более подробно get_metric позже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
function get_metric() {
    $df = `free -m |
    $df = explode(«\n», $df);
    if ( is_array( $df ) && 2 <= count( $df ) ) {
      $df = array_map( function ( $line ) {
        if ( empty( $line ) ) {
          return;
        }
        $segment = preg_split( ‘/\s+/’, $line );
 
        return array(
          ‘type’ => trim( $segment[0],» :» ),
          ‘total’ => (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}' free -m | grep -E "Mem|Swap" | awk '{print $1, $2, $3, $4}' free -m | grep -E "Mem|Swap" | awk '{print $1, $2, $3, $4}' . Его вывод выглядит примерно так.

1
2
3
4
[vagrant@vagrant-centos64 ~]$ free -m |
Mem: 589 541 47
Swap: 255 0 255
[vagrant@vagrant-centos64 ~]$

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

  • type : первое поле
  • total : второе поле
  • used : третье поле
  • free : четвертое поле

Теперь пришло время для get_content .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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 <<<EOD
      <div id=»widget_ram_usage»></div>
      <script type=»text/javascript»>
      google.setOnLoadCallback(function () {
        var data = google.visualization.arrayToDataTable({$data});
        var options = {
          isStacked: true
        };
        var chart = new google.visualization.ColumnChart(document.getElementById(‘widget_ram_usage’));
        chart.draw(data, options);
      })
    </script>
EOD;
  }

Мы использовали гистограмму с накоплением для отображения использования оперативной памяти.

Сначала мы вызываем get_metric() чтобы получить необходимые данные. Затем мы просто зациклим его и отформатируем в соответствии с требованиями к данным диаграммы Google. Наконец, мы используем json_encode для преобразования их в нотацию объектов JavaScript (или JSON). Затем мы выводим HTML-код, который содержит элемент div для хранения объекта диаграммы.

Наконец, мы вызываем соответствующий API Google Chart для отображения диаграммы в этом элементе div .
Виджет использования оперативной памяти показывает физическую память и информацию о подкачке.

Второй виджет, который мы рассмотрим, будет отображать установленное программное обеспечение. Это виджет, который предназначен для того, чтобы показать, какие общие пакеты у нас на сервере и какая версия.

Например, у нас установлен NodeJS, у нас установлен Ruby? Какую версию PHP мы используем? И так далее.
Давайте создадим widget/software.php с этим начальным содержимым:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
namespace AX\StatBoard\Widget;
 
class Software implements Provider {
  function __construct() {
  }
 
  public function get_title() {
    return «Installed Software»;
  }
  function get_metric() {
    $cmds = array();
 
    $package = array(
      ‘php’ => ‘-v’,
      ‘node’ => ‘-v’,
      ‘mysql’ => ‘-V’,
      ‘vim’ => ‘—version’,
      ‘python’ => ‘-V’,
      ‘ruby’ => ‘-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 ] .= ‘<br>’ .
    }
    return $cmds;
  }

Итак, как всегда, у нас есть get_title и он просто возвращает простую строку. Для get_metric() мы хотим знать, установлена ​​ли конкретная часть программного обеспечения или нет. Если так, то получите информацию о его версии.

Для этого мы создаем массив команд с помощью переключателя, который показывает версию программного обеспечения. Например, принимая PHP, php -v показывает информацию о версии, mysql --version показывает информацию MySQL.
shell_exec возвращает false если команда возвращает ошибку и команда не найдена. В этом случае мы можем определить, что программное обеспечение не установлено; в противном случае мы можем проанализировать результат, чтобы показать информацию о версии. Затем мы разбиваем результат по строкам и извлекаем первую строку как информацию о версии. Это потому, что нужная нам информация находится только в первой строке.
Для других приложений некоторые команды слишком многословны и содержат много информации. Как только мы получим данные, пришло время создать метод get_content .

01
02
03
04
05
06
07
08
09
10
11
public function get_content() {
  
   $cmds = $this->get_metric();
   $content = »;
    
   foreach ( $cmds as $cmd => $info ) {
     $content .= «<p><strong>$cmd</strong>&nbsp; $info</p>»;
   }
   echo $content;
    
 }

Мы просто показываем базовую таблицу для такого рода данных. Вот панель инструментов при появлении:

Виджет показывает информацию об установке программного обеспечения

Теперь мы рассмотрим использование диска. Назовем класс, который выполняет эту задачу Disk . Давайте сначала создадим базовый скелет.

01
02
03
04
05
06
07
08
09
10
<?php
namespace AX\StatBoard\Widget;
 
class Disk implements Provider {
  function __construct() {
  }
  public function get_title() {
    return «Disk Usage»;
  }
}

Как всегда, мы должны реализовать интерфейс Provider . Мы устанавливаем заголовок для нашего виджета здесь. Следующее является сердцем нашего класса: метод получения использования диска.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
 function get_metric() {
   $df = `df -h`;
   $df = explode(«\n», $df);
   if (is_array($df) && count($df)>=2) {
     array_shift($df);
     $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 :

1
2
3
4
5
6
7
8
[vagrant@vagrant-centos64 ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 7.3G 1.4G 5.6G 20% /
tmpfs 295M 0 295M 0% /dev/shm
/vagrant 60G 55G 4.9G 92% /vagrant
/data/GeoIP 60G 55G 4.9G 92% /data/GeoIP
/var/webapps 60G 55G 4.9G 92% /var/webapps
/var/www/html 60G 55G 4.9G 92% /var/www/html

Мы разбиваем его по строкам, чтобы превратить в массив. Мы перебираем каждую строку, разделяем целую строку пробелами, чтобы снова превратить ее в массив. Затем мы просто отображаем значение, чтобы иметь более дружественный, понятный человеку ассоциативный массив. Когда у нас есть эти данные, мы можем поместить их в get_content .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
   }
 }

Мы перебираем метрический массив и пытаемся преобразовать пространство в МБ в ГБ. Мы строим массив в соответствии с требованиями формата данных диаграммы. Массив данных должен выглядеть так:

Как только у нас есть данные, мы начинаем отображать графики. Мы сделаем две диаграммы:

  1. Первая диаграмма показывает пространство каждой смонтированной файловой системы в целом. Для этих данных мы будем использовать круговую диаграмму.
  2. Вторая диаграмма предназначена для отображения использования диска каждой отдельной смонтированной файловой системой. Для этого мы будем использовать гистограмму.

Для этого давайте изменим наш метод следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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 <<<EOD
      <div id=»widget_disk_usage»></div>
      <div id=»widget_disk_partion»></div>
      <script type=»text/javascript»>
      google.load(«visualization», «1», {packages:[«corechart»]});
      google.setOnLoadCallback(function () {
        var data = google.visualization.arrayToDataTable({$data});
        var options = {
          is3D: true,
        };
        var chart = new google.visualization.PieChart(document.getElementById(‘widget_disk_usage’));
        chart.draw(data, options);
 
        var data2 = google.visualization.arrayToDataTable({$data_partition});
        var options2 = {
          isStacked: true
        };
        var chart2 = new google.visualization.ColumnChart(document.getElementById(‘widget_disk_partion’));
        chart2.draw(data2, options2);
 
      })
    </script>
EOD;
  }

Мы создали два элемента div для хранения информации

1
2
<div id=»widget_disk_usage»></div>
      <div id=»widget_disk_partion»></div>

Затем диаграмма отображается внутри этого элемента с помощью метода draw API диаграммы. Самым запутанным здесь может быть формат данных для нашего графика.

Вот результат:

Использование диска

Этот виджет показывает нам информацию: ядро ​​Linux, архитектура процессора, время работы, IP-адрес. Нам не нужна диаграмма здесь, простая таблица данных делает работу. Вызов класса является Server . Вот первый контент для widget/server.php

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
namespace AX\StatBoard\Widget;
use DateTime;
 
class Server implements Provider {
  function __construct() {
  }
 
  public function get_title() {
    return «Server Info»;
  }
   
  /**
   * Return server info: OS, Kernel, Uptime, and hostname
   * @return array with 3 metric:
   * * hostname
   * * os
   * * uptime
   */
  function get_metric() {
    $server = array();
    $server[‘hostname’] = `hostname`;
    $server[‘os’] = `uname -sr`;
    $server[‘core’] = `grep -c ^processor /proc/cpuinfo`;
    $total_uptime_sec = time() — `cut -d.
     
    $now = new DateTime(«now»);
    $server[‘uptime’] = $now->diff(new DateTime(«@$total_uptime_sec»))->format(‘%a days, %h hours, %i minutes and %s seconds’);
 
    // Get the external ip with ifconfig.me, a website that show you ip address in plaintext
    // when sending request with curl header
    $server[‘ip’] = `curl ifconfig.me`;
    $server[‘ram’] = `free -m |
    $server[‘cpu’] =`cat /proc/cpuinfo |
 
    return $server;
  }
 
}

К этому моменту вы должны быть знакомы с get_title() . Мы просто возвращаем название этого виджета.

Во-первых, мы используем оператор use DateTime потому что мы находимся внутри пространства имен AX\StatBoard\Widget а класс DateTime — из глобального пространства имен. Каждый раз, когда мы хотим использовать DateTime мы должны набирать \DateTime . Поэтому мы используем импорт пространства имен, чтобы сделать имя DateTime доступным внутри нашего текущего пространства имен.
Думайте об этом как о символической ссылке. Внутри get_metric мы запускаем команду оболочки, чтобы получить результат и просто присвоить его обратно.

Покажите имя вашего сервера.

Показать информацию о ядре Linux:

1
2
[vagrant@vagrant-centos64 ~]$ uname -sr
Linux 2.6.32-358.23.2.el6.x86_64

Ключ -c выводит количество совпадающих строк во входной строке. /proc/cpuinfo содержит информацию о процессоре. Мы grep это и подсчитать возникновение текстового процессора. Вот мой результат с 32 ядрами.

1
2
$ grep -c ^processor /proc/cpuinfo
32

Эта команда показывает, сколько секунд сервер был запущен и работает. Мы конвертируем эти числа секунд в формат «x день y час z минута», чтобы сделать его более удобным для пользователя.

Используя DateTime :: diff, мы можем легко добиться этого. Мы создаем объект DateTime с текущей отметкой времени, а другой объект с отметкой времени — это текущая отметка времени минус число секунд времени безотказной работы. Затем с помощью метода форматирования отформатируйте его в удобную для человека строку.

Вот мой результат с временем безотказной работы 26194091 секунд.

1
2
$ cut -d.
26194091

ifconfig.me — это сервис, который показывает ваш IP-адрес при посещении прямо в браузере. Если вы отправляете запрос с помощью curl , он возвращает ваш IP-адрес в виде одной строки.

1
2
[vagrant@vagrant-centos64 ~]$ curl ifconfig.me
76.102.253.237

Как уже упоминалось выше, /proc/cpuinfo хранит информацию о процессоре. Мы можем извлечь модель процессора из него. Например:

1
2
[vagrant@vagrant-centos64 ~]$ cat /proc/cpuinfo |
Intel(R) Core(TM) i5-4250U CPU

Как только у нас есть все данные, доступные в массиве, мы возвращаем их и get_content методу get_content эти данные. Вот get_content , просто показывающий данные:

01
02
03
04
05
06
07
08
09
10
11
12
public function get_content() {
    $server = $this->get_metric();
    echo <<<EOD
    <strong>Ip Address</strong>&nbsp;{$server[‘ip’]}<br>
    <strong>CPU</strong>&nbsp;
    <strong>Number of Core</strong>&nbsp;
    <strong>Ram</strong>&nbsp;
    <strong>Hostname</strong>&nbsp;{$server[‘hostname’]}<br>
    <strong>OS</strong> {$server[‘os’]}<br>
    <strong>Uptime</strong> {$server[‘uptime’]}<br>
EOD;
  }

Вот наш виджет на приборной панели.

Информация о сервере

Мониторинг нашего процессора — одна из самых важных вещей, которые мы можем отобразить. Мы хотим знать, сколько ЦП используется и / или объем памяти, потребляемый конкретным процессом. Мы вызываем наш класс Process , начиная с get_title и get_metric . Я объясню более подробно get_metric после кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
namespace AX\StatBoard\Widget;
 
class Process implements Provider {
 
 
  public function get_title() {
    return «Processes»;
  }
 
  /**
   * Return server info: OS, Kernel, Uptime, and hostname
   * @return array with 3 metric:
   * * hostname
   * * os
   * * uptime
   */
  function get_metric() {
    $processes = array();
    $output = `ps -eo pcpu,pmem,pid,user,args,time,start |
    $output = explode(«\n», $output);
    if (!is_array($output) || count($output)<2) {
      return false;
    }
    array_shift($output);
    foreach ($output as $line) {
      //$line = preg_split(‘/\s+/’, $line);
      $line = explode(‘ ‘, $line);
      if (count($line)<6) {
        continue;
      }
      //var_dump($line);
      //echo count($line);
      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];
      }
    }
 
    return $processes;
  }
 
}

Команда, которая показывает нам, что процесс запущен — это ps . Он дает обширную информацию с ключом -e так как позволяет нам видеть каждый процесс. Для нашего виджета нам нужно только вытащить наш COU, память, PID, пользователей, аргументы, время и старт.

Мы можем комбинировать с -o средним определяемым пользователем форматом, таким как: ps -eo pcpu,pmem,pid,user,args,time,start . Если вы попробуете эту команду, вы получите странный процесс, такой как:

1
2
3
4
5
[vagrant@vagrant-centos64 ~]$ 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], [igration / 0]. По сути, это означает, что команда не может быть расположена в файловой системе. Это может быть какой-то внутренний системный процесс или поток ядра, и нам, возможно, никогда не захочется об этом заботиться. Поэтому мы должны исключить этот процесс с помощью grep . grep имеет ключ -v позволяющий нам инвертировать соответствие. Он возвращает результат, который не содержит строку, которую мы передаем ему.

01
02
03
04
05
06
07
08
09
10
[vagrant@vagrant-centos64 ~]$ 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.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 для форматирования вывода. Вот наша команда с примером вывода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[vagrant@vagrant-centos64 ~]$ ps -eo pcpu,pmem,pid,user,args,time,start |
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 vagrant@pts/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 . Мы группируем одноименный процесс в элемент и складываем в него проценты процессора и память.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<?php
//…
// inside get_content
 
    foreach ( $output as $line ) {
      //$line = preg_split( ‘/\s+/’, $line );
      $line = explode( ‘ ‘, $line );
      if ( 6 > 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_content . Напомню, что мы должны реализовать метод get_title : get_title , get_metric и get_content . Для процесса мы хотим показать только простую таблицу.
Наш метод get_content прост.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
public function get_content() {
   $processes = $this->get_metric();
   $html = ‘<table class=»wp-list-table widefat»><thead><tr>
     <th>User</th>
     <th>Pid</th>
     <th>%CPU</th>
     <th>%Mem</th>
     <th>Command</th>
     </tr></thead><tbody>’;
   foreach ($processes as $process) {
     $html .= «<tr>
       <td>{$process[‘user’]}</td>
       <td>{$process[‘pid’]}</td>
       <td>{$process[‘%cpu’]}</td>
       <td>{$process[‘%mem’]}</td>
       <td>{$process[‘command’]}</td>
       </tr>»;
   }
   $html .= ‘</tbody></table>’;
   echo $html;
 }

И вот что мы получаем:

Процессы отображения виджетов процессов выполняются на сервере, и их ЦП и память занимают

В Linux есть команда, которая показывает среднюю загрузку процессора и ввода-вывода за последнюю минуту, пять минут и 15 минут. Пусть хрустят в виджет. Назовите его Cpuload и создайте наш widget/cpuload.php

01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace AX\StatBoard\Widget;
 
class Cpuload implements Provider {
  function __construct() {
  }
 
  public function get_title() {
    return «CPU Load»;
  }
  function get_metric() {
 
}

Первым делом мы подсчитываем количество ядер процессора, читая /proc/cpuinfo и подсчитываем количество строк, содержащих слово «процессор». Мы рассмотрели это в разделе « Информация о сервере».

В Linux /proc/loadavg содержит информацию о средней загрузке. Первые три столбца представляют собой нагрузку на одну минуту, пять минут и 15 минут соответственно. Здесь используется awk , чтобы отфильтровать только те поля, которые нам нужны.

1
2
3
4
5
➜ ~ cat /proc/loadavg
0.01 0.04 0.05 1/217 16089
➜ ~ cat /proc/loadavg |
0.01 0.04 0.05
<br>

Приведенный выше результат разделен пробелами для создания массива из трех элементов. Средняя нагрузка рассчитана для всех ядер. Таким образом, чтобы получить результат, мы $loadAvg массив $loadAvg с array_map и делим на количество ядер, которое у нас есть. Обратите внимание, что мы создаем 2 дополнительных массива такой же длины, что и $loadAvg , один для ключа, другой для хранения номера ядра, чтобы передать все по одному в обратный вызов array_map .

Время для get_content :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public function get_content() {
    $metrics = $this->get_metric();
    if ( ! $metrics ) {
      return false;
    }
    // see https://google-developers.appspot.com/chart/interactive/docs/gallery/barchart#Data_Format for more detai of format
    $data = array( array( ‘Duration’, ‘% Load’ ) );
    foreach ( $metrics as $key=>$metric ) {
      array_push( $data, array( $metric[0], $metric[1] ) );
    }
    $data = json_encode( $data );
    echo <<<EOD
<div id=»avg_load»></div>
<script type=»text/javascript»>
      google.load(«visualization», «1», {packages:[«corechart»]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable($data);
 
        var options = {
          hAxis: {
            titleTextStyle: {color: ‘red’},
            minValue:0,
            maxValue:100
          }
        };
 
        var chart = new google.visualization.BarChart(document.getElementById(‘avg_load’));
        chart.draw(data, options);
      }
    </script>
EOD;
  }

Мы используем гистограмму и создаем массив данных из нашего массива, затем используем json_encode чтобы превратить его в массив нотации JavaScript, который соответствует формату данных гистограммы.

Например:

Вот наш результат, когда график отображается:

Следующий виджет, который мы рассмотрим, — для интерфейса Ethernet. Некоторые серверы могут иметь несколько интерфейсов Ethernet с разными IP-адресами.

Просмотр этой информации очень полезен. Давайте назовем этот класс Ethernet , начнем с этой базовой вещи для widget/ethernet.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
/**
 * Adopt from https://github.com/afaqurk/linux-dash/blob/master/sh/ip.php
 *
 */
namespace AX\StatBoard\Widget;
 
class Ethernet implements Provider {
  function __construct() {
  }
 
  public function get_title() {
    return «Ethernet»;
  }
 
  function get_metric() {
    $ethernet = array();
    $output = shell_exec(«ip -oneline link show | awk ‘{print $2}’ | sed ‘s/://’»);
    if (!$output) { // It didn’t work with «ip» , so we do it with ifconfig
      $output = shell_exec(
        ‘ifconfig |
        ‘{ if ( $1 == «inet» ) { print $2 }’ .
        ‘else if ( $2 == «Link» ) { printf «%s:»,$1 } }\’ |
        ‘ -F: \'{ print $1″,»$3 }\»
      );
      $output = trim($output, » \n»);
      $output = `ifconfig |
      $interfaces = explode(«\n», $output);
      $output = `ifconfiga |
      $addreses = explode(«\n», $output);
      $output = trim($output, » \n»);
      return array_combine($interfaces, $addreses);
    }
 
    $output = trim($output, » \n»);
    $interfaces = explode(«\n», $output);
    $addreses = array();
    foreach ($interfaces as $interface) {
      $output = shell_exec(«ip -oneline -family inet addr show $interface | awk ‘{print $4}’ | cut -d’/’ -f1»);
      $addreses[] = $output;
    }
    return array_combine($interfaces, $addreses);
  }
 
}

Таким образом, название виджета будет Ethernet . Для get_metric мы попытаемся получить все имена интерфейсов Ethernet, затем мы получим IP-адрес каждого из них и скомбинируем имя устройства и IP-адрес для возврата.

Нам нужно решить две ситуации: если сервер использует ifconfig или если сервер использует утилиту ip . Более новые серверы, скорее всего, имеют ip вместо ifconfig; поэтому сначала нужно запустить ip, чтобы получить Ethernet-устройства.
1
$output = shell_exec(«ip -oneline link show | awk ‘{print $2}’ | sed ‘s/://’»);

Команда ip с параметром -oneline покажет вывод только в одной строке, где в виде link и show будут перечислены все устройства. Мы используем awk, чтобы получить второй столбец с именами устройств; однако он содержит: char. Мы использовали sed для замены: пустой строкой.

Вот результат, когда мы запускаем их в командной строке:

01
02
03
04
05
06
07
08
09
10
11
12
13
[vagrant@vagrant-centos64 sbin]$ ip -oneline link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \ link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000\ link/ether 08:00:27:eb:11:e4 brd ff:ff:ff:ff:ff:ff
[vagrant@vagrant-centos64 sbin]$ ip -oneline link show |
lo:
eth0:
eth1:
[vagrant@vagrant-centos64 sbin]$ ip -oneline link show |
lo
eth0
eth1
[vagrant@vagrant-centos64 sbin]$

Если shell_exec работает успешно, мы переходим к утилите IP. Приведенный выше вывод разбивается на массив строка за строкой

1
2
$output = trim($output, » \n»);
$interfaces = explode(«\n», $output);

Затем мы перебираем этот массив и снова используем команду ip ip -oneline -family inet addr show device_name чтобы получить IP-адрес, назначенный устройству.

1
2
3
4
5
$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. Затем мы используем команду cut, чтобы разделить команду на / и получить первый элемент с swich -f1.

Посмотрите на вывод, чтобы увидеть, как все работает, когда мы запускаем их в командной строке:

1
2
3
4
5
6
7
[vagrant@vagrant-centos64 sbin]$ ip -oneline -family inet addr show eth1
3: eth1 inet 192.168.1.111/24 brd 192.168.1.255 scope global eth1
[vagrant@vagrant-centos64 sbin]$ ip -oneline -family inet addr show eth1 |
192.168.1.111/24
[vagrant@vagrant-centos64 sbin]$ ip -oneline -family inet addr show eth1 |
192.168.1.111
[vagrant@vagrant-centos64 sbin]$

Когда мы получаем имя устройства в массиве интерфейсов и IP-адрес в массиве адресов, мы создаем ассоциативный массив с именем интерфейса в качестве ключа и IP-адресом в качестве значения.

1
return array_combine($interfaces, $addreses);

В случае ifconfig shell_exec ip вернет false . В этом случае мы запускаем ifconfig.

Логика, которую мы рассмотрели выше, абсолютно одинакова — это просто другая утилита для сбора информации.

1
2
3
4
5
6
7
8
if (!$output) { // It didn’t work with «ip» , so we do it with ifconfig
     $output = `ifconfig |
     $interfaces = explode(«\n», $output);
     $output = `ifconfig |
     $addreses = explode(«\n», $output);
     $output = trim($output, » \n»);
     return array_combine($interfaces, $addreses);
   }

Давайте запустим указанную выше команду в терминале, чтобы иметь представление о том, что происходит.

Обратите внимание, что ifconfig показывает IP-адрес непосредственно в выходных данных, поэтому мы можем просто получить их вместо запуска цикла по устройствам и получить IP-адрес каждого из них.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[vagrant@vagrant-centos64 sbin]$ ifconfig
eth0 Link encap: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 encap: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 encap: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)
 
[vagrant@vagrant-centos64 sbin]$ ifconfig |
eth0 Link encap:Ethernet HWaddr 08:00:27:08:C2:E4
eth1 Link encap:Ethernet HWaddr 08:00:27:EB:11:E4
lo Link encap:Local Loopback
[vagrant@vagrant-centos64 sbin]$ ifconfig |
eth0
eth1
lo
 
[vagrant@vagrant-centos64 sbin]$ ifconfig |
          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
[vagrant@vagrant-centos64 sbin]$ ifconfig |
addr:10.0.2.15
addr:192.168.1.111
addr:127.0.0.1
[vagrant@vagrant-centos64 sbin]$ ifconfig |
10.0.2.15
192.168.1.111
127.0.0.1
[vagrant@vagrant-centos64 sbin]$

Когда у нас есть данные, поместить их в get_content легко, потому что мы просто показываем здесь простую таблицу.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public function get_content() {
   $interfaces = $this->get_metric();
   $html = ‘<table class=»wp-list-table widefat»><thead><tr>
     <th>Interface</th>
     <th>IP</th>
     </tr></thead><tbody>’;
   foreach ( $interfaces as $interface => $ip ) {
     $html .= «<tr>
       <td>{$interface}</td>
       <td>{$ip}</td>
       </tr>»;
   }
   $html .= ‘</tbody></table>’;
   echo $html;
 }

Вот как это выглядит до администратора:

Сетевой трафик, или Сетевой ввод-вывод, показывает состояние передачи пакетов по сети компьютеров. Информация извлечена из netstat .

1
2
3
4
5
6
[vagrant@vagrant-centos64 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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<?php
/**
 * Adopt from https://github.com/afaqurk/linux-dash/blob/master/sh/ip.php
 *
 */
namespace AX\StatBoard\Widget;
 
class Networkio implements Provider {
  function __construct() {
  }
 
  public function get_title() {
    return «Network IO»;
  }
function get_metric() {

Я объясню их позже в статье. А сейчас давайте попробуем оценить команду, которую мы использовали в приведенном выше коде.

Я попытаюсь выполнить несколько команд, чтобы вы могли понять разницу, как только мы передадим результат в другой канал.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
[vagrant@vagrant-centos64 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
 
[vagrant@vagrant-centos64 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
 
[vagrant@vagrant-centos64 sbin]$ netstat -i | grep -v -E '(Iface|Interface)' | awk '{print $1","$4","$8}'
eth0,5760,3420
eth1,5004,2797
lo,292,292
[vagrant@vagrant-centos64 sbin]$ <br><br>

netstatвозвращая многие вещи, мы использовали grep, чтобы исключить строку, содержащую слова Iface или Kernel (первые две строки), мы заботимся только о последних трех строках с нашими устройствами Ethernet и передачей их пакетов. awk используется для распечатки данных первого, четвертого и восьмого столбцов, означающих название интерфейса, RX-OK и TX-OK.

В нашем случае get_metricмы разбиваем результат построчно на массив. Поскольку каждая строка содержит данные, разделенные запятой,  они снова разделяются на массив.

Мы обязательно принимаем только массив с тремя элементами. Мы также пытаемся преобразовать числовую строку в целочисленное значение. Данные, в свою очередь, будут снабжать get_content.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public function get_content() {
    $interfaces = $this->get_metric();
    $data = array_merge(array(array('Interface', 'Receive(package)', 'Transfer(package)')), $interfaces);
    $data = json_encode($data);
    echo <<<EOD
      <div id="nio_chart"></div>
      <script type=»text/javascript»>
      google.setOnLoadCallback(function () {
        var data = google.visualization.arrayToDataTable({$data});
 
        var options = {
        };
 
        var chart = new google.visualization.ColumnChart(document.getElementById('nio_chart'));
        chart.draw(data, options);
      })
    </script>
EOD;
 
  }

Ранее мы использовали гистограмму и попытались отформатировать массив метрических данных в формат данных гистограммы, а затем отобразить его.

Каждая строка массива данных представляет групповую панель с названием панели и соответствующими значениями. В нашем случае каждая строка — это имя интерфейса, а также строка RX и строка TX.
Вот что мы получили:

Теперь мы решаем io stat. IO означает ввод / вывод. Мы узнаем, сколько операций чтения / записи выполняется в секунду. Мы также занимаемся io_wait. IO Wait — это время простоя процессора в ожидании результата, который он считывает с жесткого диска.

Например, вы читаете данные MySQL, и процессор будет бездействовать, чтобы дождаться результата. io waitРассчитан на 1 секунду или 1000 миллисекунд. Если вашему коду требуется 100 миллисекунд для чтения данных с жесткого диска, то значение io_wait100/1000 = 10%. Чем меньше ожиданий ввода-вывода, тем выше производительность системы.

Чтобы продолжить, убедитесь, что в вашей системе есть пакет sysstat .

  1. Для Arch Linux установите with pacman -S sysstat
  2. Для Debian / Ubuntu вы можете получить их с apt-get install sysstat
  3. Для Fedora / Centos, вы можете использовать yum install sysstat
  4. Для других дистрибутивов: используйте менеджер дистрибутива для его установки.

После установки давайте оценим некоторые команды, которые мы будем использовать. Первым делом первым:

1
2
3
4
5
6
7
8
[vagrant@vagrant-centos64 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

Четвертая строка содержит данные о состоянии ввода-вывода. Мы заинтересованы в iowaitстоимости в четвертом столбце. Данные из седьмой строки в будущем содержат блок чтения / записи в секунду жесткого диска.

Если к серверу подключено много жестких дисков, у вас будет более одного устройства: sdb, sdc и т. Д.
Данные — это количество блоков вместо реального размера в мегабайтах. Мы должны найти размер блока, чтобы рассчитать общий размер.
Размер блока хранится в / sys / block / sda / queue / Physical_block_size .

1
2
3
[vagrant@vagrant-centos64 ~]$ cat /sys/block/sda/queue/physical_block_size
512
[vagrant@vagrant-centos64 ~]$

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

С базовыми знаниями, давайте создадим наш класс Iostatв widget/iostat.php.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
 
namespace AX\StatBoard\Widget;
 
class Iostat implements Provider {
  function __construct() {
  }
 
  public function get_title() {
    return "Disk IO";
  }
 
 
  /**
   * Make sure we install package sysstat
   * yum install sysstat
   * or apt-get install sysstat
   *
   * Return IO Stat information. CPU waiting time, disk read/write
   *
   */
  function get_metric() {
    $metric = array();
 
    $output = `iostat`;
    $number_of_core = intval(`/bin/grep -c processor /proc/cpuinfo`);
 
    $lines = explode("\n", $output);
    //We should have more than 4 lines
    if (!is_array($lines) || sizeof($lines)<4) {
      return false;
    }
    $avg_cpu = preg_split("/\s+/", $lines[3]);
    $metric['cpu'] = array(
      'user' => floatval($avg_cpu[0]) * $number_of_core,
      'system' => 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)<5) {
          continue;
        }
        // Calculate block size
        $block_size = shell_exec("cat /sys/block/{$lines[1]}/queue/physical_block_size");
 
        $metric['disk'][$line[0]] = array(
          'read' => floatval($line[2]) * $block_size / 1024,
          'write' => floatval($line[3]) * $block_size / 1024,
        );
 
      }
    }
 
    return $metric;
  }
 
}

Мы просто пытались реализовать нашу теорию в PHP-коде. Получив вывод iostat, превратить его в массив с каждой строкой является элементом.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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 <<<EOD
      <div id="widget_disk_io"></div>
      <div id="widget_cpu_io_wait"></div>
      <script type=»text/javascript»>
      google.load('visualization', '1', {packages:['gauge']});
      google.setOnLoadCallback(function () {
        var data = google.visualization.arrayToDataTable({$cpu_io});
        var goptions = {
          redFrom: 80, redTo: 100,
          yellowFrom:50, yellowTo: 80,
          minorTicks: 5
        };
        var chart = new google.visualization.Gauge(document.getElementById('widget_cpu_io_wait'));
        chart.draw(data, goptions);
 
        var data2 = google.visualization.arrayToDataTable({$disk_io});
        var chart2 = new google.visualization.ColumnChart(document.getElementById('widget_disk_io'));
        chart2.draw(data2, {});
      })
    </script>
EOD;
 
  }

Для чтения и записи дискового ввода-вывода мы использовали гистограмму. Для ввода — вывода ожидания, мы используем калибровочную диаграмму , чтобы сделать его хорошо выглядеть. Мы считаем, что IOwait 80-100 является критическим инцидентом, и выделим его красным.

Для 50-80 мы выделяем желтым цветом. Датчик позволяет нам сделать это с опцией:

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

Давайте посмотрим на нашу тяжелую работу в реальной жизни:

DISK IO на линейчатой ​​диаграмме и калибровочной диаграмме для ожидания ввода-вывода

На данный момент мы закончили все виджеты для нашего плагина. Вы можете скачать плагин в этом руководстве, чтобы не вводить весь код руководства. Установка плагина, затем обновление панели инструментов и использование опции экрана, чтобы решить, какой виджет вы хотите показать.

Наш плагин прекрасно работает на этом этапе; тем не менее, мы можем пойти дальше, внедрив проверку пользователей и ролей, поскольку данные могут быть конфиденциальными.

Мы также должны использовать cronjob, чтобы получить эти метрики. Оставайтесь с нами для следующей части.

Как всегда, обязательно оставьте комментарий, чтобы сообщить нам, что вы думаете о плагине, и если вы настроите его (а также как!).