您好,欢迎访问一九零五行业门户网

将Transforming a WordPress Server Dashboard into a Widget

在上一篇文章中,我们创建了插件的基本结构。现在是时候为每个小部件实现渲染类了。
回想一下,所有小部件提供程序都必须实现 provider 接口。它们还必须位于名为 widget 的文件夹内,并位于名称空间 ax\statboard\widget 下。如果我们想添加一种新的指标,只需创建一个相应的类,并创建一个对象并使用 add_provider 方法将其添加到 widget 类中。
ram 使用情况小部件我们想要显示的第一条信息是当前正在使用的 ram 量以及当前空闲的 ram 量。
在本例中,free -m 是我们的朋友 - 它告诉我们 ram 使用情况。 -m 开关是以兆字节为单位输出结果。
[vagrant@vagrant-centos64 ~]$ free -m total used free shared buffers cachedmem: 589 366 223 0 9 57-/+ buffers/cache: 299 290swap: 0 0 0
我们将类命名为 ram。相应的文件将为 widget/ram.php。我们在这里只是编写基础并实现 get_title 。
<?phpnamespace ax\statboard\widget;class ram implements provider { function __construct() { } public function get_title() { return ram usage; }?>
接下来,我们将实现 get_metric 来实际运行必要的 shell 命令并提取信息。稍后我将解释 get_metric 的更多细节。<?phpfunction 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 47swap: 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 <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; }
我们使用堆积条形图来显示 ram 使用情况。
首先,我们调用 get_metric() 来获取必要的数据。然后,我们只需循环它并格式化它以匹配 google 图表数据要求。最后,我们使用 json_encode 将它们转换为 javascript 对象表示法(或 json)。然后,我们输出一个 html 代码,其中包含 div 元素来保存图表对象。
最后,我们调用相应的 google chart api 将图表渲染到 div 元素中。
安装的软件
我们将介绍的第二个小部件是显示已安装软件的小部件。它是一个小部件,旨在显示我们在服务器上有哪些常见软件包以及哪个版本。
例如,我们是否安装了 nodejs,是否安装了 ruby?我们使用的是哪个版本的 php?等等。
让我们使用以下初始内容创建 widget/software.php:<?phpnamespace 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>' . $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 .= <p><strong>$cmd</strong>&nbsp; $info</p>; } echo $content; }
我们只是展示此类数据的基本表格。这是显示时的仪表板:
磁盘使用情况现在我们将解决磁盘使用问题。我们将处理此任务的类命名为 disk。让我们先制作基本骨架。
<?phpnamespace ax\statboard\widget;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 命令有了一些了解,因此理解以下命令应该很容易:
回想一下 df 输出:
[vagrant@vagrant-centos64 ~]$ df -hfilesystem 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 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 元素来包含信息 <div id=widget_disk_usage></div> <div id=widget_disk_partion></div>
然后,使用图表 api 的绘制方法将图表渲染在这些元素内。这里最令人困惑的事情可能是我们图表的数据格式。
结果如下:
服务器信息这个小部件向我们显示信息:linux 内核、cpu 架构、正常运行时间、ip 地址。我们这里不需要图表,一个简单的数据表就可以完成这项工作。调用该类是server。这是 widget/server.php
的第一个内容<?phpnamespace 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. -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()。我们只是返回这个小部件的标题。
首先,我们使用语句 use datetime 因为我们位于名称空间 ax\statboard\widget 中,并且 datetime 类来自全局命名空间。每次我们想要使用 datetime 时,我们都必须输入 \datetime。因此,我们使用命名空间导入来使 datetime 名称在我们当前的命名空间中可用。
将其视为符号链接。在 get_metric 中,我们运行 shell 命令来获取结果并将其分配回来。
主机名显示您的服务器主机名。
名称-sr显示linux内核信息:
[vagrant@vagrant-centos64 ~]$ uname -srlinux 2.6.32-358.23.2.el6.x86_64
grep -c ^处理器/proc/cpuinfo -c 开关打印输入字符串中匹配行的计数。 /proc/cpuinfo 包含处理器信息。我们 grep 它并计算文字处理器的出现次数。这是我的 32 核结果。
$ grep -c ^processor /proc/cpuinfo32
剪切-d。 -f1 /proc/uptime
此命令显示服务器已启动并运行的秒数。我们将秒数转换为“x 天 y 小时 z 分钟”的格式,以使其更加用户友好。
使用 datetime::diff 我们可以轻松实现这一点。我们创建一个带有当前时间戳的 datetime 对象,另一个带有时间戳的对象是当前时间戳减去正常运行时间的秒数。然后使用 format 方法将其格式化为人类友好的字符串。
这是我的结果,正常运行时间为 26194091 秒。
$ cut -d. -f1 /proc/uptime26194091
卷曲 ifconfig.me
ifconfig.me 是一项在浏览器内直接访问时显示您的 ip 地址的服务。如果您使用 curl 向其发送请求,它将以单个字符串形式返回您的 ip 地址。
[vagrant@vagrant-centos64 ~]$ curl ifconfig.me76.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 <<<eod <strong>ip address</strong>&nbsp;{$server['ip']}<br> <strong>cpu</strong>&nbsp; {$server['cpu']}<br> <strong>number of core</strong>&nbsp; {$server['core']}<br> <strong>ram</strong>&nbsp; {$server['ram']}<br> <strong>hostname</strong>&nbsp;{$server['hostname']}<br> <strong>os</strong> {$server['os']}<br> <strong>uptime</strong> {$server['uptime']}<br>eod; }
这是仪表板上的小部件。
处理器监控我们的处理器是其中之一我们可以展示的最重要的东西。我们想知道某个特定进程正在使用多少 cpu 和/或消耗了多少内存。我们将我们的类称为 process,首先从 get_title 和 get_metric 开始。我将在代码后面解释 get_metric 的更多细节:
<?phpnamespace 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 | 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、用户、参数、时间和启动。
我们可以结合 -o 表示用户定义的格式,例如: ps -eo pcpu,pmem,pid,user,args,time,start。如果您尝试该命令,您将得到一些奇怪的过程,例如:
[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 是第二列。
就像索引为零的数组一样,第二个元素通过索引键 1 访问。我们可以使用 sort -k 1。它按从最低到最高的顺序排序。我们实际上关心的是首先消耗大量内存的进程。为此,我们应该使用 sort -k 1 -r 反转顺序。一旦我们得到结果,我们可能只需要前30个过程。当然,这取决于您,因为您可以选择包含所有内容,但我想保持简短。 30 听起来是一个合理的数字。
最后,我们使用 awk 来格式化输出。这是我们的命令和示例输出:
[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/udevdroot 1152 0.0 0.0 00:00:00 -d /sbin/udevdroot 292 0.0 0.0 00:00:00 -d /sbin/udevdroot 811 0.0 0.0 vagrant-c -h /sbin/dhclientroot 1 0.0 0.1 06:50:39 00:00:00 /sbin/initroot 2153 0.0 0.1 -q -1 /sbin/dhclientroot 3642 0.0 0.1 00:00:00 -s /usr/sbin/anacronvagrant 3808 0.0 0.1 pcpu,pmem,pid,user,a -eo psvagrant 3810 0.0 0.1 1 -k sortvagrant 3811 0.0 0.1 00:00:00 -30 headvagrant 3812 0.0 0.1 $4,$3,$1,$2,$7,$ {print awkroot 948 0.0 0.1 /var/run/ -i /sbin/rsyslogdrpc 966 0.0 0.1 06:50:50 00:00:00 rpcbindroot 1073 0.0 0.2 06:50:51 00:00:00 /usr/sbin/vboxserviceroot 1105 0.0 0.2 06:50:51 00:00:00 /usr/sbin/sshdroot 1121 0.0 0.2 06:50:52 00:00:00 crondrpcuser 984 0.0 0.2 06:50:50 00:00:00 rpc.statd496 1088 0.0 0.3 -p -d memcachedvagrant 3544 0.0 0.3 00:00:00 vagrant@pts/0 sshd:vagrant 3545 0.0 0.3 06:59:27 00:00:00 -bashroot 1113 0.0 1.7 06:50:52 00:00:00 /usr/sbin/httpdapache 1157 0.0 4.2 06:50:53 00:00:01 /usr/sbin/httpdapache 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 从两个数组创建一个关联数组:一个用于键,一个用于值。
剩下的就是实现 get_content 方法。只是提醒我们必须实现三个方法: get_title, get_metric 和 get_content.对于这个过程,我们只想展示一个简单的表格。
我们的 get_content 方法很简单。
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 分钟内 cpu 和 io 的平均负载。让我们把它压缩成一个小部件。称之为 cpuload,并创建我们的 widget/cpuload.php
<?phpnamespace ax\statboard\widget;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”一词的行数。我们在服务器信息
部分对此进行了介绍。
在linux中,/proc/loadavg保存平均负载信息。前三列分别是1分钟、5分钟和15分钟的负载。 awk 在这里用于过滤掉我们需要的字段。➜ ~ cat /proc/loadavg0.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。
get_content 的时间:
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 表示法数组。
例如:
[ [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 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 | /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 地址结合起来返回。
我们需要处理两种情况:如果服务器使用 ifconfig 或服务器使用 ip 实用程序。较新的服务器很可能有 ip 而不是 ifconfig; 因此,我们应该首先运行 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 show1: 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:002: 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:ff3: 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 | awk '{print $2}'lo:eth0:eth1:[vagrant@vagrant-centos64 sbin]$ ip -oneline link show | awk '{print $2}' | sed 's/://'loeth0eth1[vagrant@vagrant-centos64 sbin]$
如果 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 eth13: 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'/' -f1192.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); }
让我们在终端中运行上面的命令,以便我们了解发生了什么。
请注意,ifconfig 直接在输出中显示 ip 地址,因此我们可以直接获取它们,而不是在设备数组上运行循环并获取每个设备的 ip 地址。
[vagrant@vagrant-centos64 sbin]$ ifconfigeth0 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 encapeth0 link encap:ethernet hwaddr 08:00:27:08:c2:e4eth1 link encap:ethernet hwaddr 08:00:27:eb:11:e4lo link encap:local loopback[vagrant@vagrant-centos64 sbin]$ ifconfig | grep link encap | awk '{ print $1 }'eth0eth1lo[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.15addr:192.168.1.111addr:127.0.0.1[vagrant@vagrant-centos64 sbin]$ ifconfig | grep inet addr | awk '{ print $2 }' | sed 's/addr://'10.0.2.15192.168.1.111127.0.0.1[vagrant@vagrant-centos64 sbin]$
一旦我们有了数据,将它们放入 get_content 中就很容易了,因为我们在这里只显示了一个简单的表格。
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; }
以下是它向管理员显示的方式:
网络流量网络流量或网络 io 显示通过计算机网络传输包的状态。该信息是从 netstat 中提取的。
[vagrant@vagrant-centos64 sbin]$ netstat -ikernel interface tableiface mtu met rx-ok rx-err rx-drp rx-ovr tx-ok tx-err tx-drp tx-ovr flgeth0 1500 0 4828 0 0 0 2933 0 0 0 bmrueth1 1500 0 4806 0 0 0 2679 0 0 0 bmrulo 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 ax\statboard\widget;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 -ikernel interface tableiface mtu met rx-ok rx-err rx-drp rx-ovr tx-ok tx-err tx-drp tx-ovr flgeth0 1500 0 5727 0 0 0 3400 0 0 0 bmrueth1 1500 0 5004 0 0 0 2797 0 0 0 bmrulo 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 bmrueth1 1500 0 5004 0 0 0 2797 0 0 0 bmrulo 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,3420eth1,5004,2797lo,292,292[vagrant@vagrant-centos64 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 <<<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等待是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]$ iostatlinux 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.66device: tps blk_read/s blk_wrtn/s blk_read blk_wrtnsda 0.18 7.62 1.04 157826 21584
第四行包含io状态数据。我们对第四列中的 iowait 值感兴趣。从第七行开始的数据包含硬盘驱动器每秒的读/写块。
如果您有许多硬盘连接到服务器,您将拥有多个设备:sdb、sdc 等。
数据是块的数量,而不是实际大小(以兆字节为单位)。我们必须找到块大小来计算总大小。
块大小存储在/sys/block/sda/queue/physical_block_size中。
[vagrant@vagrant-centos64 ~]$ cat /sys/block/sda/queue/physical_block_size512[vagrant@vagrant-centos64 ~]$
所以我的sda的块大小是512。我们将每秒读取的块数与块大小相乘,得到读/写数据的实际大小。
有了上面的基本知识,让我们在 widget/iostat.php 中创建我们的类 iostat 。
<?phpnamespace 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 并渲染我们的图表。
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; }
对于磁盘 io 读写,我们使用了条形图。对于 io 等待,我们使用仪表图来使其看起来更漂亮。我们认为 80-100 的 iowait 是一个严重事件,并用红色突出显示。
以上就是将transforming a wordpress server dashboard into a widget的详细内容。
其它类似信息

推荐信息