root / plugins / network / interfaces_linux_multi @ 17f78427
Historique | Voir | Annoter | Télécharger (15,8 ko)
| 1 | cdf6eeb3 | Adrien "ze" Urban | #! /usr/bin/perl |
|---|---|---|---|
| 2 | ######################################################################## |
||
| 3 | # Copyright (c) 2012, Adrien Urban |
||
| 4 | # All rights reserved. |
||
| 5 | 17f78427 | Lars Kruse | # |
| 6 | cdf6eeb3 | Adrien "ze" Urban | # Redistribution and use in source and binary forms, with or without |
| 7 | # modification, are permitted provided that the following conditions are |
||
| 8 | 17f78427 | Lars Kruse | # met: |
| 9 | # |
||
| 10 | cdf6eeb3 | Adrien "ze" Urban | # 1. Redistributions of source code must retain the above copyright |
| 11 | 17f78427 | Lars Kruse | # notice, this list of conditions and the following disclaimer. |
| 12 | cdf6eeb3 | Adrien "ze" Urban | # 2. Redistributions in binary form must reproduce the above copyright |
| 13 | # notice, this list of conditions and the following disclaimer in the |
||
| 14 | # documentation and/or other materials provided with the |
||
| 15 | 17f78427 | Lars Kruse | # distribution. |
| 16 | # |
||
| 17 | cdf6eeb3 | Adrien "ze" Urban | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
| 19 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
| 20 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
| 21 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
| 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
| 23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
| 24 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
| 25 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
| 26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
| 27 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
| 28 | # |
||
| 29 | ######################################################################## |
||
| 30 | # # |
||
| 31 | # WARNING WARNING WARNING WARNING WARNING WARNING # |
||
| 32 | # # |
||
| 33 | # This plugin does not work properly with multiple master # |
||
| 34 | # # |
||
| 35 | ######################################################################## |
||
| 36 | # |
||
| 37 | # multigraph, supersampling, detailed interfaces statistics |
||
| 38 | # |
||
| 39 | # require: ifconfig |
||
| 40 | # linux only for now. Would need to implement way to gather the same |
||
| 41 | # data for other ifconfig usage and output. |
||
| 42 | # require: Time::HiRes |
||
| 43 | # |
||
| 44 | # ENV (default): |
||
| 45 | # MUNIN_PLUGSTATE - pid and cache files gets there |
||
| 46 | # |
||
| 47 | # ENV (user defined): |
||
| 48 | # MUNIN_UPDATERATE - rate at which to update (default: 1s) |
||
| 49 | # MUNIN_CACHEFLUSH_RATE - flush data every N batch (default: 1) |
||
| 50 | # MUNIN_IFCONFIG - path for ifconfig (default /sbin/ifconfig) |
||
| 51 | # |
||
| 52 | # MUNIN_IF_INCLUDE - list of interfaces to graph (all by default) |
||
| 53 | # MUNIN_IF_EXCLUDE - exclude all of those interfaces (none by default) |
||
| 54 | # MUNIN_GRAPH_BYTES - do graph bytes per seconds (default: yes) |
||
| 55 | # MUNIN_GRAPH_PACKETS - do graph packets per seconds (default: yes) |
||
| 56 | # MUNIN_GRAPH_ERRORS - do graph errors (default: yes) |
||
| 57 | # |
||
| 58 | # Parent graphs: none |
||
| 59 | # child graphs: per interface - bytes, packets, errors |
||
| 60 | # interfaces/XXX/{bw,pkt,err}
|
||
| 61 | # |
||
| 62 | # Known bugs: |
||
| 63 | # |
||
| 64 | # Multi-Master |
||
| 65 | # If there are many masters, the data is only sent once. Each master will |
||
| 66 | # only have part of the data. |
||
| 67 | # |
||
| 68 | # Everlasting |
||
| 69 | # The daemon is launched on first config/fetch. A touch of the pidfile is |
||
| 70 | # done on every following config/fetch. The daemon should check if the |
||
| 71 | # pidfile is recent (configurable) enough, and stop itself if not. |
||
| 72 | # |
||
| 73 | # Graph Order |
||
| 74 | # There is currently (2.0.6) noway to order childgraphs. |
||
| 75 | # |
||
| 76 | # RRD file |
||
| 77 | # The master currently (2.0.6) generate rrd file for aggregate values, and |
||
| 78 | # complains that no data is provided for them (but the graph still works |
||
| 79 | # fine) |
||
| 80 | # |
||
| 81 | |||
| 82 | #%# family=auto |
||
| 83 | #%# capabilities=autoconf |
||
| 84 | |||
| 85 | use strict; |
||
| 86 | use warnings; |
||
| 87 | use Time::HiRes; |
||
| 88 | 191ef79a | Daniel Forsberg | use IO::Handle; |
| 89 | cdf6eeb3 | Adrien "ze" Urban | |
| 90 | my $plugin = $0; |
||
| 91 | $plugin =~ s/.*\///; |
||
| 92 | |||
| 93 | # quick failsafe |
||
| 94 | if (!defined $ENV{MUNIN_PLUGSTATE}) {
|
||
| 95 | die "This plugin should be run via munin. Try munin-run $plugin\n"; |
||
| 96 | } |
||
| 97 | |||
| 98 | ######################################################################## |
||
| 99 | # If you want to change something, it's probably doable here |
||
| 100 | # |
||
| 101 | |||
| 102 | sub pidfile() { "$ENV{MUNIN_PLUGSTATE}/munin.$plugin.pid" }
|
||
| 103 | sub cachefile() { "$ENV{MUNIN_PLUGSTATE}/munin.$plugin.cache" }
|
||
| 104 | |||
| 105 | sub graph_name() { "interfaces" }
|
||
| 106 | #sub graph_title() { "interfaces" }
|
||
| 107 | #sub graph_title_all() { "Overall CPU usage" }
|
||
| 108 | #sub graph_title_n($) { "CPU#" . shift . " usage" }
|
||
| 109 | sub acquire_name() { "<$plugin> collecting information" }
|
||
| 110 | |||
| 111 | # Default update rate. Can be changed by configuration. |
||
| 112 | my $update_rate = 1; |
||
| 113 | # default flush interval. Can be changed by configuration. |
||
| 114 | my $flush_interval = 1; |
||
| 115 | # default ifconfig command. Can be changed by configuration |
||
| 116 | my $ifconfig = '/sbin/ifconfig'; |
||
| 117 | |||
| 118 | ######################################################################## |
||
| 119 | # if you need to change something after that line, It should probably be |
||
| 120 | # changed to be configurable above it. |
||
| 121 | # |
||
| 122 | |||
| 123 | if (defined $ENV{MUNIN_UPDATERATE}) {
|
||
| 124 | if ($ENV{MUNIN_UPDATERATE} =~ /^[1-9][0-9]*$/) {
|
||
| 125 | $update_rate = int($ENV{MUNIN_UPDATERATE});
|
||
| 126 | } else {
|
||
| 127 | print STDERR "Invalid update_rate: $ENV{MUNIN_UPDATERATE}";
|
||
| 128 | } |
||
| 129 | } |
||
| 130 | |||
| 131 | if (defined $ENV{MUNIN_CACHEFLUSH_RATE}) {
|
||
| 132 | if ($ENV{MUNIN_CACHEFLUSH_RATE} =~ /^[0-9]+$/) {
|
||
| 133 | 191ef79a | Daniel Forsberg | $flush_interval = int($ENV{MUNIN_CACHEFLUSH_RATE});
|
| 134 | cdf6eeb3 | Adrien "ze" Urban | } else {
|
| 135 | print STDERR "Invalid flush rate: $ENV{MUNIN_CACHEFLUSH_RATE}";
|
||
| 136 | } |
||
| 137 | } |
||
| 138 | |||
| 139 | if (defined $ENV{MUNIN_IFCONFIG}) {
|
||
| 140 | if (-f $ENV{MUNIN_IFCONFIG}) {
|
||
| 141 | print STDERR "MUNIN_IFCONFIG: file not found: $ENV{MUNIN_IFCONFIG}";
|
||
| 142 | } else {
|
||
| 143 | $ifconfig = defined $ENV{MUNIN_IFCONFIG};
|
||
| 144 | } |
||
| 145 | } |
||
| 146 | |||
| 147 | my $include_list = undef; |
||
| 148 | if (defined $ENV{MUNIN_IF_INCLUDE}) {
|
||
| 149 | $include_list = [ split(/[[:space:]]+/, $ENV{MUNIN_IF_INCLUDE}) ];
|
||
| 150 | if (0 == scalar (@$include_list)) {
|
||
| 151 | $include_list = undef; |
||
| 152 | } elsif ('' eq $include_list->[0]) {
|
||
| 153 | shift @$include_list; |
||
| 154 | } |
||
| 155 | } |
||
| 156 | my $exclude_list = undef; |
||
| 157 | 191ef79a | Daniel Forsberg | if (defined $ENV{MUNIN_IF_EXCLUDE}) {
|
| 158 | $exclude_list = [ split(/[[:space:]]+/, $ENV{MUNIN_IF_EXCLUDE}) ];
|
||
| 159 | cdf6eeb3 | Adrien "ze" Urban | if (0 == scalar (@$exclude_list)) {
|
| 160 | $exclude_list = undef; |
||
| 161 | } elsif ('' eq $exclude_list->[0]) {
|
||
| 162 | shift @$exclude_list; |
||
| 163 | } |
||
| 164 | } |
||
| 165 | |||
| 166 | sub configbool($) {
|
||
| 167 | my $str = shift; |
||
| 168 | if ($str =~ /^(y(es)?|1|t(rue)?)$/i) {
|
||
| 169 | return 1; |
||
| 170 | } |
||
| 171 | if ($str =~ /^(no?|0|f(alse)?)$/i) {
|
||
| 172 | return 0; |
||
| 173 | } |
||
| 174 | print STDERR "$str: unrecognized bool\n"; |
||
| 175 | return 1; |
||
| 176 | } |
||
| 177 | |||
| 178 | my $should_graph = {
|
||
| 179 | 'bytes' => 1, |
||
| 180 | 'packets' => 1, |
||
| 181 | 'errors' => 1, |
||
| 182 | }; |
||
| 183 | if (defined $ENV{MUNIN_GRAPH_BYTES}) {
|
||
| 184 | $should_graph->{'bytes'} = configbool($ENV{MUNIN_GRAPH_BYTES});
|
||
| 185 | } |
||
| 186 | if (defined $ENV{MUNIN_GRAPH_PACKETS}) {
|
||
| 187 | $should_graph->{'packets'} = configbool($ENV{MUNIN_GRAPH_PACKETS});
|
||
| 188 | } |
||
| 189 | if (defined $ENV{MUNIN_GRAPH_ERRORS}) {
|
||
| 190 | $should_graph->{'errors'} = configbool($ENV{MUNIN_GRAPH_ERRORS});
|
||
| 191 | } |
||
| 192 | unless ($should_graph->{bytes} or $should_graph->{packets}
|
||
| 193 | or $should_graph->{errors}) {
|
||
| 194 | die "Nothing to graph!"; |
||
| 195 | } |
||
| 196 | |||
| 197 | ######################################################################## |
||
| 198 | # Base functions, specific to what we really try to do here. |
||
| 199 | # |
||
| 200 | sub included_interface($) |
||
| 201 | {
|
||
| 202 | my $if = shift; |
||
| 203 | if (defined $exclude_list) {
|
||
| 204 | foreach my $ifl (@$exclude_list) {
|
||
| 205 | return 0 if ($if =~ /^($ifl)$/); |
||
| 206 | } |
||
| 207 | } |
||
| 208 | if (defined $include_list) {
|
||
| 209 | foreach my $ifl (@$include_list) {
|
||
| 210 | return 1 if ($if =~ /^($ifl)$/); |
||
| 211 | } |
||
| 212 | return 0; |
||
| 213 | } |
||
| 214 | return 1; |
||
| 215 | } |
||
| 216 | sub if_to_name($) |
||
| 217 | {
|
||
| 218 | my $if = shift; |
||
| 219 | $if =~ s/[^A-Za-z0-9]/_/g; |
||
| 220 | return $if; |
||
| 221 | } |
||
| 222 | |||
| 223 | sub get_data() |
||
| 224 | {
|
||
| 225 | open IFCONFIG, "-|", $ifconfig or |
||
| 226 | die "open: $ifconfig|: $!\n"; |
||
| 227 | my $data = {};
|
||
| 228 | my $current_if = undef; |
||
| 229 | while (<IFCONFIG>) {
|
||
| 230 | if (/^([^[:space:]]+)/) {
|
||
| 231 | $current_if = $1; |
||
| 232 | if (!included_interface($current_if)) {
|
||
| 233 | $current_if = undef; |
||
| 234 | next |
||
| 235 | } |
||
| 236 | $data->{$current_if} = {};
|
||
| 237 | next; # nothing else on that line |
||
| 238 | } |
||
| 239 | next if (!defined $current_if); |
||
| 240 | if (/RX packets:([0-9]+) errors:([0-9]+) dropped:([0-9]+) overruns:([0-9]+) frame:([0-9]+)/) {
|
||
| 241 | $data->{$current_if}{'rx_pkt'} = $1;
|
||
| 242 | $data->{$current_if}{'rx_err'} = $2;
|
||
| 243 | $data->{$current_if}{'rx_drp'} = $3;
|
||
| 244 | $data->{$current_if}{'rx_ovr'} = $4;
|
||
| 245 | $data->{$current_if}{'rx_frm'} = $5;
|
||
| 246 | next; |
||
| 247 | } |
||
| 248 | if (/TX packets:([0-9]+) errors:([0-9]+) dropped:([0-9]+) overruns:([0-9]+) carrier:([0-9]+)/) {
|
||
| 249 | $data->{$current_if}{'tx_pkt'} = $1;
|
||
| 250 | $data->{$current_if}{'tx_err'} = $2;
|
||
| 251 | $data->{$current_if}{'tx_drp'} = $3;
|
||
| 252 | $data->{$current_if}{'tx_ovr'} = $4;
|
||
| 253 | $data->{$current_if}{'tx_car'} = $5;
|
||
| 254 | next; |
||
| 255 | } |
||
| 256 | if (/RX bytes:([0-9]+) \([^)]*\) TX bytes:([0-9]+) /) {
|
||
| 257 | $data->{$current_if}{'rx_byt'} = $1;
|
||
| 258 | $data->{$current_if}{'tx_byt'} = $2;
|
||
| 259 | } |
||
| 260 | } |
||
| 261 | close IFCONFIG; |
||
| 262 | return $data; |
||
| 263 | } |
||
| 264 | |||
| 265 | # values names, from a data line |
||
| 266 | sub get_data_names($) |
||
| 267 | {
|
||
| 268 | my $line = shift; |
||
| 269 | my $name = $line->[0]; |
||
| 270 | my $count = scalar(@$line) - 2; # 2: name, and timestamp |
||
| 271 | if ($name =~ /\.(bps|pkt)$/ and 2 == $count) {
|
||
| 272 | return [ 'rx', 'tx' ]; |
||
| 273 | } |
||
| 274 | if ($name =~ /\.err$/ and 8 == $count) {
|
||
| 275 | return [ 'rxerr', 'txerr', 'rxdrp', 'txdrp', |
||
| 276 | 'rxovr', 'txovr', 'rxfrm', 'txcar', ]; |
||
| 277 | } |
||
| 278 | # no idea what it is ? corrupted data |
||
| 279 | return undef; |
||
| 280 | } |
||
| 281 | |||
| 282 | sub collect_info_once($$) |
||
| 283 | {
|
||
| 284 | my $fh = shift; |
||
| 285 | my $now = shift; |
||
| 286 | my $data = get_data(); |
||
| 287 | foreach my $if (keys %$data) {
|
||
| 288 | my $name = if_to_name($if); |
||
| 289 | my $d = $data->{$if};
|
||
| 290 | if ($should_graph->{'bytes'}) {
|
||
| 291 | print $fh <<EOF; |
||
| 292 | $name.bps $now $d->{'rx_byt'} $d->{'tx_byt'}
|
||
| 293 | EOF |
||
| 294 | #$name.byt $now rx $d->{'rx_byt'}
|
||
| 295 | #$name.byt $now tx $d->{'tx_byt'}
|
||
| 296 | } |
||
| 297 | if ($should_graph->{'packets'}) {
|
||
| 298 | print $fh <<EOF; |
||
| 299 | $name.pkt $now $d->{'rx_pkt'} $d->{'tx_pkt'}
|
||
| 300 | EOF |
||
| 301 | #$name.pkt $now rx $d->{'rx_pkt'}
|
||
| 302 | #$name.pkt $now tx $d->{'tx_pkt'}
|
||
| 303 | } |
||
| 304 | if ($should_graph->{'errors'}) {
|
||
| 305 | print $fh <<EOF; |
||
| 306 | $name.err $now $d->{'rx_err'} $d->{'tx_err'} $d->{'rx_drp'} $d->{'tx_drp'} $d->{'rx_ovr'} $d->{'tx_ovr'} $d->{'rx_frm'} $d->{'tx_car'}
|
||
| 307 | EOF |
||
| 308 | #$name.err $now rxerr $d->{'rx_err'}
|
||
| 309 | #$name.err $now txerr $d->{'tx_err'}
|
||
| 310 | #$name.err $now rxdrp $d->{'rx_drp'}
|
||
| 311 | #$name.err $now txdrp $d->{'tx_drp'}
|
||
| 312 | #$name.err $now rxovr $d->{'rx_ovr'}
|
||
| 313 | #$name.err $now txovr $d->{'tx_ovr'}
|
||
| 314 | #$name.err $now rxfrm $d->{'rx_frm'}
|
||
| 315 | #$name.err $now txcar $d->{'tx_car'}
|
||
| 316 | } |
||
| 317 | } |
||
| 318 | } |
||
| 319 | sub show_config() |
||
| 320 | {
|
||
| 321 | my $data = get_data(); |
||
| 322 | my $graph_order = "graph_order"; |
||
| 323 | foreach my $if (sort keys %$data) {
|
||
| 324 | my $name = if_to_name($if); |
||
| 325 | $graph_order .= " ${name}_bps=${name}.bps.tx";
|
||
| 326 | } |
||
| 327 | print <<EOF; |
||
| 328 | multigraph @{[ graph_name() ]}
|
||
| 329 | 34eeebbe | Lars Kruse | graph_category network |
| 330 | cdf6eeb3 | Adrien "ze" Urban | graph_title overall bits per seconds |
| 331 | graph_vlabel bits per seconds |
||
| 332 | update_rate 1 |
||
| 333 | graph_data_size custom 1d, 10s for 1w, 1m for 1t, 5m for 1y |
||
| 334 | graph_args --base 1000 |
||
| 335 | $graph_order |
||
| 336 | EOF |
||
| 337 | my $style = 'AREA'; |
||
| 338 | foreach my $if (keys %$data) {
|
||
| 339 | my $name = if_to_name($if); |
||
| 340 | print <<EOF; |
||
| 341 | ${name}_bps.label $if bps out
|
||
| 342 | ${name}_bps.draw $style
|
||
| 343 | ${name}_bps.cdef ${name}_bps,8,*
|
||
| 344 | EOF |
||
| 345 | $style = 'STACK'; |
||
| 346 | } |
||
| 347 | foreach my $if (keys %$data) {
|
||
| 348 | my $name = if_to_name($if); |
||
| 349 | print <<EOF; |
||
| 350 | multigraph @{[ graph_name() ]}.@{[ if_to_name($if) ]}
|
||
| 351 | graph_title $if traffic |
||
| 352 | graph_vlabel kbits/s and pkt/s |
||
| 353 | graph_order bpsrx=bps.rx bpstx=bps.tx pktrx=pkt.rx pkttx=pkt.tx |
||
| 354 | bpsrx.label $if kbps in |
||
| 355 | bpsrx.draw AREA |
||
| 356 | bpsrx.cdef bpsrx,-125,/ |
||
| 357 | bpstx.label $if kbps out |
||
| 358 | bpstx.draw AREA |
||
| 359 | bpstx.cdef bpstx,125,* |
||
| 360 | pktrx.label $if pkt/s in |
||
| 361 | pktrx.draw LINE1 |
||
| 362 | pktrx.cdef pktrx,-1,* |
||
| 363 | pkttx.label $if pkt/s out |
||
| 364 | pkttx.draw LINE1 |
||
| 365 | EOF |
||
| 366 | #foo.negative bar |
||
| 367 | if ($should_graph->{'bytes'}) {
|
||
| 368 | print <<EOF; |
||
| 369 | multigraph @{[ graph_name() ]}.@{[ if_to_name($if) ]}.bps
|
||
| 370 | graph_title $if - bits per seconds |
||
| 371 | graph_vlabel bits per seconds |
||
| 372 | graph_args --base 1000 |
||
| 373 | graph_scale no |
||
| 374 | update_rate 1 |
||
| 375 | graph_data_size custom 1d, 10s for 1w, 1m for 1t, 5m for 1y |
||
| 376 | rx.label bps received |
||
| 377 | rx.type DERIVE |
||
| 378 | rx.min 0 |
||
| 379 | rx.cdef rx,8,* |
||
| 380 | tx.label bps sent |
||
| 381 | tx.type DERIVE |
||
| 382 | tx.min 0 |
||
| 383 | tx.cdef tx,8,* |
||
| 384 | EOF |
||
| 385 | } |
||
| 386 | if ($should_graph->{'packets'}) {
|
||
| 387 | print <<EOF; |
||
| 388 | multigraph @{[ graph_name() ]}.@{[ if_to_name($if) ]}.pkt
|
||
| 389 | graph_title $if - packets per seconds |
||
| 390 | graph_vlabel packets per seconds |
||
| 391 | graph_args --base 1000 |
||
| 392 | graph_scale no |
||
| 393 | update_rate 1 |
||
| 394 | graph_data_size custom 1d, 10s for 1w, 1m for 1t, 5m for 1y |
||
| 395 | rx.label packets per second received |
||
| 396 | rx.type DERIVE |
||
| 397 | rx.min 0 |
||
| 398 | tx.label packets per second sent |
||
| 399 | tx.type DERIVE |
||
| 400 | tx.min 0 |
||
| 401 | EOF |
||
| 402 | } |
||
| 403 | if ($should_graph->{'errors'}) {
|
||
| 404 | print <<EOF; |
||
| 405 | multigraph @{[ graph_name() ]}.@{[ if_to_name($if) ]}.err
|
||
| 406 | graph_title $if - errors |
||
| 407 | graph_vlabel errors |
||
| 408 | graph_scale no |
||
| 409 | update_rate 1 |
||
| 410 | graph_data_size custom 1d, 10s for 1w, 1m for 1t, 5m for 1y |
||
| 411 | graph_order rxerr txerr rxdrp txdrp rxovr txovr rxfrm txcar |
||
| 412 | rxerr.label errors per second (in) |
||
| 413 | rxerr.type DERIVE |
||
| 414 | rxerr.min 0 |
||
| 415 | txerr.label errors per second (out) |
||
| 416 | txerr.type DERIVE |
||
| 417 | txerr.min 0 |
||
| 418 | rxdrp.label drop per second (in) |
||
| 419 | rxdrp.type DERIVE |
||
| 420 | rxdrp.min 0 |
||
| 421 | txdrp.label drop per second (out) |
||
| 422 | txdrp.type DERIVE |
||
| 423 | txdrp.min 0 |
||
| 424 | rxovr.label overruns per second (in) |
||
| 425 | rxovr.type DERIVE |
||
| 426 | rxovr.min 0 |
||
| 427 | txovr.label overruns per second (out) |
||
| 428 | txovr.type DERIVE |
||
| 429 | txovr.min 0 |
||
| 430 | rxfrm.label frame per second (in) |
||
| 431 | rxfrm.type DERIVE |
||
| 432 | rxfrm.min 0 |
||
| 433 | txcar.label carrier per second (out) |
||
| 434 | txcar.type DERIVE |
||
| 435 | txcar.min 0 |
||
| 436 | EOF |
||
| 437 | } |
||
| 438 | } |
||
| 439 | } |
||
| 440 | sub check_req() |
||
| 441 | {
|
||
| 442 | 17f78427 | Lars Kruse | my $data = get_data(); |
| 443 | cdf6eeb3 | Adrien "ze" Urban | if (0 != scalar(keys %$data)) {
|
| 444 | return 1; |
||
| 445 | } |
||
| 446 | return 0; |
||
| 447 | } |
||
| 448 | |||
| 449 | |||
| 450 | ######################################################################## |
||
| 451 | fba800ae | Veres Lajos | # beyond that line, it should be generic stuffs, not dependent on what |
| 452 | cdf6eeb3 | Adrien "ze" Urban | # you are trying to graph |
| 453 | # |
||
| 454 | |||
| 455 | sub check_running() {
|
||
| 456 | if (-f pidfile()) {
|
||
| 457 | my $pid = undef; |
||
| 458 | if (open FILE, "<", pidfile()) {
|
||
| 459 | $pid = <FILE>; |
||
| 460 | close FILE; |
||
| 461 | chomp $pid; |
||
| 462 | } |
||
| 463 | if ($pid) {
|
||
| 464 | # does not exist ? kill it |
||
| 465 | if (kill 0, $pid) {
|
||
| 466 | return 1; |
||
| 467 | } |
||
| 468 | } |
||
| 469 | unlink(pidfile()); |
||
| 470 | } |
||
| 471 | return 0; |
||
| 472 | } |
||
| 473 | |||
| 474 | |||
| 475 | # FIXME: should also trap kill sigint and sigterm |
||
| 476 | # FIXME: check pidfile got touched recently |
||
| 477 | sub collect_loop() {
|
||
| 478 | $0 = acquire_name(); |
||
| 479 | $0 = "<$plugin> collecting information"; |
||
| 480 | # write our pid |
||
| 481 | open PIDFILE, '>', pidfile() or die "open: @{[ pidfile() ]}: $!\n";
|
||
| 482 | print PIDFILE $$, "\n"; |
||
| 483 | close PIDFILE; |
||
| 484 | # open cache |
||
| 485 | my $fh_cache; |
||
| 486 | open $fh_cache, ">>", cachefile() or |
||
| 487 | die "open: @{[ cachefile() ]}: $!\n";
|
||
| 488 | my @tick = Time::HiRes::gettimeofday(); |
||
| 489 | my $flush_count = 0; |
||
| 490 | while (1) {
|
||
| 491 | collect_info_once($fh_cache, $tick[0]); |
||
| 492 | if ($flush_interval) {
|
||
| 493 | if ($flush_interval == ++$flush_count) {
|
||
| 494 | $fh_cache->flush(); |
||
| 495 | $flush_count = 0; |
||
| 496 | } |
||
| 497 | } |
||
| 498 | my @now = Time::HiRes::gettimeofday(); |
||
| 499 | # when should the next tick be ? |
||
| 500 | $tick[0] += $update_rate; |
||
| 501 | # how long until next tick ? |
||
| 502 | my $diff = ($tick[0] - $now[0]) * 1000000 |
||
| 503 | + $tick[1] - $now[1]; |
||
| 504 | if ($diff <= 0) {
|
||
| 505 | # next tick already passed ? damn! |
||
| 506 | @tick = @now; |
||
| 507 | } else {
|
||
| 508 | # sleep what remains |
||
| 509 | Time::HiRes::usleep($diff); |
||
| 510 | } |
||
| 511 | } |
||
| 512 | unlink(pidfile()); |
||
| 513 | unlink(cachefile()); |
||
| 514 | } |
||
| 515 | |||
| 516 | # launch daemon if not running |
||
| 517 | # notify the daemon we still need it (touch its pid) |
||
| 518 | sub daemon_alive() {
|
||
| 519 | if (check_running()) {
|
||
| 520 | my $atime; |
||
| 521 | my $mtime; |
||
| 522 | $atime = $mtime = time; |
||
| 523 | utime $atime, $mtime, pidfile(); |
||
| 524 | } else {
|
||
| 525 | if (0 == fork()) {
|
||
| 526 | close(STDIN); |
||
| 527 | close(STDOUT); |
||
| 528 | close(STDERR); |
||
| 529 | open STDIN, "<", "/dev/null"; |
||
| 530 | open STDOUT, ">", "/dev/null"; |
||
| 531 | open STDERR, ">", "/dev/null"; |
||
| 532 | collect_loop(); |
||
| 533 | exit(0); |
||
| 534 | } |
||
| 535 | } |
||
| 536 | } |
||
| 537 | |||
| 538 | |||
| 539 | sub run_autoconf() {
|
||
| 540 | if (check_req()) {
|
||
| 541 | print "yes\n"; |
||
| 542 | } else {
|
||
| 543 | print "no\n"; |
||
| 544 | } |
||
| 545 | } |
||
| 546 | |||
| 547 | sub run_config() {
|
||
| 548 | daemon_alive(); |
||
| 549 | show_config(); |
||
| 550 | } |
||
| 551 | |||
| 552 | sub fetch_showline($) {
|
||
| 553 | my $line = shift; |
||
| 554 | my $names = get_data_names($line); |
||
| 555 | # don't display anything if we don't like what it is |
||
| 556 | return unless (defined $names); |
||
| 557 | my $graph = shift @$line; |
||
| 558 | my $time = shift @$line; |
||
| 559 | foreach my $value (@$line) {
|
||
| 560 | my $name = shift @$names; |
||
| 561 | print <<EOF; |
||
| 562 | $name.value $time:$value |
||
| 563 | EOF |
||
| 564 | } |
||
| 565 | } |
||
| 566 | sub run_fetch() {
|
||
| 567 | daemon_alive(); |
||
| 568 | if (open CACHE, "+<", cachefile()) {
|
||
| 569 | my $data = {};
|
||
| 570 | while (<CACHE>) {
|
||
| 571 | chomp; |
||
| 572 | my $field = []; |
||
| 573 | @$field = split(/ /); |
||
| 574 | if (not defined $data->{$field->[0]}) {
|
||
| 575 | $data->{$field->[0]} = [];
|
||
| 576 | } |
||
| 577 | push @{$data->{$field->[0]}}, $field;
|
||
| 578 | } |
||
| 579 | fba800ae | Veres Lajos | # finished reading ? truncate it right away |
| 580 | cdf6eeb3 | Adrien "ze" Urban | truncate CACHE, 0; |
| 581 | close CACHE; |
||
| 582 | foreach my $graph (keys %$data) {
|
||
| 583 | print <<EOF; |
||
| 584 | multigraph @{[ graph_name() ]}.$graph
|
||
| 585 | EOF |
||
| 586 | foreach my $line (@{$data->{$graph}}) {
|
||
| 587 | fetch_showline($line); |
||
| 588 | } |
||
| 589 | } |
||
| 590 | } |
||
| 591 | } |
||
| 592 | |||
| 593 | my $cmd = 'fetch'; |
||
| 594 | if (defined $ARGV[0]) {
|
||
| 595 | $cmd = $ARGV[0]; |
||
| 596 | } |
||
| 597 | if ('fetch' eq $cmd) {
|
||
| 598 | run_fetch(); |
||
| 599 | } elsif ('config' eq $cmd) {
|
||
| 600 | run_config(); |
||
| 601 | } elsif ('autoconf' eq $cmd) {
|
||
| 602 | run_autoconf(); |
||
| 603 | } elsif ('daemon' eq $cmd) {
|
||
| 604 | run_daemon(); |
||
| 605 | } else {
|
||
| 606 | print STDERR <<EOF; |
||
| 607 | $0: unrecognized command |
||
| 608 | |||
| 609 | Usage: |
||
| 610 | $0 autoconf - check if we have everything we need |
||
| 611 | $0 config - show plugin configuration |
||
| 612 | $0 fetch - fetch latest data |
||
| 613 | $0 daemon - launch daemon |
||
| 614 | EOF |
||
| 615 | exit(1); |
||
| 616 | } |
||
| 617 | exit(0); |
