回想一下,所有小部件提供程序都必須實現 Provider 接口。它們還必須位于名為 widget 的文件夾內,并位于名稱空間 AXStatBoardWidget 下。如果我們想添加一種新的指標,只需創建一個相應的類,并創建一個對象并使用 add_provider 方法將其添加到 Widget 類中。
RAM 使用情況小部件
我們想要顯示的第一條信息是當前正在使用的 RAM 量以及當前空閑的 RAM 量。
在本例中,free -m 是我們的朋友 – 它告訴我們 RAM 使用情況。 -m 開關是以兆字節為單位輸出結果。
[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 。
<?php namespace AXStatBoardWidget; class Ram implements Provider { function __construct() { } public function get_title() { return "Ram Usage"; } ?>
接下來,我們將實現 get_metric 來實際運行必要的 shell 命令并提取信息。稍后我將解釋 get_metric 的更多細節。
<?php function get_metric() { $df = `free -m | grep -E "(Mem|Swap)" | awk '{print $1, $2, $3, $4}'`; $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 “內存|交換” | awk ‘{print $1, $2, $3, $4}’ .它的輸出看起來與此類似。
[vagrant@vagrant-centos64 ~]$ free -m | grep -E "Mem|Swap" | awk '{print $1, $2, $3, $4}' Mem: 589 541 47 Swap: 255 0 255 [vagrant@vagrant-centos64 ~]$
我們通過將行拆分為數組來使用 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
EOD; } 我們使用堆積條形圖來顯示 RAM 使用情況。
安裝的軟件
我們將介紹的第二個小部件是顯示已安裝軟件的小部件。它是一個小部件,旨在顯示我們在服務器上有哪些常見軟件包以及哪個版本。
<?php namespace AXStatBoardWidget; 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>' . $version; } return $cmds; }
因此,與往常一樣,我們有 get_title ,它只返回一個簡單的字符串。對于 get_metric(),我們想知道是否安裝了特定的軟件。如果有,則獲取其版本信息。
public function get_content() { $cmds = $this->get_metric(); $content = ''; foreach ( $cmds as $cmd => $info ) { $content .= "<p><strong>$cmd</strong>? $info</p>"; } echo $content; }
我們只是展示此類數據的基本表格。這是顯示時的儀表板:
磁盤使用情況
現在我們將解決磁盤使用問題。我們將處理此任務的類命名為 Disk。讓我們先制作基本骨架。
<?php namespace AXStatBoardWidget; class Disk implements Provider { function __construct() { } public function get_title() { return "Disk Usage"; } }
與往常一樣,我們必須實現 Provider 接口。我們在這里為我們的小部件設置一個標題。接下來是我們課程的核心:獲取磁盤使用情況的方法。
<?php function get_metric() { $df = `df -h`; $df = explode("n", $df); if (is_array($df) && count($df)>=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 命令有了一些了解,因此理解以下命令應該很容易:
[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.
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); } }
我們遍歷度量數組并嘗試將 MB 空間轉換為 GB 空間。我們構建一個數組來匹配圖表數據格式要求。數據數組應如下所示:
[ ['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
EOD; } 我們創建了兩個 div 元素來包含信息
<div id="widget_disk_usage"></div> <div id="widget_disk_partion"></div>
然后,使用圖表 API 的繪制方法將圖表渲染在這些元素內。這里最令人困惑的事情可能是我們圖表的數據格式。
服務器信息
這個小部件向我們顯示信息:linux 內核、CPU 架構、正常運行時間、IP 地址。我們這里不需要圖表,一個簡單的數據表就可以完成這項工作。調用該類是Server。這是 widget/server.php
的第一個內容
<?php namespace AXStatBoardWidget; 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. -f1 /proc/uptime`; $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 | grep Mem | awk '{print $2}'`; $server['cpu'] =`cat /proc/cpuinfo | grep "model name" | awk '{print $4,$5,$6,$7}'`; return $server; } }
至此,您應該熟悉 get_title()。我們只是返回這個小部件的標題。
主機名
顯示您的服務器主機名。
名稱-sr
顯示Linux內核信息:
[vagrant@vagrant-centos64 ~]$ uname -sr Linux 2.6.32-358.23.2.el6.x86_64
grep -c ^處理器/proc/cpuinfo
-c 開關打印輸入字符串中匹配行的計數。 /proc/cpuinfo 包含處理器信息。我們 grep 它并計算文字處理器的出現次數。這是我的 32 核結果。
$ grep -c ^processor /proc/cpuinfo 32
剪切-d。 -f1 /proc/uptime
此命令顯示服務器已啟動并運行的秒數。我們將秒數轉換為“x 天 y 小時 z 分鐘”的格式,以使其更加用戶友好。
使用 DateTime::diff 我們可以輕松實現這一點。我們創建一個帶有當前時間戳的 DateTime 對象,另一個帶有時間戳的對象是當前時間戳減去正常運行時間的秒數。然后使用 format 方法將其格式化為人類友好的字符串。
這是我的結果,正常運行時間為 26194091 秒。
$ cut -d. -f1 /proc/uptime 26194091
卷曲 ifconfig.me
ifconfig.me 是一項在瀏覽器內直接訪問時顯示您的 IP 地址的服務。如果您使用 curl 向其發送請求,它將以單個字符串形式返回您的 IP 地址。
[vagrant@vagrant-centos64 ~]$ curl ifconfig.me 76.102.253.237
CPU型號
如上所述,/proc/cpuinfo存儲了CPU信息。我們可以從中提取CPU型號。例如:
[vagrant@vagrant-centos64 ~]$ 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 Ip Address?{$server['ip']}<br><strong>CPU</strong>? {$server['cpu']}<br><strong>Number of Core</strong>? {$server['core']}<br><strong>Ram</strong>? {$server['ram']}<br><strong>Hostname</strong>?{$server['hostname']}<br><strong>OS</strong> {$server['os']}<br><strong>Uptime</strong> {$server['uptime']}<br> EOD; }
這是儀表板上的小部件。
處理器
監控我們的處理器是其中之一我們可以展示的最重要的東西。我們想知道某個特定進程正在使用多少 CPU 和/或消耗了多少內存。我們將我們的類稱為 Process,首先從 get_title 和 get_metric 開始。我將在代碼后面解釋 get_metric 的更多細節:
<?php namespace AXStatBoardWidget; 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 | grep -v '[' | sort -k 1 -r | head -30 | awk '{print $4,$3,$1,$2,$7,$6,$5}'`; $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、用戶、參數、時間和啟動。
[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]、[migration/0]。基本上,這意味著該命令無法在文件系統中找到。它可能是一些內部系統進程或內核線程,我們可能永遠不想關心它。因此,我們應該使用 grep 來消除這些進程。 grep 有 -v 開關使我們能夠反轉匹配。它返回的結果不包含我們傳遞給它的字符串。
[vagrant@vagrant-centos64 ~]$ 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
為了使數據看起來不錯,我們應該按內存或CPU對進程進行排序。在我們的教程中,我們按 %MEM 排序。我們可以使用Linux的sort命令來做到這一點。 %MEM 是第二列。
[vagrant@vagrant-centos64 ~]$ 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 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 循環它。我們將同名進程分組到一個元素中,并將 CPU 百分比和內存添加到其中。
<?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 從兩個數組創建一個關聯數組:一個用于鍵,一個用于值。
public function get_content() { $processes = $this->get_metric(); $html = '
User | Pid | %CPU | %Mem | Command |
---|---|---|---|---|
{$process[‘user’]} | {$process[‘pid’]} | {$process[‘%cpu’]} | {$process[‘%mem’]} | {$process[‘command’]} |
‘; echo $html; } 這是我們得到的結果:
平均負載
Linux 有一個命令可以顯示過去一分鐘、五分鐘和 15 分鐘內 CPU 和 IO 的平均負載。讓我們把它壓縮成一個小部件。稱之為 Cpuload,并創建我們的 widget/cpuload.php
<?php namespace AXStatBoardWidget; class Cpuload implements Provider { function __construct() { } public function get_title() { return "CPU Load"; } function get_metric() { $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 來統計 CPU 核心數,并統計包含“processor”一詞的行數。我們在服務器信息
部分對此進行了介紹。
? ~ 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 數組,并除以我們擁有的核心數。請注意,我們創建了 2 個與 $loadAvg 長度相同的額外數組,一個用于鍵,另一個用于保存核心數,以便將所有這些一一傳遞給 array_map。
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; } 我們使用條形圖并從數組創建一個數據數組,然后使用 json_encode 將其轉換為與條形圖數據格式匹配的 JavaScript 表示法數組。
[ ["Duration","% Load"], ["1 min",20], ["5 mins",11], ["15 mins",3]]
這是渲染圖表時的結果:
以太網接口
我們要處理的下一個小部件是以太網接口。某些服務器可以有多個以太網接口,并為其分配不同的 IP 地址。
看到這些信息非常有用。我們將這個類稱為 Ethernet,從 widget/ethernet.php 的基本內容開始。
<?php /** * Adopt from https://github.com/afaqurk/linux-dash/blob/master/sh/ip.php * */ namespace AXStatBoardWidget; 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 | /bin/grep -B1 "inet addr" | /usr/bin/awk '' . '{ if ( $1 == "inet" ) { print $2 }' . 'else if ( $2 == "Link" ) { printf "%s:",$1 } }' | /usr/bin/awk' . ' -F: '{ print $1","$3 }'' ); $output = trim($output, " n"); $output = `ifconfig | grep "Link encap" | awk '{ print $1 }'`; $interfaces = explode("n", $output); $output = `ifconfiga | grep "inet addr" | awk '{ print $2 }' | sed 's/addr://'`; $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); } }
所以小部件的標題將是以太網。對于 get_metric,我們將嘗試獲取所有以太網接口名稱,然后獲取每個接口的 IP 地址,并將設備名稱和 IP 地址結合起來返回。
$output = shell_exec("ip -oneline link show | awk '{print $2}' | sed 's/://'");
使用 IP 實用程序
帶有 ip 命令和 -oneline 將僅在一行中顯示輸出,其中 link 和 show 將列出所有設備。我們使用 awk 獲取第二列,其中包含設備名稱;但是它包含 : 字符。我們使用 sed 將 : 替換為空字符串。
[vagrant@vagrant-centos64 sbin]$ ip -oneline link show 1: lo: <loopback> mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <broadcast> 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> 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 | awk '{print $2}' lo: eth0: eth1: [vagrant@vagrant-centos64 sbin]$ ip -oneline link show | awk '{print $2}' | sed 's/://' lo eth0 eth1 [vagrant@vagrant-centos64 sbin]$ </broadcast></broadcast></loopback>
如果 shell_exec 成功運行,我們將繼續使用 IP 實用程序。上面的輸出被逐行分割成一個數組。
$output = trim($output, " n"); $interfaces = explode("n", $output);
然后我們循環遍歷該數組,并再次使用 ip 命令 ip -oneline -family inet addr show device_name 來獲取分配給設備的 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 用于打印該值。然后我們使用 cut 將命令按 / 分割,并使用 swich -f1 獲取第一個元素。
[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 | awk '{print $4}' 192.168.1.111/24 [vagrant@vagrant-centos64 sbin]$ ip -oneline -family inet addr show eth1 | awk '{print $4}' | cut -d'/' -f1 192.168.1.111 [vagrant@vagrant-centos64 sbin]$
當我們在接口數組中獲取設備名稱并在地址數組中獲取 IP 地址時,我們創建一個關聯數組,其中接口名稱作為鍵,IP 地址作為值。
return array_combine($interfaces, $addreses);
使用 ifconfig 的服務器
在 ifconfig 的情況下,ip 的 shell_exec 將返回 false。在這種情況下,我們改為運行 ifconfig。
if (!$output) { // It didn't work with "ip" , so we do it with ifconfig $output = `ifconfig | grep "Link encap" | 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); }
讓我們在終端中運行上面的命令,以便我們了解發生了什么。
[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 | grep "Link encap" 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 | grep "Link encap" | awk '{ print $1 }' eth0 eth1 lo [vagrant@vagrant-centos64 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 [vagrant@vagrant-centos64 sbin]$ ifconfig | grep "inet addr" | awk '{ print $2 }' addr:10.0.2.15 addr:192.168.1.111 addr:127.0.0.1 [vagrant@vagrant-centos64 sbin]$ ifconfig | grep "inet addr" | awk '{ print $2 }' | sed 's/addr://' 10.0.2.15 192.168.1.111 127.0.0.1 [vagrant@vagrant-centos64 sbin]$
一旦我們有了數據,將它們放入 get_content 中就很容易了,因為我們在這里只顯示了一個簡單的表格。
public function get_content() { $interfaces = $this->get_metric(); $html = '
Interface | IP |
---|---|
{$interface} | {$ip} |
‘; echo $html; } 以下是它向管理員顯示的方式:
網絡流量
網絡流量或網絡 IO 顯示通過計算機網絡傳輸包的狀態。該信息是從 netstat 中提取的。
[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
讓我們在文件 widget/networkio.php 中獲取我們的基本類 Networkio
<?php /** * Adopt from https://github.com/afaqurk/linux-dash/blob/master/sh/ip.php * */ namespace AXStatBoardWidget; class Networkio implements Provider { function __construct() { } public function get_title() { return "Network IO"; } 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; }}
我將在本文后面解釋它們。現在,讓我們嘗試評估我們在上面代碼中使用的命令。
[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]$
netstat 返回很多東西,我們使用 grep 來排除包含單詞 Iface 或 Kernel 的行(前兩行),我們只關心最后三行是我們的以太網設備及其包傳輸。 awk 用于打印出第一、四、八列的數據,分別表示接口名稱、RX-OK、TX-OK。
在我們的get_metric中,我們將結果逐行拆分到一個數組中。因為每一行都包含用逗號分隔的數據,所以它們被再次分割成一個數組。
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; } 我們之前使用了條形圖,并嘗試將指標數據數組格式化為條形圖數據格式,然后進行渲染。
輸入/輸出統計
現在,我們處理 io stat。 IO 表示輸入/輸出。我們將了解每秒執行多少次讀/寫操作。我們還處理 io_wait。 IO等待是CPU空閑等待從硬盤讀取結果的時間。
比如你正在讀取MySQL數據,CPU會空閑下來等待結果。 io wait 按1秒或1000毫秒計算。如果您的代碼需要 100 毫秒從硬盤讀取數據,則 io_wait 為 100/1000 = 10%。 IO 等待越少,系統性能越好。
為了繼續執行此操作,請確保系統上有 sysstat 軟件包。
- 對于 Arch Linux,使用 pacman -S sysstat 安裝
- 對于 debian/ubuntu,您可以使用 apt-get install sysstat 獲取它們
- 對于 Fedora/Centos,您可以使用 yum install sysstat
- 對于其他發行版,:請使用您的發行版包管理器進行安裝
安裝完成后,讓我們評估一下我們將使用的一些命令。首先是第一件事:
[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
第四行包含IO狀態數據。我們對第四列中的 iowait 值感興趣。從第七行開始的數據包含硬盤驅動器每秒的讀/寫塊。
[vagrant@vagrant-centos64 ~]$ cat /sys/block/sda/queue/physical_block_size 512 [vagrant@vagrant-centos64 ~]$
所以我的sda的塊大小是512。我們將每秒讀取的塊數與塊大小相乘,得到讀/寫數據的實際大小。
有了上面的基本知識,讓我們在 widget/iostat.php 中創建我們的類 Iostat 。
<?php namespace AXStatBoardWidget; 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 floatval($line[2]) * $block_size / 1024, 'write' => floatval($line[3]) * $block_size / 1024, ); } } return $metric; } }
我們只是嘗試將我們的理論應用到 PHP 代碼中。獲取 iostat 的輸出,將其轉換為數組,每一行都是一個元素。
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; } 對于磁盤 IO 讀寫,我們使用了條形圖。對于 IO 等待,我們使用儀表圖來使其看起來更漂亮。我們認為 80-100 的 IOwait 是一個嚴重事件,并用紅色突出顯示。