2 # collectd - OpenVZ collectd plugin
3 # Copyright (C) 2009 Jonathan Kolb
5 # This program is free software; you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 2 of the License, or (at your option) any later
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 # Jonathan Kolb <jon at b0g.us>
23 package Collectd::Plugins::OpenVZ;
28 #use Collectd qw( :all );
30 my $vzctl = '/usr/sbin/vzctl';
31 my $vzlist = '/usr/sbin/vzlist';
33 # Since OpenVZ is container based, all guests see all the host's CPUs,
34 # and would report the same data. So we disable CPU by default.
35 my $enable_interface = 1;
39 my $enable_processes = 1;
42 # We probably don't care about loopback transfer
43 my @ignored_interfaces = ( "lo" );
45 sub interface_read($$) {
48 my ($current_interface, $val, @lines, @parts, @counters, $i);
49 my @if_instances = ('if_octets', 'if_packets', 'if_errors');
50 my %v = _build_report_hash($name);
52 $v{'plugin'} = 'interface';
53 delete $v{'plugin_instance'};
55 @lines = split(/\n/, `$vzctl exec $veid cat /proc/net/dev`);
56 #$ vzctl exec 1106221 cat /proc/net/dev
57 #Inter-| Receive | Transmit
58 # face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
59 # lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
60 # venet0: 2420 27 0 0 0 0 0 0 2200 29 0 0 0 0 0 0
65 ($current_interface = $parts[0]) =~ s/^\s*(.*?)\s*$/$1/;
66 next if grep { $current_interface eq $_ } @ignored_interfaces;
68 ($val = $parts[1]) =~ s/^\s*(.*?)\s*$/$1/;
69 @counters = split(/ +/, $val);
71 $v{'plugin_instance'} = $current_interface;
72 for ($i= 0; $i <= $#if_instances; ++$i) {
73 $v{'type'} = $if_instances[$i];
74 $v{'values'} = [ $counters[$i], $counters[$i + 8] ];
75 plugin_dispatch_values(\%v);
83 my ($key, $val, $i, @lines, @counters);
84 my @cpu_instances = ('user', 'nice', 'system', 'idle', 'wait', 'interrupt', 'softirq', 'steal');
86 my %v = _build_report_hash($name);
92 @lines = split(/\n/, `$vzctl exec $veid cat /proc/stat`);
94 next if (!/^cpu[0-9]/);
96 @counters = split(/ +/);
99 # Remove once OpenVZ bug 1376 is resolved
100 if (48485 == $counters[3]) {
101 $counters[3] = $last_stat->{"$veid-$i-idle"};
102 $counters[4] = $last_stat->{"$veid-$i-wait"};
105 $last_stat->{"$veid-$i-idle"} = $counters[3];
106 $last_stat->{"$veid-$i-wait"} = $counters[4];
109 $v{'plugin_instance'} = $i++;
110 for ($key = 0; $key <= $#counters; ++$key) {
111 $v{'type_instance'} = $cpu_instances[$key];
112 $v{'values'} = [ $counters[$key] ];
113 plugin_dispatch_values(\%v);
121 my ($key, $val, @lines, @parts);
122 my %v = _build_report_hash($name);
125 delete $v{'plugin_instance'};
128 $val = join(' ', map { (split)[1] } split(/\n/, `$vzctl exec $veid cat /proc/mounts`));
129 @lines = split(/\n/, `$vzctl exec $veid stat -tf $val`);
132 next if (0 == $parts[7]);
134 $val = substr($parts[0], 1);
135 $val = 'root' if ($val =~ /^$/);
138 $v{'type_instance'} = $val;
139 $v{'values'} = [ $parts[5] * ($parts[6] - $parts[7]), $parts[5] * $parts[7] ];
140 plugin_dispatch_values(\%v);
147 my ($key, $val, @lines, @parts);
148 my %v = _build_report_hash($name);
150 $v{'plugin'} = 'load';
151 delete $v{'plugin_instance'};
153 delete $v{'type_instance'};
155 @parts = split(/ +/, `$vzctl exec $veid cat /proc/loadavg`);
156 $v{'values'} = [ $parts[0], $parts[1], $parts[2] ];
157 plugin_dispatch_values(\%v);
160 sub processes_read($$) {
163 my ($key, $val, @lines);
164 my %v = _build_report_hash($name);
166 my $ps_states = { 'paging' => 0, 'blocked' => 0, 'zombies' => 0, 'stopped' => 0,
167 'running' => 0, 'sleeping' => 0 };
168 my $state_map = { 'R' => 'running', 'S' => 'sleeping', 'D' => 'blocked',
169 'Z' => 'zombies', 'T' => 'stopped', 'W' => 'paging' };
171 $v{'plugin'} = 'processes';
172 delete $v{'plugin_instance'};
173 $v{'type'} = 'ps_state';
175 @lines = map { (split)[2] } split(/\n/, `$vzctl exec $veid cat '/proc/[0-9]*/stat'`);
176 foreach $key (@lines) {
177 ++$ps_states->{$state_map->{$key}};
180 foreach $key (keys %{$ps_states}) {
181 $v{'type_instance'} = $key;
182 $v{'values'} = [ $ps_states->{$key} ];
183 plugin_dispatch_values(\%v);
190 my ($key, $val, @lines);
191 my %v = _build_report_hash($name);
193 $v{'plugin'} = 'users';
194 delete $v{'plugin_instance'};
195 $v{'type'} = 'users';
196 delete $v{'type_instance'};
198 @lines = split(/\n/, `$vzctl exec $veid w -h`);
199 $v{'values'} = [ scalar(@lines) ];
200 plugin_dispatch_values(\%v);
203 sub _build_report_hash($) {
205 return (time => time(), interval => plugin_get_interval(), host => $name);
209 my (@veids, $veid, $name);
211 @veids = map { s/ //g; $_; } split(/\n/, `$vzlist -Ho veid`);
213 foreach $veid (@veids) {
214 ($name = `$vzlist -Ho name $veid`) =~ s/^\s*(.*?)\s*$/$1/;
215 ($name = `$vzlist -Ho hostname $veid`) =~ s/^\s*(.*?)\s*$/$1/ if($name =~ /^-$/);
216 $name = $veid if ($name =~ /^-$/);
218 if($enable_interface) {
219 interface_read($veid, $name);
223 cpu_read($veid, $name);
227 df_read($veid, $name);
231 load_read($veid, $name);
234 if($enable_processes) {
235 processes_read($veid, $name);
239 users_read($veid, $name);
246 plugin_register(TYPE_READ, 'OpenVZ', 'openvz_read');