mirror of https://github.com/mikaku/Monitorix.git
7007 lines
186 KiB
Perl
Executable File
7007 lines
186 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
#
|
|
# Monitorix - A lightweight system monitoring tool.
|
|
#
|
|
# Copyright (C) 2005-2012 by Jordi Sanfeliu <jordi@fibranet.cat>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
|
|
require 5.006;
|
|
|
|
no strict "vars";
|
|
no warnings "once";
|
|
#use warnings;
|
|
use RRDs;
|
|
use POSIX;
|
|
use File::Basename;
|
|
use LWP::UserAgent;
|
|
use XML::Simple;
|
|
use Socket;
|
|
use DBI;
|
|
use Getopt::Std;
|
|
use Cwd 'abs_path';
|
|
use locale;
|
|
|
|
# Force a standard locale
|
|
$ENV{LANG} = "";
|
|
setlocale(LC_TIME, "C");
|
|
|
|
# Signals to Trap and Handle
|
|
$SIG{'INT' } = 'INT_handler';
|
|
$SIG{'ABRT'} = 'INT_handler';
|
|
$SIG{'QUIT'} = 'INT_handler';
|
|
$SIG{'TRAP'} = 'INT_handler';
|
|
$SIG{'STOP'} = 'INT_handler';
|
|
$SIG{'TERM'} = 'INT_handler';
|
|
$SIG{'CHLD'} = 'CHLD_handler';
|
|
$SIG{'HUP' } = 'HUP_handler';
|
|
$SIG{'ALRM'} = 'ALRM_handler';
|
|
|
|
use constant VERSION => "2.6.0";
|
|
use constant RELDATE => "19-Sep-2012";
|
|
|
|
my @suppsys = ("Linux", "FreeBSD", "OpenBSD", "NetBSD");
|
|
my @graphs;
|
|
my @graphs_debug;
|
|
my $os;
|
|
my $kernel_branch;
|
|
|
|
sub INT_handler {
|
|
my ($signal) = @_;
|
|
|
|
logger("SIG$signal caught.");
|
|
flush_accounting_rules();
|
|
logger("Exiting.");
|
|
exit(0);
|
|
}
|
|
|
|
sub CHLD_handler {
|
|
my $pid = waitpid(-1, WNOHANG);
|
|
}
|
|
|
|
sub HUP_handler {
|
|
my ($signal) = @_;
|
|
my $myself = (caller(0))[3];
|
|
|
|
logger("SIG$signal caught.");
|
|
close(STDOUT);
|
|
close(STDERR);
|
|
unless(open(STDOUT, ">> $LOG_FILE")) {
|
|
logger("Can't write to LOG: $!");
|
|
}
|
|
unless(open(STDERR, ">> $LOG_FILE")) { # >>&STDOUT XXX
|
|
logger("Can't write to LOG: $!");
|
|
}
|
|
logger("$myself: reopening log file.");
|
|
}
|
|
|
|
sub ALRM_handler {
|
|
my $myself = (caller(0))[3];
|
|
my ($sec, $min, $hour, $mday) = localtime(time);
|
|
|
|
if($sec == 0) {
|
|
foreach my $g (@graphs) {
|
|
my ($t) = split('_', $g);
|
|
logger("$myself: calling $g()") unless !$opt_d;
|
|
if(!grep {$_ eq $t} (@graphs_debug)) {
|
|
undef($t);
|
|
}
|
|
eval {&$g($t);};
|
|
if($@) {
|
|
logger("$g(): $@");
|
|
}
|
|
}
|
|
if($PC_LAN eq "Y" && $PC_ENABLE_MONTHLY_REPORTS eq "Y") {
|
|
if($min == 0 && $hour == 0) {
|
|
get_counters();
|
|
if($mday == 1) {
|
|
send_reports();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
alarm(1);
|
|
}
|
|
|
|
sub logger {
|
|
my ($msg) = @_;
|
|
|
|
$msg = localtime() . " - " . $msg;
|
|
print("$msg\n");
|
|
}
|
|
|
|
sub daemonize {
|
|
if(fork) {
|
|
exit(0); # parent exits
|
|
}
|
|
|
|
setsid();
|
|
foreach(0 .. (sysconf(&POSIX::_SC_OPEN_MAX) || 1024)) {
|
|
close($_);
|
|
}
|
|
unless(chdir("/")) {
|
|
die("Can't chdir to /: $!");
|
|
}
|
|
unless(umask(022)) {
|
|
die("Unable to umask 022: $!");
|
|
}
|
|
# unless(open(STDIN, "< /dev/null")) {
|
|
# die("Can't read /dev/null: $!");
|
|
# }
|
|
unless(open(STDOUT, ">> $LOG_FILE")) {
|
|
die("Can't write to LOG: $!");
|
|
}
|
|
unless(open(STDERR, ">> $LOG_FILE")) { # >>&STDOUT XXX
|
|
die("Can't write to LOG: $!");
|
|
}
|
|
}
|
|
|
|
sub usage {
|
|
print(STDERR << "EOF");
|
|
Usage: monitorix -c configfile [-p pidfile] [-d none | graph[,graph] | all ] [-v]
|
|
|
|
EOF
|
|
exit(1);
|
|
}
|
|
|
|
sub create_index {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $n;
|
|
my $gname;
|
|
my %rgraphs = reverse %GRAPHS;
|
|
|
|
if($THEME_COLOR eq "black") {
|
|
$bgcolor = $BLACK{main_bg};
|
|
$table_back_color = $BLACK{graph_bg};
|
|
$title_back_color = $BLACK{title_bg};
|
|
$title_fore_color = $BLACK{title_fg};
|
|
} elsif(!$THEME_COLOR || $THEME_COLOR eq "white") {
|
|
$bgcolor = "#ffffff";
|
|
$table_back_color = "#CCCCCC";
|
|
$title_back_color = "#777777";
|
|
$title_fore_color = "#CCCC00";
|
|
} else {
|
|
logger("$myself: ERROR: invalid value in \$THEME_COLOR") unless !$opt_d;
|
|
}
|
|
|
|
if(!open(OUT, "> $BASE_DIR/index.html")) {
|
|
die "unable to create ${BASE_DIR}index.html. $!";
|
|
}
|
|
print(OUT <<EOF);
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
|
<html>
|
|
<head>
|
|
<title>$TITLE</title>
|
|
<link rel="shortcut icon" href="$FAVICON">
|
|
</head>
|
|
<body bgcolor="$bgcolor" text="#888888" vlink="#888888" link="#888888">
|
|
<center>
|
|
<p>
|
|
<br>
|
|
<font face="Verdana, sans-serif">
|
|
<table>
|
|
<tr>
|
|
<td>
|
|
<a href="http://www.monitorix.org/"><img src="logo_top.png" border="0"></a>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<h2 align="right">v@{[VERSION]}</h2>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<p>
|
|
<form action="$BASE_CGI/monitorix.cgi" method="get">
|
|
<table cellspacing="5" cellpadding="0" bgcolor="$table_back_color" border="1">
|
|
<tr>
|
|
<td bgcolor="$title_back_color">
|
|
<font color="$title_fore_color">
|
|
<b> Hostname </b>
|
|
</font>
|
|
</td>
|
|
<td bgcolor="$title_back_color">
|
|
<font color="$title_fore_color">
|
|
<b> Graph </b>
|
|
</font>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
EOF
|
|
|
|
if(!$FAVICON) {
|
|
logger("WARNING: the option \$FAVICON is missing in your configuration file. Do you really have the latest version?");
|
|
}
|
|
print(OUT " <td bgcolor='$bgcolor'>\n");
|
|
print(OUT " <select name='mode' size='1'>\n");
|
|
print(OUT " <option value='localhost'>Local Host</option>\n");
|
|
if(scalar(@REMOTEHOST_LIST) && $MULTIHOST eq "Y") {
|
|
print(OUT " <optgroup label='Multihost'>\n");
|
|
print(OUT " <option value='multihost.all'>All Hosts</option>\n");
|
|
for($n = 0; $n < scalar(@REMOTEHOST_LIST); $n += 2) {
|
|
print(OUT " <option value='multihost." . ($n / 2). "'>" . $REMOTEHOST_LIST[$n] . "</option>\n");
|
|
}
|
|
print(OUT " </optgroup>\n");
|
|
}
|
|
|
|
|
|
if(scalar(@REMOTEGROUP_LIST) && $MULTIHOST eq "Y" && $GROUPS eq "Y" ) {
|
|
print(OUT " <optgroup label='Multihost-Groups'>\n");
|
|
print(OUT " <option value='multihost.group'>All Groups</option>\n");
|
|
for($n = 0; $n < scalar(@REMOTEGROUP_LIST); $n += 2) {
|
|
print(OUT " <option value='multihost.group" . ($n / 2). "'>" . $REMOTEGROUP_LIST[$n] . "</option>\n");
|
|
}
|
|
print(OUT " </optgroup>\n");
|
|
}
|
|
|
|
if(scalar(@PC_LIST) && $PC_LAN eq "Y") {
|
|
print(OUT " <optgroup label='LAN PCs'>\n");
|
|
print(OUT " <option value='pc.all'>All LAN PCs</option>\n");
|
|
for($n = 0; $n < scalar(@PC_LIST); $n++) {
|
|
print(OUT " <option value='pc." . $n . "'>" . $PC_LIST[$n] . "</option>\n");
|
|
}
|
|
print(OUT " </optgroup>\n");
|
|
}
|
|
print(OUT " </select>\n");
|
|
print(OUT " </td>\n");
|
|
|
|
|
|
|
|
print(OUT " <td bgcolor='$bgcolor'>\n");
|
|
print(OUT " <select name='graph' size='1'>\n");
|
|
print(OUT " <option value='all'>All graphs</option>\n");
|
|
foreach my $g (@GRAPH_NAME) {
|
|
if($GRAPH_ENABLE{$g} eq "Y") {
|
|
print(OUT " <optgroup label='" . $GRAPH_TITLE{$g} . "'>\n");
|
|
if($g eq "proc") {
|
|
for($n = 0; $n < $PROC_MAX; $n++) {
|
|
$gname = "_" . $g;
|
|
print(OUT " <option value='" . $gname . $n . "'>" . $rgraphs{$gname} . " " . $n . "</option>\n");
|
|
}
|
|
next;
|
|
}
|
|
if($g eq "net") {
|
|
my $n2;
|
|
for($n = 0; $n < scalar(@NET_LIST); $n++) {
|
|
$gname = "_" . $g;
|
|
for($n2 = 1; $n2 <= 3; $n2++) {
|
|
$str = $rgraphs{$gname . $n2};
|
|
$str =~ s/^/$NET_LIST[$n] /;
|
|
print(OUT " <option value='" . $gname . $n . $n2 . "'>" . $str . "</option>\n");
|
|
}
|
|
}
|
|
next;
|
|
}
|
|
if($g eq "port") {
|
|
for($n = 0; $n < $PORT_MAX && $n < scalar(@PORT_LIST); $n++) {
|
|
$gname = "_" . $g;
|
|
print(OUT " <option value='" . $gname . $n . "'>" . $rgraphs{$gname} . " " . $PORT_LIST[$n] . " (" . $PORT_NAME[$n] . ")" . "</option>\n");
|
|
}
|
|
next;
|
|
}
|
|
if($g eq "fail2ban") {
|
|
for($n = 0; $n < scalar(@FAIL2BAN_LIST); $n++) {
|
|
$gname = "_" . $g;
|
|
print(OUT " <option value='" . $gname . $n . "'>" . ($FAIL2BAN_DESC[$n] ? $FAIL2BAN_DESC[$n] : $rgraphs{$gname}) . "</option>\n");
|
|
}
|
|
next;
|
|
}
|
|
$n = 0;
|
|
foreach my $k (sort keys %rgraphs) {
|
|
if($k =~ m/$g/) {
|
|
$gname = "_" . $g . ++$n;
|
|
if($rgraphs{$gname}) {
|
|
print(OUT " <option value='" . $gname ."'>" . $rgraphs{$gname} . "</option>\n");
|
|
}
|
|
}
|
|
}
|
|
print(OUT " </optgroup>\n");
|
|
}
|
|
}
|
|
print(OUT " </select>\n");
|
|
print(OUT " </td>\n");
|
|
|
|
|
|
print(OUT <<EOF);
|
|
</tr>
|
|
</table>
|
|
<p>
|
|
<table cellspacing="5" cellpadding="0" bgcolor="$table_back_color" border="1">
|
|
<tr>
|
|
<td bgcolor="$title_back_color">
|
|
<input type="radio" checked name="when" value="1day">
|
|
<font color="$title_fore_color"><b>Daily </b></font>
|
|
</td>
|
|
<td bgcolor="$title_back_color">
|
|
<input type="radio" name="when" value="1week">
|
|
<font color="$title_fore_color"><b>Weekly </b></font>
|
|
</td>
|
|
<td bgcolor="$title_back_color">
|
|
<input type="radio" name="when" value="1month">
|
|
<font color="$title_fore_color"><b>Monthly </b></font>
|
|
</td>
|
|
<td bgcolor="$title_back_color">
|
|
<input type="radio" name="when" value="1year">
|
|
<font color="$title_fore_color"><b>Yearly </b></font>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<p>
|
|
<input type="hidden" name="color" value="$THEME_COLOR">
|
|
<input type="submit" value=" Ok ">
|
|
</form>
|
|
</font>
|
|
</center>
|
|
</body>
|
|
</html>
|
|
EOF
|
|
close(OUT);
|
|
}
|
|
|
|
sub flush_accounting_rules {
|
|
my $num = 0;
|
|
|
|
# flushes out any Monitorix iptables/ipfw rules
|
|
if($os eq "Linux") {
|
|
logger("Flushing out iptables rules.") unless !$opt_d;
|
|
if(open(IN, "iptables -nxvL INPUT --line-numbers |")) {
|
|
my @rules;
|
|
my @names;
|
|
while(<IN>) {
|
|
my ($rule, undef, undef, $name) = split(' ', $_);
|
|
if($name =~ /MONITORIX_IN/ || /NGINX_IN/) {
|
|
push(@rules, $rule);
|
|
push(@names, $name);
|
|
}
|
|
}
|
|
close(IN);
|
|
@rules = reverse(@rules);
|
|
foreach(@rules) {
|
|
system("iptables -D INPUT $_");
|
|
$num++;
|
|
}
|
|
foreach(@names) {
|
|
system("iptables -X $_");
|
|
}
|
|
}
|
|
if(open(IN, "iptables -nxvL OUTPUT --line-numbers |")) {
|
|
my @rules;
|
|
my @names;
|
|
while(<IN>) {
|
|
my ($rule, undef, undef, $name) = split(' ', $_);
|
|
if($name =~ /MONITORIX_OUT/ || /NGINX_OUT/) {
|
|
push(@rules, $rule);
|
|
push(@names, $name);
|
|
}
|
|
}
|
|
close(IN);
|
|
@rules = reverse(@rules);
|
|
foreach(@rules) {
|
|
system("iptables -D OUTPUT $_");
|
|
$num++;
|
|
}
|
|
foreach(@names) {
|
|
system("iptables -X $_");
|
|
}
|
|
}
|
|
logger("$num iptables rules have been flushed.") unless !$opt_d;
|
|
}
|
|
if($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
logger("Flushing out ipfw rules.") unless !$opt_d;
|
|
system("ipfw delete $PORT_RULE 2>/dev/null");
|
|
system("ipfw delete $NGINX_RULE 2>/dev/null");
|
|
}
|
|
}
|
|
|
|
# SYSTEM graph
|
|
# ----------------------------------------------------------------------------
|
|
sub system_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $SYSTEM_RRD)) {
|
|
logger("Creating '$SYSTEM_RRD' file.");
|
|
eval {
|
|
RRDs::create($SYSTEM_RRD,
|
|
"--step=60",
|
|
"DS:system_load1:GAUGE:120:0:U",
|
|
"DS:system_load5:GAUGE:120:0:U",
|
|
"DS:system_load15:GAUGE:120:0:U",
|
|
"DS:system_nproc:GAUGE:120:0:U",
|
|
"DS:system_npslp:GAUGE:120:0:U",
|
|
"DS:system_nprun:GAUGE:120:0:U",
|
|
"DS:system_npwio:GAUGE:120:0:U",
|
|
"DS:system_npzom:GAUGE:120:0:U",
|
|
"DS:system_npstp:GAUGE:120:0:U",
|
|
"DS:system_npswp:GAUGE:120:0:U",
|
|
"DS:system_mtotl:GAUGE:120:0:U",
|
|
"DS:system_mbuff:GAUGE:120:0:U",
|
|
"DS:system_mcach:GAUGE:120:0:U",
|
|
"DS:system_mfree:GAUGE:120:0:U",
|
|
"DS:system_macti:GAUGE:120:0:U",
|
|
"DS:system_minac:GAUGE:120:0:U",
|
|
"DS:system_val01:GAUGE:120:0:U",
|
|
"DS:system_val02:GAUGE:120:0:U",
|
|
"DS:system_val03:GAUGE:120:0:U",
|
|
"DS:system_val04:GAUGE:120:0:U",
|
|
"DS:system_val05:GAUGE:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $SYSTEM_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if($ENABLE_ALERTS eq "Y") {
|
|
if(! -x $ALERT_LOADAVG_SCRIPT) {
|
|
logger("$myself: ERROR: script '$ALERT_LOADAVG_SCRIPT' doesn't exist or don't has execute permissions.");
|
|
}
|
|
}
|
|
|
|
our $system_hist = 0;
|
|
push(@graphs, "system_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub system_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $load1;
|
|
my $load5;
|
|
my $load15;
|
|
my $nproc;
|
|
my $npslp;
|
|
my $nprun;
|
|
my $npwio;
|
|
my $npzom;
|
|
my $npstp;
|
|
my $npswp;
|
|
my $mtotl;
|
|
my $mbuff;
|
|
my $mcach;
|
|
my $mfree;
|
|
my $macti;
|
|
my $minac;
|
|
my $val01 = 0;
|
|
my $val02 = 0;
|
|
my $val03 = 0;
|
|
my $val04 = 0;
|
|
my $val05 = 0;
|
|
|
|
my $rrdata = "N";
|
|
|
|
$npwio = $npzom = $npstp = $npswp = 0;
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "/proc/loadavg");
|
|
while(<IN>) {
|
|
if(/^(\d+\.\d+) (\d+\.\d+) (\d+\.\d+) (\d+)\/(\d+)/) {
|
|
$load1 = $1;
|
|
$load5 = $2;
|
|
$load15 = $3;
|
|
$nprun = $4;
|
|
$npslp = $5;
|
|
}
|
|
}
|
|
close(IN);
|
|
$nproc = $npslp + $nprun;
|
|
|
|
open(IN, "/proc/meminfo");
|
|
while(<IN>) {
|
|
if(/^MemTotal:\s+(\d+) kB$/) {
|
|
$mtotl = $1;
|
|
next;
|
|
}
|
|
if(/^MemFree:\s+(\d+) kB$/) {
|
|
$mfree = $1;
|
|
next;
|
|
}
|
|
if(/^Buffers:\s+(\d+) kB$/) {
|
|
$mbuff = $1;
|
|
next;
|
|
}
|
|
if(/^Cached:\s+(\d+) kB$/) {
|
|
$mcach = $1;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
$macti = $minac = "";
|
|
} elsif($os eq "FreeBSD") {
|
|
my $page_size;
|
|
open(IN, "sysctl -n vm.loadavg |");
|
|
while(<IN>) {
|
|
if(/^\{ (\d+\.\d+) (\d+\.\d+) (\d+\.\d+) \}$/) {
|
|
$load1 = $1;
|
|
$load5 = $2;
|
|
$load15 = $3;
|
|
}
|
|
}
|
|
close(IN);
|
|
open(IN, "sysctl vm.vmtotal |");
|
|
while(<IN>) {
|
|
if(/^Processes:\s+\(RUNQ:\s+(\d+) Disk.*? Sleep:\s+(\d+)\)$/) {
|
|
$nprun = $1;
|
|
$npslp = $2;
|
|
}
|
|
if(/^Free Memory Pages:\s+(\d+)K$/) {
|
|
$mfree = $1;
|
|
}
|
|
}
|
|
close(IN);
|
|
$nproc = $npslp + $nprun;
|
|
$mtotl = `sysctl -n hw.realmem`;
|
|
$mbuff = `sysctl -n vfs.bufspace`;
|
|
$mcach = `sysctl -n vm.stats.vm.v_cache_count`;
|
|
|
|
chomp($mbuff);
|
|
$mbuff = $mbuff / 1024;
|
|
chomp($mtotl);
|
|
$mtotl = $mtotl / 1024;
|
|
$page_size = `sysctl -n vm.stats.vm.v_page_size`;
|
|
$macti = `sysctl -n vm.stats.vm.v_active_count`;
|
|
$minac = `sysctl -n vm.stats.vm.v_inactive_count`;
|
|
chomp($page_size, $mcach, $macti, $minac);
|
|
$mcach = ($page_size * $mcach) / 1024;
|
|
$macti = ($page_size * $macti) / 1024;
|
|
$minac = ($page_size * $minac) / 1024;
|
|
} elsif($os eq "OpenBSD" || $os eq "NetBSD") {
|
|
open(IN, "sysctl -n vm.loadavg |");
|
|
while(<IN>) {
|
|
if(/^(\d+\.\d+) (\d+\.\d+) (\d+\.\d+)$/) {
|
|
$load1 = $1;
|
|
$load5 = $2;
|
|
$load15 = $3;
|
|
}
|
|
}
|
|
close(IN);
|
|
open(IN, "top -b |");
|
|
while(<IN>) {
|
|
if(/ processes:/) {
|
|
$_ =~ s/:/,/;
|
|
my (@tmp) = split(',', $_);
|
|
foreach(@tmp) {
|
|
my ($num, $desc) = split(' ', $_);
|
|
$nproc = $num unless $desc ne "processes";
|
|
if(grep {$_ eq $desc} ("idle", "sleeping", "stopped", "zombie")) {
|
|
$npslp += $num;
|
|
}
|
|
if($desc eq "running" || $desc eq "on") {
|
|
$nprun += $num;
|
|
}
|
|
}
|
|
}
|
|
if($os eq "OpenBSD") {
|
|
if(/^Memory: Real: (\d+)\w\/\d+\w act\/tot Free: (\d+)\w /) {
|
|
$macti = $1;
|
|
$mfree = $2;
|
|
$macti = int($macti) * 1024;
|
|
$mfree = int($mfree) * 1024;
|
|
last;
|
|
}
|
|
}
|
|
if($os eq "NetBSD") {
|
|
if(/^Memory: (\d+)\w Act, .*, (\d+)\w Free/) {
|
|
$macti = $1;
|
|
$mfree = $2;
|
|
$macti = int($macti) * 1024;
|
|
$mfree = int($mfree) * 1024;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
$mtotl = `sysctl -n hw.physmem`;
|
|
chomp($mtotl);
|
|
$mtotl = $mtotl / 1024;
|
|
}
|
|
|
|
chomp(
|
|
$load1,
|
|
$load5,
|
|
$load15,
|
|
$nproc,
|
|
$npslp,
|
|
$nprun,
|
|
$npwio,
|
|
$npzom,
|
|
$npstp,
|
|
$npswp,
|
|
$mtotl,
|
|
$mbuff,
|
|
$mcach,
|
|
$mfree,
|
|
$macti,
|
|
$minac,
|
|
);
|
|
|
|
# SYSTEM alert
|
|
if($ENABLE_ALERTS eq "Y") {
|
|
if(!$ALERT_LOADAVG_THRESHOLD || $load15 < $ALERT_LOADAVG_THRESHOLD) {
|
|
$system_hist = 0;
|
|
} else {
|
|
if(!$system_hist) {
|
|
$system_hist = time;
|
|
}
|
|
if($system_hist > 0 && (time - $system_hist) > $ALERT_LOADAVG_TIMEINTVL) {
|
|
if(-x $ALERT_LOADAVG_SCRIPT) {
|
|
system($ALERT_LOADAVG_SCRIPT . " " .$ALERT_LOADAVG_TIMEINTVL . " " . $ALERT_LOADAVG_THRESHOLD . " " . $load15);
|
|
}
|
|
$system_hist = time;
|
|
}
|
|
}
|
|
}
|
|
|
|
$rrdata .= ":$load1:$load5:$load15:$nproc:$npslp:$nprun:$npwio:$npzom:$npstp:$npswp:$mtotl:$mbuff:$mcach:$mfree:$macti:$minac:$val01:$val02:$val03:$val04:$val05";
|
|
RRDs::update($SYSTEM_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $SYSTEM_RRD: $err") if $err;
|
|
}
|
|
|
|
# KERN graph
|
|
# ----------------------------------------------------------------------------
|
|
sub kern_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $KERN_RRD)) {
|
|
logger("Creating '$KERN_RRD' file.");
|
|
eval {
|
|
RRDs::create($KERN_RRD,
|
|
"--step=60",
|
|
"DS:kern_user:GAUGE:120:0:100",
|
|
"DS:kern_nice:GAUGE:120:0:100",
|
|
"DS:kern_sys:GAUGE:120:0:100",
|
|
"DS:kern_idle:GAUGE:120:0:100",
|
|
"DS:kern_iow:GAUGE:120:0:100",
|
|
"DS:kern_irq:GAUGE:120:0:100",
|
|
"DS:kern_sirq:GAUGE:120:0:100",
|
|
"DS:kern_steal:GAUGE:120:0:100",
|
|
"DS:kern_guest:GAUGE:120:0:100",
|
|
"DS:kern_cs:COUNTER:120:0:U",
|
|
"DS:kern_dentry:GAUGE:120:0:100",
|
|
"DS:kern_file:GAUGE:120:0:100",
|
|
"DS:kern_inode:GAUGE:120:0:100",
|
|
"DS:kern_forks:COUNTER:120:0:U",
|
|
"DS:kern_vforks:COUNTER:120:0:U",
|
|
"DS:kern_val03:GAUGE:120:0:100",
|
|
"DS:kern_val04:GAUGE:120:0:100",
|
|
"DS:kern_val05:GAUGE:120:0:100",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $KERN_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Since 2.2.0 two new values are used (kern_val01 and kern_val02) to
|
|
# support 'forks' and 'vforks'. These two values need to be converted
|
|
# to COUNTER and renamed.
|
|
RRDs::tune($KERN_RRD,
|
|
"--data-source-rename=kern_val01:kern_forks",
|
|
"--data-source-type=kern_forks:COUNTER",
|
|
"--maximum=kern_forks:U",
|
|
);
|
|
RRDs::tune($KERN_RRD,
|
|
"--data-source-rename=kern_val02:kern_vforks",
|
|
"--data-source-type=kern_vforks:COUNTER",
|
|
"--maximum=kern_vforks:U",
|
|
);
|
|
|
|
our %kernel_hist = ();
|
|
push(@graphs, "kern_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub kern_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $user;
|
|
my $nice;
|
|
my $sys;
|
|
my $idle;
|
|
my $iow;
|
|
my $irq;
|
|
my $sirq;
|
|
my $steal;
|
|
my $guest;
|
|
my $cs;
|
|
my $dentry;
|
|
my $file;
|
|
my $inode;
|
|
my $forks;
|
|
my $vforks = 0;
|
|
my $val03 = 0;
|
|
my $val04 = 0;
|
|
my $val05 = 0;
|
|
|
|
my $lastuser = 0;
|
|
my $lastnice = 0;
|
|
my $lastsys = 0;
|
|
my $lastidle = 0;
|
|
my $lastiow = 0;
|
|
my $lastirq = 0;
|
|
my $lastsirq = 0;
|
|
my $laststeal = 0;
|
|
my $lastguest = 0;
|
|
|
|
my $rrdata = "N";
|
|
|
|
if($kernel_hist{'kernel'}) {
|
|
(undef, $lastuser, $lastnice, $lastsys, $lastidle, $lastiow, $lastirq, $lastsirq, $laststeal, $lastguest) = split(' ', $kernel_hist{'kernel'});
|
|
}
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "/proc/stat");
|
|
while(<IN>) {
|
|
if(/^cpu /) {
|
|
(undef, $user, $nice, $sys, $idle, $iow, $irq, $sirq, $steal, $guest) = split(' ', $_);
|
|
$kernel_hist{'kernel'} = $_;
|
|
next;
|
|
}
|
|
if(/^ctxt (\d+)$/) {
|
|
# avoid initial spike
|
|
$cs = int($1) unless !$kernel_hist{'cs'};
|
|
$kernel_hist{'cs'} = int($1) unless $kernel_hist{'cs'};
|
|
next;
|
|
}
|
|
if(/^processes (\d+)$/) {
|
|
# avoid initial spike
|
|
$forks = int($1) unless !$kernel_hist{'forks'};
|
|
$kernel_hist{'forks'} = int($1) unless $kernel_hist{'forks'};
|
|
$vforks = 0;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
open(IN, "/proc/sys/fs/dentry-state");
|
|
while(<IN>) {
|
|
if(/^(\d+)\s+(\d+)\s+/) {
|
|
$dentry = ($1 * 100) / ($1 + $2);
|
|
}
|
|
}
|
|
close(IN);
|
|
open(IN, "/proc/sys/fs/file-nr");
|
|
while(<IN>) {
|
|
if(/^(\d+)\s+\d+\s+(\d+)$/) {
|
|
$file = ($1 * 100) / $2;
|
|
}
|
|
}
|
|
close(IN);
|
|
open(IN, "/proc/sys/fs/inode-nr");
|
|
while(<IN>) {
|
|
if(/^(\d+)\s+(\d+)$/) {
|
|
$inode = ($1 * 100) / ($1 + $2);
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "FreeBSD") {
|
|
my $max;
|
|
my $num;
|
|
my $data;
|
|
|
|
my $cptime = `sysctl -n kern.cp_time`;
|
|
chomp($cptime);
|
|
my @tmp = split(' ', $cptime);
|
|
($user, $nice, $sys, $iow, $idle) = @tmp;
|
|
|
|
$kernel_hist{'kernel'} = join(' ', "cpu", $user, $nice, $sys, $idle, $iow);
|
|
$data = `sysctl -n vm.stats.sys.v_swtch`;
|
|
chomp($data);
|
|
$cs = int($data) unless !$kernel_hist{'cs'};
|
|
$kernel_hist{'cs'} = int($data) unless $kernel_hist{'cs'};
|
|
|
|
$data = `sysctl -n vm.stats.vm.v_forks`;
|
|
chomp($data);
|
|
$forks = int($data) unless !$kernel_hist{'forks'};
|
|
$kernel_hist{'forks'} = int($data) unless $kernel_hist{'forks'};
|
|
|
|
$data = `sysctl -n vm.stats.vm.v_vforks`;
|
|
chomp($data);
|
|
$vforks = int($data) unless !$kernel_hist{'vforks'};
|
|
$kernel_hist{'vforks'} = int($data) unless $kernel_hist{'vforks'};
|
|
|
|
$max = `sysctl -n kern.maxfiles`;
|
|
chomp($max);
|
|
$num = `sysctl -n kern.openfiles`;
|
|
chomp($num);
|
|
$file = ($num * 100) / $max;
|
|
|
|
$max = `sysctl -n kern.maxvnodes`;
|
|
chomp($max);
|
|
$num = `sysctl -n vfs.numvnodes`;
|
|
chomp($num);
|
|
$inode = ($num * 100) / $max;
|
|
} elsif($os eq "OpenBSD") {
|
|
my $max;
|
|
my $num;
|
|
my $data;
|
|
|
|
my $cptime = `sysctl -n kern.cp_time`;
|
|
chomp($cptime);
|
|
my @tmp = split(',', $cptime);
|
|
($user, $nice, $sys, $iow, $idle) = @tmp;
|
|
$kernel_hist{'kernel'} = join(' ', "cpu", $user, $nice, $sys, $idle, $iow);
|
|
open(IN, "vmstat -s |");
|
|
while(<IN>) {
|
|
if(/^\s*(\d+) cpu context switches$/) {
|
|
$cs = int($1) unless !$kernel_hist{'cs'};
|
|
$kernel_hist{'cs'} = int($1) unless $kernel_hist{'cs'};
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
|
|
$data = `sysctl -n kern.forkstat.forks`;
|
|
chomp($data);
|
|
$forks = int($data) unless !$kernel_hist{'forks'};
|
|
$kernel_hist{'forks'} = int($data) unless $kernel_hist{'forks'};
|
|
|
|
$data = `sysctl -n kern.forkstat.vforks`;
|
|
chomp($data);
|
|
$vforks = int($data) unless !$kernel_hist{'vforks'};
|
|
$kernel_hist{'vforks'} = int($data) unless $kernel_hist{'vforks'};
|
|
|
|
$max = `sysctl -n kern.maxfiles`;
|
|
chomp($max);
|
|
$num = `sysctl -n kern.nfiles`;
|
|
chomp($num);
|
|
$file = ($num * 100) / $max;
|
|
|
|
$max = `sysctl -n kern.maxvnodes`;
|
|
chomp($max);
|
|
$data = `sysctl -n kern.malloc.kmemstat.vnodes`;
|
|
($num) = ($data =~ m/^\(inuse = (\d+), /);
|
|
$inode = ($num * 100) / $max;
|
|
} elsif($os eq "NetBSD") {
|
|
my $max;
|
|
my $num;
|
|
my $data;
|
|
|
|
my $cptime = `sysctl -n kern.cp_time`;
|
|
chomp($cptime);
|
|
my @tmp = ($cptime =~ m/user = (\d+), nice = (\d+), sys = (\d+), intr = (\d+), idle = (\d+)/);
|
|
($user, $nice, $sys, $iow, $idle) = @tmp;
|
|
$kernel_hist{'kernel'} = join(' ', "cpu", $user, $nice, $sys, $idle, $iow);
|
|
open(IN, "vmstat -s |");
|
|
while(<IN>) {
|
|
if(/^\s*(\d+) CPU context switches$/) {
|
|
$cs = int($1) unless !$kernel_hist{'cs'};
|
|
$kernel_hist{'cs'} = int($1) unless $kernel_hist{'cs'};
|
|
next;
|
|
}
|
|
if(/^\s*(\d+) forks total$/) {
|
|
$forks = int($1) unless !$kernel_hist{'forks'};
|
|
$kernel_hist{'forks'} = int($1) unless $kernel_hist{'forks'};
|
|
next;
|
|
}
|
|
}
|
|
close(IN);
|
|
|
|
$vforks = 0;
|
|
|
|
open(IN, "pstat -T |");
|
|
while(<IN>) {
|
|
if(/^(\d+)\/(\d+) files$/) {
|
|
$file = ($1 * 100) / $2;
|
|
}
|
|
}
|
|
close(IN);
|
|
|
|
$inode = 0;
|
|
}
|
|
|
|
# Linux 2.4, early Linux 2.6 versions and other systems don't have
|
|
# these values.
|
|
$iow = 0 unless $iow;
|
|
$irq = 0 unless $irq;
|
|
$sirq = 0 unless $sirq;
|
|
$steal = 0 unless $sirq;
|
|
$guest = 0 unless $guest;
|
|
$lastiow = 0 unless $lastiow;
|
|
$lastirq = 0 unless $lastirq;
|
|
$lastsirq = 0 unless $lastsirq;
|
|
$laststeal = 0 unless $lastsirq;
|
|
$lastguest = 0 unless $lastguest;
|
|
|
|
if($user >= $lastuser && $nice >= $lastnice && $sys >= $lastsys && $idle >= $lastidle && $iow >= $lastiow && $irq >= $lastirq && $sirq >= $lastsirq && $steal >= $laststeal && $guest >= $lastguest) {
|
|
my $user_ = $user - $lastuser;
|
|
my $nice_ = $nice - $lastnice;
|
|
my $sys_ = $sys - $lastsys;
|
|
my $idle_ = $idle - $lastidle;
|
|
my $iow_ = $iow - $lastiow;
|
|
my $irq_ = $irq - $lastirq;
|
|
my $sirq_ = $sirq - $lastsirq;
|
|
my $steal_ = $steal - $laststeal;
|
|
my $guest_ = $guest - $lastguest;
|
|
my $total = $user_ + $nice_ + $sys_ + $idle_ + $iow_ + $irq_ + $sirq_ + $steal_ + $guest_;
|
|
$user = ($user_ * 100) / $total;
|
|
$nice = ($nice_ * 100) / $total;
|
|
$sys = ($sys_ * 100) / $total;
|
|
$idle = ($idle_ * 100) / $total;
|
|
$iow = ($iow_ * 100) / $total;
|
|
$irq = ($irq_ * 100) / $total;
|
|
$sirq = ($sirq_ * 100) / $total;
|
|
$steal = ($steal_ * 100) / $total;
|
|
$guest = ($guest_ * 100) / $total;
|
|
} else {
|
|
$user = "nan";
|
|
$nice = "nan";
|
|
$sys = "nan";
|
|
$idle = "nan";
|
|
$iow = "nan";
|
|
$irq = "nan";
|
|
$sirq = "nan";
|
|
$steal = "nan";
|
|
$guest = "nan";
|
|
}
|
|
|
|
$rrdata .= ":$user:$nice:$sys:$idle:$iow:$irq:$sirq:$steal:$guest:$cs:$dentry:$file:$inode:$forks:$vforks:$val03:$val04:$val05";
|
|
RRDs::update($KERN_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $KERN_RRD: $err") if $err;
|
|
}
|
|
|
|
# PROC graph
|
|
# ----------------------------------------------------------------------------
|
|
sub proc_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
if(!grep {$_ eq $os} ("Linux", "FreeBSD")) {
|
|
logger("$myself is not supported yet by your operating system ($os).");
|
|
return;
|
|
}
|
|
|
|
if(-e $PROC_RRD) {
|
|
$info = RRDs::info($PROC_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
# print("$key\n");
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
# foreach(@ds) {
|
|
# print($_ . "\n");
|
|
# }
|
|
# print(scalar(@ds) . "\n");
|
|
if(scalar(@ds) / 9 != $PROC_MAX) {
|
|
logger("Detected size mismatch between \$PROC_MAX ($PROC_MAX) and $PROC_RRD (" . scalar(@ds) / 9 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($PROC_RRD, "$PROC_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $PROC_RRD)) {
|
|
logger("Creating '$PROC_RRD' file.");
|
|
for($n = 0; $n < $PROC_MAX; $n++) {
|
|
push(@tmp, "DS:proc" . $n . "_user:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_nice:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_sys:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_idle:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_iow:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_irq:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_sirq:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_steal:GAUGE:120:0:100");
|
|
push(@tmp, "DS:proc" . $n . "_guest:GAUGE:120:0:100");
|
|
}
|
|
eval {
|
|
RRDs::create($PROC_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $PROC_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
our %proc_hist = ();
|
|
push(@graphs, "proc_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub proc_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @proc;
|
|
my $total;
|
|
|
|
my $n;
|
|
my @lastproc;
|
|
|
|
my @p;
|
|
my @l;
|
|
my $rrdata = "N";
|
|
|
|
# Read last processor usage data
|
|
my $str;
|
|
for($n = 0; $n < $PROC_MAX; $n++) {
|
|
$str = "cpu" . $n;
|
|
if($proc_hist{$str}) {
|
|
push(@lastproc, $proc_hist{$str});
|
|
}
|
|
}
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "/proc/stat");
|
|
while(<IN>) {
|
|
for($n = 0; $n < $PROC_MAX; $n++) {
|
|
$str = "cpu" . $n;
|
|
if(/^cpu$n /) {
|
|
$proc_hist{$str} = $_;
|
|
chomp($proc_hist{$str});
|
|
push(@proc, $proc_hist{$str});
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "FreeBSD") {
|
|
my $cptimes;
|
|
my @tmp;
|
|
my $from;
|
|
my $to;
|
|
my $ncpu = `sysctl -n hw.ncpu`;
|
|
open(IN, "sysctl -n kern.cp_times |");
|
|
my @data = split(' ', <IN>);
|
|
close(IN);
|
|
chomp($ncpu);
|
|
for($n = 0; $n < $PROC_MAX; $n++) {
|
|
$str = "cpu" . $n;
|
|
$from = $n * 5;
|
|
$to = $from + 4;
|
|
@tmp = @data[$from..$to];
|
|
@tmp[0, 1, 2, 3, 4] = @tmp[0, 1, 2, 4, 3];
|
|
$cptimes = join(' ', @tmp);
|
|
chomp($cptimes);
|
|
$cptimes = $str . " " . $cptimes;
|
|
$proc_hist{$str} = $cptimes;
|
|
push(@proc, $cptimes);
|
|
}
|
|
}
|
|
|
|
my @deltas;
|
|
for($n = 0; $n < $PROC_MAX; $n++) {
|
|
if($proc[$n]) {
|
|
@p = split(' ', $proc[$n]);
|
|
@l = split(' ', $lastproc[$n]);
|
|
@deltas = (
|
|
$p[1] - $l[1], # user
|
|
$p[2] - $l[2], # nice
|
|
$p[3] - $l[3], # sys
|
|
$p[4] - $l[4], # idle
|
|
$p[5] - $l[5], # iow
|
|
$p[6] - $l[6], # irq
|
|
$p[7] - $l[7], # sirq
|
|
$p[8] - $l[8], # steal
|
|
$p[9] - $l[9], # guest
|
|
);
|
|
$total = $deltas[0] + $deltas[1] + $deltas[2] + $deltas[3] + $deltas[4] + $deltas[5] + $deltas[6] + $deltas[7] + $deltas[8];
|
|
|
|
undef(@p);
|
|
push(@p, $deltas[0] ? ($deltas[0] * 100) / $total : 0);
|
|
push(@p, $deltas[1] ? ($deltas[1] * 100) / $total : 0);
|
|
push(@p, $deltas[2] ? ($deltas[2] * 100) / $total : 0);
|
|
push(@p, $deltas[3] ? ($deltas[3] * 100) / $total : 0);
|
|
push(@p, $deltas[4] ? ($deltas[4] * 100) / $total : 0);
|
|
push(@p, $deltas[5] ? ($deltas[5] * 100) / $total : 0);
|
|
push(@p, $deltas[6] ? ($deltas[6] * 100) / $total : 0);
|
|
push(@p, $deltas[7] ? ($deltas[7] * 100) / $total : 0);
|
|
push(@p, $deltas[8] ? ($deltas[8] * 100) / $total : 0);
|
|
$proc[$n] = join(' ', @p);
|
|
} else {
|
|
$proc[$n] = join(' ', (0, 0, 0, 0, 0, 0, 0, 0, 0));
|
|
}
|
|
}
|
|
|
|
for($n = 0; $n < $PROC_MAX; $n++) {
|
|
@p = split(' ', $proc[$n]);
|
|
$rrdata .= ":$p[0]:$p[1]:$p[2]:$p[3]:$p[4]:$p[5]:$p[6]:$p[7]:$p[8]";
|
|
}
|
|
RRDs::update($PROC_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $PROC_RRD: $err") if $err;
|
|
}
|
|
|
|
# HPTEMP graph
|
|
# ----------------------------------------------------------------------------
|
|
sub hptemp_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
# save the contents of 'hplog -t' since only 'root' is able to run it
|
|
# it also checks if 'hplog' does exists.
|
|
if(!open(IN, "hplog -t |")) {
|
|
logger("$myself: unable to execute 'hplog'. $!");
|
|
return;
|
|
}
|
|
my @data = <IN>;
|
|
close(IN);
|
|
open(OUT, "> $BASE_DIR/cgi-bin/monitorix.hplog");
|
|
print(OUT @data);
|
|
close(OUT);
|
|
|
|
if(!(-e $HPTEMP_RRD)) {
|
|
logger("Creating '$HPTEMP_RRD' file.");
|
|
eval {
|
|
RRDs::create($HPTEMP_RRD,
|
|
"--step=60",
|
|
"DS:hptemp1_1:GAUGE:120:0:100",
|
|
"DS:hptemp1_2:GAUGE:120:0:100",
|
|
"DS:hptemp1_3:GAUGE:120:0:100",
|
|
"DS:hptemp1_4:GAUGE:120:0:100",
|
|
"DS:hptemp1_5:GAUGE:120:0:100",
|
|
"DS:hptemp1_6:GAUGE:120:0:100",
|
|
"DS:hptemp1_7:GAUGE:120:0:100",
|
|
"DS:hptemp1_8:GAUGE:120:0:100",
|
|
"DS:hptemp2_1:GAUGE:120:0:100",
|
|
"DS:hptemp2_2:GAUGE:120:0:100",
|
|
"DS:hptemp2_3:GAUGE:120:0:100",
|
|
"DS:hptemp2_4:GAUGE:120:0:100",
|
|
"DS:hptemp2_5:GAUGE:120:0:100",
|
|
"DS:hptemp2_6:GAUGE:120:0:100",
|
|
"DS:hptemp3_1:GAUGE:120:0:100",
|
|
"DS:hptemp3_2:GAUGE:120:0:100",
|
|
"DS:hptemp3_3:GAUGE:120:0:100",
|
|
"DS:hptemp3_4:GAUGE:120:0:100",
|
|
"DS:hptemp3_5:GAUGE:120:0:100",
|
|
"DS:hptemp3_6:GAUGE:120:0:100",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $HPTEMP_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "hptemp_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub hptemp_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @hptemp1;
|
|
my @hptemp2;
|
|
my @hptemp3;
|
|
|
|
my $l;
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
open(IN, "hplog -t |");
|
|
my @data = <IN>;
|
|
close(IN);
|
|
my $str;
|
|
for($l = 0; $l < scalar(@data); $l++) {
|
|
$_ = @data[$l];
|
|
foreach my $t (@HPTEMP_1) {
|
|
$str = sprintf("%2d", $t);
|
|
if(/^$str /) {
|
|
my $temp = substr($_, 47, 3);
|
|
chomp($temp);
|
|
push(@hptemp1, int($temp));
|
|
}
|
|
}
|
|
foreach my $t (@HPTEMP_2) {
|
|
$str = sprintf("%2d", $t);
|
|
if(/^$str /) {
|
|
my $temp = substr($_, 47, 3);
|
|
chomp($temp);
|
|
push(@hptemp2, int($temp));
|
|
}
|
|
}
|
|
foreach my $t (@HPTEMP_3) {
|
|
$str = sprintf("%2d", $t);
|
|
if(/^$str /) {
|
|
my $temp = substr($_, 47, 3);
|
|
chomp($temp);
|
|
push(@hptemp3, int($temp));
|
|
}
|
|
}
|
|
}
|
|
for($n = 0; $n < 8; $n++) {
|
|
$hptemp1[$n] = 0 unless $hptemp1[$n];
|
|
$rrdata .= ":$hptemp1[$n]";
|
|
}
|
|
for($n = 0; $n < 6; $n++) {
|
|
$hptemp2[$n] = 0 unless $hptemp2[$n];
|
|
$rrdata .= ":$hptemp2[$n]";
|
|
}
|
|
for($n = 0; $n < 6; $n++) {
|
|
$hptemp3[$n] = 0 unless $hptemp3[$n];
|
|
$rrdata .= ":$hptemp3[$n]";
|
|
}
|
|
|
|
RRDs::update($HPTEMP_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $HPTEMP_RRD: $err") if $err;
|
|
}
|
|
|
|
# LMSENS graph
|
|
# ----------------------------------------------------------------------------
|
|
sub lmsens_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $LMSENS_RRD)) {
|
|
logger("Creating '$LMSENS_RRD' file.");
|
|
eval {
|
|
RRDs::create($LMSENS_RRD,
|
|
"--step=60",
|
|
"DS:lmsens_mb0:GAUGE:120:0:100",
|
|
"DS:lmsens_mb1:GAUGE:120:0:100",
|
|
"DS:lmsens_cpu0:GAUGE:120:0:100",
|
|
"DS:lmsens_cpu1:GAUGE:120:0:100",
|
|
"DS:lmsens_cpu2:GAUGE:120:0:100",
|
|
"DS:lmsens_cpu3:GAUGE:120:0:100",
|
|
"DS:lmsens_fan0:GAUGE:120:0:U",
|
|
"DS:lmsens_fan1:GAUGE:120:0:U",
|
|
"DS:lmsens_fan2:GAUGE:120:0:U",
|
|
"DS:lmsens_fan3:GAUGE:120:0:U",
|
|
"DS:lmsens_fan4:GAUGE:120:0:U",
|
|
"DS:lmsens_fan5:GAUGE:120:0:U",
|
|
"DS:lmsens_fan6:GAUGE:120:0:U",
|
|
"DS:lmsens_fan7:GAUGE:120:0:U",
|
|
"DS:lmsens_fan8:GAUGE:120:0:U",
|
|
"DS:lmsens_core0:GAUGE:120:0:100",
|
|
"DS:lmsens_core1:GAUGE:120:0:100",
|
|
"DS:lmsens_core2:GAUGE:120:0:100",
|
|
"DS:lmsens_core3:GAUGE:120:0:100",
|
|
"DS:lmsens_core4:GAUGE:120:0:100",
|
|
"DS:lmsens_core5:GAUGE:120:0:100",
|
|
"DS:lmsens_core6:GAUGE:120:0:100",
|
|
"DS:lmsens_core7:GAUGE:120:0:100",
|
|
"DS:lmsens_core8:GAUGE:120:0:100",
|
|
"DS:lmsens_core9:GAUGE:120:0:100",
|
|
"DS:lmsens_core10:GAUGE:120:0:100",
|
|
"DS:lmsens_core11:GAUGE:120:0:100",
|
|
"DS:lmsens_core12:GAUGE:120:0:100",
|
|
"DS:lmsens_core13:GAUGE:120:0:100",
|
|
"DS:lmsens_core14:GAUGE:120:0:100",
|
|
"DS:lmsens_core15:GAUGE:120:0:100",
|
|
"DS:lmsens_volt0:GAUGE:120:U:U",
|
|
"DS:lmsens_volt1:GAUGE:120:U:U",
|
|
"DS:lmsens_volt2:GAUGE:120:U:U",
|
|
"DS:lmsens_volt3:GAUGE:120:U:U",
|
|
"DS:lmsens_volt4:GAUGE:120:U:U",
|
|
"DS:lmsens_volt5:GAUGE:120:U:U",
|
|
"DS:lmsens_volt6:GAUGE:120:U:U",
|
|
"DS:lmsens_volt7:GAUGE:120:U:U",
|
|
"DS:lmsens_volt8:GAUGE:120:U:U",
|
|
"DS:lmsens_volt9:GAUGE:120:U:U",
|
|
"DS:lmsens_volt10:GAUGE:120:U:U",
|
|
"DS:lmsens_volt11:GAUGE:120:U:U",
|
|
"DS:lmsens_gpu0:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu1:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu2:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu3:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu4:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu5:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu6:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu7:GAUGE:120:0:100",
|
|
"DS:lmsens_gpu8:GAUGE:120:0:100",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $LMSENS_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "lmsens_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub get_nvidia_data {
|
|
my ($gpu) = @_;
|
|
my $total = 0;
|
|
my $used = 0;
|
|
my $mem = 0;
|
|
my $cpu = 0;
|
|
my $temp = 0;
|
|
my $check_mem = 0;
|
|
my $check_cpu = 0;
|
|
my $check_temp = 0;
|
|
|
|
open(IN, "nvidia-smi -q -i $gpu -d MEMORY,UTILIZATION,TEMPERATURE |");
|
|
my @data = <IN>;
|
|
close(IN);
|
|
for($l = 0; $l < scalar(@data); $l++) {
|
|
$_ = @data[$l];
|
|
if(/Memory Usage/) {
|
|
$check_mem = 1;
|
|
next;
|
|
}
|
|
if($check_mem) {
|
|
if(/Total/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$total = int($value);
|
|
}
|
|
}
|
|
if(/Used/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$used = int($value);
|
|
}
|
|
$check_mem = 0;
|
|
}
|
|
}
|
|
|
|
if(/Utilization/) {
|
|
$check_cpu = 1;
|
|
next;
|
|
}
|
|
if($check_cpu) {
|
|
if(/Gpu/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$cpu = int($value);
|
|
}
|
|
}
|
|
if(/Memory/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$mem = int($value);
|
|
}
|
|
}
|
|
$check_cpu = 0;
|
|
}
|
|
|
|
if(/Temperature/) {
|
|
$check_temp = 1;
|
|
next;
|
|
}
|
|
if($check_temp) {
|
|
if(/Gpu/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$temp = int($value);
|
|
}
|
|
}
|
|
$check_temp = 0;
|
|
}
|
|
}
|
|
# NVIDIA driver v285.+ not supported (needs new output parsing).
|
|
# This is to avoid a divide by zero message.
|
|
if($total) {
|
|
$mem = ($used * 100) / $total;
|
|
} else {
|
|
$mem = $used = $total = 0;
|
|
}
|
|
return join(" ", $mem, $cpu, $temp);
|
|
}
|
|
|
|
sub lmsens_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @mb;
|
|
my @cpu;
|
|
my @fan;
|
|
my @core;
|
|
my @volt;
|
|
my @gpu;
|
|
|
|
my $l;
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
if($os eq "Linux") {
|
|
if(scalar(%SENSORS_LIST)) {
|
|
open(IN, "sensors |");
|
|
my @data = <IN>;
|
|
close(IN);
|
|
my $str;
|
|
for($l = 0; $l < scalar(@data); $l++) {
|
|
$_ = @data[$l];
|
|
for($n = 0; $n < 2; $n++) {
|
|
$str = "MB" . $n;
|
|
$mb[$n] = 0 unless $mb[$n];
|
|
if($SENSORS_LIST{$str} && (/^$SENSORS_LIST{$str}:/) && (!/RPM/)) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$mb[$n] = int($value);
|
|
}
|
|
}
|
|
for($n = 0; $n < 4; $n++) {
|
|
$str = "CPU" . $n;
|
|
$cpu[$n] = 0 unless $cpu[$n];
|
|
if($SENSORS_LIST{$str} && (/^$SENSORS_LIST{$str}:/) && (!/RPM/)) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$cpu[$n] = int($value);
|
|
}
|
|
}
|
|
for($n = 0; $n < 9; $n++) {
|
|
$str = "FAN" . $n;
|
|
$fan[$n] = 0 unless $fan[$n];
|
|
if($SENSORS_LIST{$str} && (/^$SENSORS_LIST{$str}:/) && (/RPM/)) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$fan[$n] = int($value);
|
|
}
|
|
}
|
|
for($n = 0; $n < 16; $n++) {
|
|
$str = "CORE" . $n;
|
|
$core[$n] = 0 unless $core[$n];
|
|
if($SENSORS_LIST{$str} && (/^$SENSORS_LIST{$str}:/) && (!/RPM/)) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$core[$n] = int($value);
|
|
}
|
|
}
|
|
for($n = 0; $n < 12; $n++) {
|
|
$str = "VOLT" . $n;
|
|
$volt[$n] = 0 unless $volt[$n];
|
|
if($SENSORS_LIST{$str} && (/^$SENSORS_LIST{$str}:/) && (!/RPM/)) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$volt[$n] = $value;
|
|
}
|
|
}
|
|
}
|
|
for($n = 0; $n < 9; $n++) {
|
|
$str = "GPU" . $n;
|
|
$gpu[$n] = 0 unless $gpu[$n];
|
|
if($SENSORS_LIST{$str} && $SENSORS_LIST{$str} eq "nvidia") {
|
|
(undef, undef, $gpu[$n]) = split(' ', get_nvidia_data($n));
|
|
if(!$gpu[$n]) {
|
|
# attempt to get data using the old driver version
|
|
open(IN, "nvidia-smi -g $n |");
|
|
my @data = <IN>;
|
|
close(IN);
|
|
for($l = 0; $l < scalar(@data); $l++) {
|
|
$_ = @data[$l];
|
|
if(/Temperature/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$gpu[$n] = int($value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for($n = 0; $n < scalar(@mb); $n++) {
|
|
$rrdata .= ":$mb[$n]";
|
|
}
|
|
for($n = 0; $n < scalar(@cpu); $n++) {
|
|
$rrdata .= ":$cpu[$n]";
|
|
}
|
|
for($n = 0; $n < scalar(@fan); $n++) {
|
|
$rrdata .= ":$fan[$n]";
|
|
}
|
|
for($n = 0; $n < scalar(@core); $n++) {
|
|
$rrdata .= ":$core[$n]";
|
|
}
|
|
for($n = 0; $n < scalar(@volt); $n++) {
|
|
$rrdata .= ":$volt[$n]";
|
|
}
|
|
for($n = 0; $n < scalar(@gpu); $n++) {
|
|
$rrdata .= ":$gpu[$n]";
|
|
}
|
|
}
|
|
|
|
RRDs::update($LMSENS_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $LMSENS_RRD: $err") if $err;
|
|
}
|
|
|
|
# NVIDIA graph
|
|
# ----------------------------------------------------------------------------
|
|
sub nvidia_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $NVIDIA_RRD)) {
|
|
logger("Creating '$NVIDIA_RRD' file.");
|
|
eval {
|
|
RRDs::create($NVIDIA_RRD,
|
|
"--step=60",
|
|
"DS:nvidia_temp0:GAUGE:120:0:U",
|
|
"DS:nvidia_temp1:GAUGE:120:0:U",
|
|
"DS:nvidia_temp2:GAUGE:120:0:U",
|
|
"DS:nvidia_temp3:GAUGE:120:0:U",
|
|
"DS:nvidia_temp4:GAUGE:120:0:U",
|
|
"DS:nvidia_temp5:GAUGE:120:0:U",
|
|
"DS:nvidia_temp6:GAUGE:120:0:U",
|
|
"DS:nvidia_temp7:GAUGE:120:0:U",
|
|
"DS:nvidia_temp8:GAUGE:120:0:U",
|
|
"DS:nvidia_gpu0:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu1:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu2:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu3:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu4:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu5:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu6:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu7:GAUGE:120:0:100",
|
|
"DS:nvidia_gpu8:GAUGE:120:0:100",
|
|
"DS:nvidia_mem0:GAUGE:120:0:100",
|
|
"DS:nvidia_mem1:GAUGE:120:0:100",
|
|
"DS:nvidia_mem2:GAUGE:120:0:100",
|
|
"DS:nvidia_mem3:GAUGE:120:0:100",
|
|
"DS:nvidia_mem4:GAUGE:120:0:100",
|
|
"DS:nvidia_mem5:GAUGE:120:0:100",
|
|
"DS:nvidia_mem6:GAUGE:120:0:100",
|
|
"DS:nvidia_mem7:GAUGE:120:0:100",
|
|
"DS:nvidia_mem8:GAUGE:120:0:100",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $NVIDIA_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "nvidia_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub nvidia_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @temp;
|
|
my @gpu;
|
|
my @mem;
|
|
my @data;
|
|
my $utilization;
|
|
|
|
my $l;
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
for($n = 0; $n < 9; $n++) {
|
|
$temp[$n] = 0;
|
|
$gpu[$n] = 0;
|
|
$mem[$n] = 0;
|
|
if($n < $NVIDIA_MAX) {
|
|
($mem[$n], $gpu[$n], $temp[$n]) = split(' ', get_nvidia_data($n));
|
|
if(!$temp[$n] && !$gpu[$n] && !$mem[$n]) {
|
|
# attempt to get data using the old driver version
|
|
$utilization = 0;
|
|
open(IN, "nvidia-smi -g $n |");
|
|
@data = <IN>;
|
|
close(IN);
|
|
for($l = 0; $l < scalar(@data); $l++) {
|
|
$_ = @data[$l];
|
|
if(/Temperature/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$temp[$n] = int($value);
|
|
}
|
|
}
|
|
if(/Utilization/) {
|
|
$utilization = 1;
|
|
}
|
|
if($utilization == 1) {
|
|
if(/GPU/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$gpu[$n] = int($value);
|
|
}
|
|
}
|
|
if(/Memory/) {
|
|
my (undef, $tmp) = split(':', $_);
|
|
if($tmp eq "\n") {
|
|
$l++;
|
|
$tmp = $data[$l];
|
|
}
|
|
my ($value, undef) = split(' ', $tmp);
|
|
$value =~ s/[-]/./;
|
|
$value =~ s/[^0-9.]//g;
|
|
if(int($value) > 0) {
|
|
$mem[$n] = int($value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for($n = 0; $n < scalar(@temp); $n++) {
|
|
$rrdata .= ":$temp[$n]";
|
|
}
|
|
for($n = 0; $n < scalar(@gpu); $n++) {
|
|
$rrdata .= ":$gpu[$n]";
|
|
}
|
|
for($n = 0; $n < scalar(@mem); $n++) {
|
|
$rrdata .= ":$mem[$n]";
|
|
}
|
|
|
|
RRDs::update($NVIDIA_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $NVIDIA_RRD: $err") if $err;
|
|
}
|
|
|
|
# DISK graph
|
|
# ----------------------------------------------------------------------------
|
|
sub disk_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
# This warns and transforms an old @DISK_LIST array (before 2.6) into
|
|
# the new two-dimensional array to keep backwards compatibility.
|
|
my @tmp2;
|
|
if(!(ref($DISK_LIST[0]) eq "ARRAY")) {
|
|
logger("$myself: \@DISK_LIST array format is outdated. Please check monitorix.conf(5) man page to see how this array must be defined.");
|
|
push(@{$tmp2[0]}, @DISK_LIST);
|
|
@DISK_LIST = @tmp2;
|
|
}
|
|
|
|
if(-e $DISK_RRD) {
|
|
$info = RRDs::info($DISK_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 24 != scalar(@DISK_LIST)) {
|
|
logger("Detected size mismatch between \@DISK_LIST (" . scalar(@DISK_LIST) . ") and $DISK_RRD (" . scalar(@ds) / 24 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($DISK_RRD, "$DISK_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $DISK_RRD)) {
|
|
logger("Creating '$DISK_RRD' file.");
|
|
for($n = 0; $n < scalar(@DISK_LIST); $n++) {
|
|
push(@tmp, "DS:disk" . $n . "_hd0_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd0_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd0_smart2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd1_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd1_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd1_smart2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd2_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd2_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd2_smart2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd3_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd3_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd3_smart2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd4_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd4_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd4_smart2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd5_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd5_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd5_smart2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd6_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd6_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd6_smart2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd7_temp:GAUGE:120:0:100");
|
|
push(@tmp, "DS:disk" . $n . "_hd7_smart1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:disk" . $n . "_hd7_smart2:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($DISK_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $DISK_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Since 2.6.0 disk.rrd supports unlimited disk device monitoring, this
|
|
# forces to rename the DS of the first disk accordingly.
|
|
for($n = 0; $n < 8; $n++) {
|
|
RRDs::tune($DISK_RRD,
|
|
"--data-source-rename=disk_hd" . $n . "_temp:disk0_hd" . $n . "_temp",
|
|
"--data-source-rename=disk_hd" . $n . "_smart1:disk0_hd" . $n . "_smart1",
|
|
"--data-source-rename=disk_hd" . $n . "_smart2:disk0_hd" . $n . "_smart2",
|
|
);
|
|
}
|
|
|
|
push(@graphs, "disk_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub disk_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $temp;
|
|
my $smart1;
|
|
my $smart2;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
foreach my $i (@DISK_LIST) {
|
|
for($n = 0; $n < 8; $n++) {
|
|
$temp = 0;
|
|
$smart1 = 0;
|
|
$smart2 = 0;
|
|
if(@$i[$n]) {
|
|
my $d = @$i[$n];
|
|
open(IN, "smartctl -A $d |");
|
|
while(<IN>) {
|
|
if(/^ 5/ && /Reallocated_Sector_Ct/) {
|
|
my @tmp = split(' ', $_);
|
|
$smart1 = $tmp[9];
|
|
chomp($smart1);
|
|
}
|
|
if(/^194/ && /Temperature_Celsius/) {
|
|
my @tmp = split(' ', $_);
|
|
$temp = $tmp[9];
|
|
chomp($temp);
|
|
}
|
|
if(/^197/ && /Current_Pending_Sector/) {
|
|
my @tmp = split(' ', $_);
|
|
$smart2 = $tmp[9];
|
|
chomp($smart2);
|
|
}
|
|
if(/^Current Drive Temperature: /) {
|
|
my @tmp = split(' ', $_);
|
|
$temp = $tmp[3] unless $temp;
|
|
chomp($temp);
|
|
}
|
|
}
|
|
close(IN);
|
|
$temp = `hddtemp -wqn $d` unless $temp;
|
|
chomp($temp);
|
|
}
|
|
$rrdata .= ":$temp";
|
|
$rrdata .= ":$smart1";
|
|
$rrdata .= ":$smart2";
|
|
}
|
|
}
|
|
|
|
RRDs::update($DISK_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $DISK_RRD: $err") if $err;
|
|
}
|
|
|
|
# FS graph
|
|
# ----------------------------------------------------------------------------
|
|
sub is_in_diskstats {
|
|
my ($d, $major, $minor) = @_;
|
|
|
|
open(IN, "/proc/diskstats");
|
|
my @data = <IN>;
|
|
close(IN);
|
|
foreach(@data) {
|
|
my ($maj, $min, $device) = split(' ', $_);
|
|
return $device unless $d ne $device;
|
|
if($maj == $major && $min == $minor) {
|
|
return $device;
|
|
}
|
|
}
|
|
}
|
|
|
|
sub is_luks {
|
|
my ($d) = @_;
|
|
|
|
if($d =~ m/luks/) {
|
|
$d =~ s/luks-//;
|
|
$d = `blkid -t UUID=$d | awk -F ":" '{ print \$1 }'`;
|
|
chomp($d);
|
|
$d =~ s/^.*dev\///; # remove the /dev/ prefix
|
|
$d =~ s/^.*mapper\///; # remove the mapper/ prefix
|
|
return $d;
|
|
}
|
|
}
|
|
|
|
sub fs_init {
|
|
my $myself = (caller(0))[3];
|
|
our %FS_DEV;
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
# This warns if an old @FS_LIST array (before 2.6) is still used.
|
|
my @tmp2;
|
|
if(!(ref($FS_LIST[0]) eq "ARRAY")) {
|
|
logger("$myself: \@FS_LIST array format is outdated. Please check monitorix.conf(5) man page to see how this array must be defined.");
|
|
push(@{$tmp2[0]}, @FS_LIST);
|
|
@FS_LIST = @tmp2;
|
|
}
|
|
|
|
if(-e $FS_RRD) {
|
|
$info = RRDs::info($FS_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 24 != scalar(@FS_LIST)) {
|
|
logger("Detected size mismatch between \@FS_LIST (" . scalar(@FS_LIST) . ") and $FS_RRD (" . scalar(@ds) / 24 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($FS_RRD, "$FS_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $FS_RRD)) {
|
|
logger("Creating '$FS_RRD' file.");
|
|
for($n = 0; $n < scalar(@FS_LIST); $n++) {
|
|
push(@tmp, "DS:fs" . $n . "_use0:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_use1:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_use2:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_use3:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa3:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim3:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_use4:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa4:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim4:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_use5:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa5:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim5:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_use6:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa6:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim6:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_use7:GAUGE:120:0:100");
|
|
push(@tmp, "DS:fs" . $n . "_ioa7:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fs" . $n . "_tim7:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($FS_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $FS_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
# This tries to find out the physical device name of each fs.
|
|
foreach my $i (@FS_LIST) {
|
|
foreach my $fs (@$i) {
|
|
my $d = $FS_DEV{$fs};
|
|
|
|
next unless !$d;
|
|
|
|
if($fs ne "swap") {
|
|
eval {
|
|
alarm $TIMEOUT;
|
|
open(IN, "df -P $fs |");
|
|
while(<IN>) {
|
|
if(/ $fs$/) {
|
|
($d) = split(' ', $_);
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
alarm 0;
|
|
chomp($d);
|
|
};
|
|
}
|
|
|
|
if($os eq "Linux" && $kernel_branch > 2.4) {
|
|
my $lvm;
|
|
my $lvm_disk;
|
|
my $is_md;
|
|
my $found;
|
|
|
|
if($fs eq "swap") {
|
|
$d = `cat /proc/swaps | tail -1 | awk -F " " '{ print \$1 }'`;
|
|
chomp($d);
|
|
}
|
|
|
|
# check for device names using symbolic links
|
|
# e.g. /dev/disk/by-uuid/db312d12-0da6-44e5-a354-4c82118f4b66
|
|
if(-l $d) {
|
|
$link = readlink($d);
|
|
$d = abs_path(dirname($d) . "/" . $link);
|
|
chomp($d);
|
|
}
|
|
|
|
# get the major and minor of $d
|
|
my $rdev = (stat($d))[6];
|
|
my $minor = $rdev % 256;
|
|
my $major = int($rdev / 256);
|
|
|
|
# do exists in /proc/diskstats?
|
|
if($found = is_in_diskstats($d, $major, $minor)) {
|
|
$d = $found;
|
|
$FS_DEV{$fs} = $d;
|
|
logger("$myself: Detected physical device name for $fs in '$d'.") unless !$opt_d;
|
|
next;
|
|
}
|
|
|
|
logger("$myself: Unable to find major/minor in /proc/diskstats.") unless !$opt_d;
|
|
|
|
# check if device is using EVMS <http://evms.sourceforge.net/>
|
|
if($d =~ m/\/dev\/evms\//) {
|
|
$d = `evms_query disks $d`;
|
|
if($found = is_in_diskstats($d)) {
|
|
$d = $found;
|
|
$FS_DEV{$fs} = $d;
|
|
logger("$myself: Detected physical device name for $fs in '$d'.") unless !$opt_d;
|
|
next;
|
|
}
|
|
}
|
|
|
|
$d =~ s/^.*dev\///; # remove the /dev/ prefix
|
|
$d =~ s/^.*mapper\///; # remove the mapper/ prefix
|
|
|
|
# check if the device is under a crypt LUKS (encrypted fs)
|
|
if($dev = is_luks($d)) {
|
|
$d = $dev;
|
|
}
|
|
|
|
# do exists in /proc/diskstats?
|
|
if($found = is_in_diskstats($d)) {
|
|
$d = $found;
|
|
$FS_DEV{$fs} = $d;
|
|
logger("$myself: Detected physical device name for $fs in '$d'.") unless !$opt_d;
|
|
next;
|
|
}
|
|
|
|
# check if the device is in a LVM
|
|
$lvm = $d;
|
|
$lvm =~ s/-.*//;
|
|
if($lvm ne $d) { # probably LVM
|
|
if(system("pvs >/dev/null 2>&1") == 0 && $lvm) {
|
|
$lvm_disk = `pvs --noheadings | grep $lvm | tail -1 | awk -F " " '{ print \$1 }'`;
|
|
chomp($lvm_disk);
|
|
$lvm_disk =~ s/^.*dev\///; # remove the /dev/ prefix
|
|
$lvm_disk =~ s/^.*mapper\///; # remove the mapper/ prefix
|
|
if(!($lvm_disk =~ m/md/)) {
|
|
if($lvm_disk =~ m/cciss/) {
|
|
# LVM over a CCISS disk (/dev/cciss/c0d0)
|
|
$d = $lvm_disk;
|
|
chomp($d);
|
|
} elsif($dev = is_luks($lvm_disk)) {
|
|
$d = $dev;
|
|
} else {
|
|
# LVM over a direct disk (/dev/sda1)
|
|
$d = $lvm_disk;
|
|
chomp($d);
|
|
}
|
|
} else {
|
|
# LVM over Linux RAID combination (/dev/md1)
|
|
$d = $lvm_disk;
|
|
chomp($d);
|
|
}
|
|
}
|
|
}
|
|
} elsif($os eq "FreeBSD" || $os eq "OpenBSD" || $os eq "NetBSD") {
|
|
# remove the /dev/ prefix
|
|
if ($d =~ s/^.*dev\///) {
|
|
# not ZFS; get the device name, eg ada0; md0; ad10
|
|
$d =~ s/^(\D+\d*)\D.*/\1/;
|
|
} else {
|
|
# Just take ZFS pool name
|
|
$d =~ s,^([^/]*)/.*,\1,;
|
|
}
|
|
}
|
|
$FS_DEV{$fs} = $d;
|
|
logger("$myself: Detected physical device name for $fs in '$d'.") unless !$opt_d;
|
|
}
|
|
}
|
|
|
|
our %fs_hist = ();
|
|
push(@graphs, "fs_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub fs_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @tmp;
|
|
my $val;
|
|
my $str;
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
my $e = 0;
|
|
foreach my $i (@FS_LIST) {
|
|
for($n = 0; $n < 8; $n++) {
|
|
my $use = 0;
|
|
my $ioa = 0;
|
|
my $tim = 0;
|
|
|
|
my $used = 0;
|
|
my $free = 0;
|
|
|
|
$fs = @$i[$n];
|
|
if($fs eq "swap") {
|
|
if($os eq "Linux") {
|
|
open(IN, "free |");
|
|
while(<IN>) {
|
|
if(/^Swap:\s+\d+\s+(\d+)\s+(\d+)$/) {
|
|
$used = $1;
|
|
$free = $2;
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "FreeBSD") {
|
|
open(IN, "swapinfo -k |");
|
|
while(<IN>) {
|
|
if(/^.*?\s+\d+\s+(\d+)\s+(\d+)\s+\d+\%$/) {
|
|
$used = $1;
|
|
$free = $2;
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "OpenBSD" || $os eq "NetBSD") {
|
|
open(IN, "pstat -sk |");
|
|
while(<IN>) {
|
|
if(/^swap_device\s+\d+\s+(\d+)\s+(\d+) /) {
|
|
$used = $1;
|
|
$free = $2;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
chomp($used, $free);
|
|
# prevents a division by 0 if swap device is not used
|
|
$use = ($used * 100) / ($used + $free) unless $used + $free == 0;
|
|
} elsif($fs) {
|
|
eval {
|
|
alarm $TIMEOUT;
|
|
open(IN, "df -P $fs |");
|
|
while(<IN>) {
|
|
if(/ $fs$/) {
|
|
@tmp = split(' ', $_);
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
alarm 0;
|
|
};
|
|
(undef, undef, $used, $free) = @tmp;
|
|
chomp($used, $free);
|
|
$use = ($used * 100) / ($used + $free);
|
|
|
|
# FS alert
|
|
if($fs eq "/" && $ENABLE_ALERTS eq "Y") {
|
|
if(!$ALERT_ROOTFS_THRESHOLD || $pcnt < $ALERT_ROOTFS_THRESHOLD) {
|
|
$fs_hist{'rootalert'} = 0;
|
|
} else {
|
|
if(!$fs_hist{'rootalert'}) {
|
|
$fs_hist{'rootalert'} = time;
|
|
}
|
|
if($fs_hist{'rootalert'} > 0 && (time - $fs_hist{'rootalert'}) > $ALERT_ROOTFS_TIMEINTVL) {
|
|
if(-x $ALERT_ROOTFS_SCRIPT) {
|
|
system($ALERT_ROOTFS_SCRIPT . " " . $ALERT_ROOTFS_TIMEINTVL . " " . $ALERT_ROOTFS_THRESHOLD . " " . $pcnt);
|
|
}
|
|
$fs_hist{'rootalert'} = time;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
my $read_cnt = 0;
|
|
my $read_sec = 0;
|
|
my $write_cnt = 0;
|
|
my $write_sec = 0;
|
|
my $d = $FS_DEV{$fs};
|
|
if($d) {
|
|
if($os eq "Linux") {
|
|
if($kernel_branch > 2.4) {
|
|
open(IN, "/proc/diskstats");
|
|
while(<IN>) {
|
|
if(/ $d /) {
|
|
@tmp = split(' ', $_);
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
(undef, undef, undef, $read_cnt, undef, undef, $read_sec, $write_cnt, undef, undef, $write_sec) = @tmp;
|
|
} else {
|
|
my $io;
|
|
open(IN, "/proc/stat");
|
|
while(<IN>) {
|
|
if(/^disk_io/) {
|
|
(undef, undef, $io) = split(':', $_);
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
(undef, $read_cnt, $read_sec, $write_cnt, $write_sec) = split(',', $io);
|
|
$write_sec =~ s/\).*$//;
|
|
}
|
|
} elsif($os eq "FreeBSD") {
|
|
@tmp = split(' ', `iostat -xI $d | grep -w $d`);
|
|
if(@tmp) {
|
|
(undef, $read_cnt, $write_cnt, $read_sec, $write_sec) = @tmp;
|
|
$read_cnt = int($read_cnt);
|
|
$write_cnt = int($write_cnt);
|
|
$read_sec = int($read_sec);
|
|
$write_sec = int($write_sec);
|
|
} else {
|
|
@tmp = split(' ', `iostat -dI | tail -1`);
|
|
(undef, $read_cnt, $read_sec) = @tmp;
|
|
$write_cnt = "";
|
|
$write_sec = "";
|
|
chomp($read_sec);
|
|
$read_sec = int($read_sec);
|
|
}
|
|
} elsif($os eq "OpenBSD" || $os eq "NetBSD") {
|
|
@tmp = split(' ', `iostat -DI | tail -1`);
|
|
($read_cnt, $read_sec) = @tmp;
|
|
$write_cnt = "";
|
|
$write_sec = "";
|
|
chomp($read_sec);
|
|
$read_sec = int($read_sec);
|
|
}
|
|
}
|
|
|
|
$ioa = $read_cnt + $write_cnt;
|
|
$tim = $read_sec + $write_sec;
|
|
|
|
$str = $e . "_ioa" . $n;
|
|
$val = $ioa;
|
|
$ioa = $val - $fs_hist{$str};
|
|
$ioa = 0 unless $val != $ioa;
|
|
$ioa /= 60;
|
|
$fs_hist{$str} = $val;
|
|
|
|
$str = $e . "_tim" . $n;
|
|
$val = $tim;
|
|
$tim = $val - $fs_hist{$str};
|
|
$tim = 0 unless $val != $tim;
|
|
$tim /= 60;
|
|
$fs_hist{$str} = $val;
|
|
|
|
$rrdata .= ":$use:$ioa:$tim";
|
|
}
|
|
$e++;
|
|
}
|
|
|
|
RRDs::update($FS_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $FS_RRD: $err") if $err;
|
|
}
|
|
|
|
# NET graph
|
|
# ----------------------------------------------------------------------------
|
|
sub net_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $NET_RRD)) {
|
|
logger("Creating '$NET_RRD' file.");
|
|
eval {
|
|
RRDs::create($NET_RRD,
|
|
"--step=60",
|
|
"DS:net0_bytes_in:COUNTER:120:0:U",
|
|
"DS:net0_bytes_out:COUNTER:120:0:U",
|
|
"DS:net0_packs_in:COUNTER:120:0:U",
|
|
"DS:net0_packs_out:COUNTER:120:0:U",
|
|
"DS:net0_error_in:COUNTER:120:0:U",
|
|
"DS:net0_error_out:COUNTER:120:0:U",
|
|
"DS:net1_bytes_in:COUNTER:120:0:U",
|
|
"DS:net1_bytes_out:COUNTER:120:0:U",
|
|
"DS:net1_packs_in:COUNTER:120:0:U",
|
|
"DS:net1_packs_out:COUNTER:120:0:U",
|
|
"DS:net1_error_in:COUNTER:120:0:U",
|
|
"DS:net1_error_out:COUNTER:120:0:U",
|
|
"DS:net2_bytes_in:COUNTER:120:0:U",
|
|
"DS:net2_bytes_out:COUNTER:120:0:U",
|
|
"DS:net2_packs_in:COUNTER:120:0:U",
|
|
"DS:net2_packs_out:COUNTER:120:0:U",
|
|
"DS:net2_error_in:COUNTER:120:0:U",
|
|
"DS:net2_error_out:COUNTER:120:0:U",
|
|
"DS:net3_bytes_in:COUNTER:120:0:U",
|
|
"DS:net3_bytes_out:COUNTER:120:0:U",
|
|
"DS:net3_packs_in:COUNTER:120:0:U",
|
|
"DS:net3_packs_out:COUNTER:120:0:U",
|
|
"DS:net3_error_in:COUNTER:120:0:U",
|
|
"DS:net3_error_out:COUNTER:120:0:U",
|
|
"DS:net4_bytes_in:COUNTER:120:0:U",
|
|
"DS:net4_bytes_out:COUNTER:120:0:U",
|
|
"DS:net4_packs_in:COUNTER:120:0:U",
|
|
"DS:net4_packs_out:COUNTER:120:0:U",
|
|
"DS:net4_error_in:COUNTER:120:0:U",
|
|
"DS:net4_error_out:COUNTER:120:0:U",
|
|
"DS:net5_bytes_in:COUNTER:120:0:U",
|
|
"DS:net5_bytes_out:COUNTER:120:0:U",
|
|
"DS:net5_packs_in:COUNTER:120:0:U",
|
|
"DS:net5_packs_out:COUNTER:120:0:U",
|
|
"DS:net5_error_in:COUNTER:120:0:U",
|
|
"DS:net5_error_out:COUNTER:120:0:U",
|
|
"DS:net6_bytes_in:COUNTER:120:0:U",
|
|
"DS:net6_bytes_out:COUNTER:120:0:U",
|
|
"DS:net6_packs_in:COUNTER:120:0:U",
|
|
"DS:net6_packs_out:COUNTER:120:0:U",
|
|
"DS:net6_error_in:COUNTER:120:0:U",
|
|
"DS:net6_error_out:COUNTER:120:0:U",
|
|
"DS:net7_bytes_in:COUNTER:120:0:U",
|
|
"DS:net7_bytes_out:COUNTER:120:0:U",
|
|
"DS:net7_packs_in:COUNTER:120:0:U",
|
|
"DS:net7_packs_out:COUNTER:120:0:U",
|
|
"DS:net7_error_in:COUNTER:120:0:U",
|
|
"DS:net7_error_out:COUNTER:120:0:U",
|
|
"DS:net8_bytes_in:COUNTER:120:0:U",
|
|
"DS:net8_bytes_out:COUNTER:120:0:U",
|
|
"DS:net8_packs_in:COUNTER:120:0:U",
|
|
"DS:net8_packs_out:COUNTER:120:0:U",
|
|
"DS:net8_error_in:COUNTER:120:0:U",
|
|
"DS:net8_error_out:COUNTER:120:0:U",
|
|
"DS:net9_bytes_in:COUNTER:120:0:U",
|
|
"DS:net9_bytes_out:COUNTER:120:0:U",
|
|
"DS:net9_packs_in:COUNTER:120:0:U",
|
|
"DS:net9_packs_out:COUNTER:120:0:U",
|
|
"DS:net9_error_in:COUNTER:120:0:U",
|
|
"DS:net9_error_out:COUNTER:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $NET_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "net_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub net_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @net_bytes_in;
|
|
my @net_bytes_out;
|
|
my @net_packs_in;
|
|
my @net_packs_out;
|
|
my @net_error_in;
|
|
my @net_error_out;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
for($n = 0; $n < 10 ; $n++) {
|
|
$net_bytes_in[$n] = 0;
|
|
$net_bytes_out[$n] = 0;
|
|
$net_packs_in[$n] = 0;
|
|
$net_packs_out[$n] = 0;
|
|
$net_error_in[$n] = 0;
|
|
$net_error_out[$n] = 0;
|
|
if($n < scalar(@NET_LIST)) {
|
|
if($os eq "Linux") {
|
|
open(IN, "/proc/net/dev");
|
|
my $dev;
|
|
while(<IN>) {
|
|
($dev, $data) = split(':', $_);
|
|
$_ = $dev;
|
|
if(/$NET_LIST[$n]/) {
|
|
($net_bytes_in[$n], $net_packs_in[$n], $net_error_in[$n], undef, undef, undef, undef, undef, $net_bytes_out[$n], $net_packs_out[$n], $net_error_out[$n]) = split(' ', $data);
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "FreeBSD") {
|
|
open(IN, "netstat -nibd |");
|
|
while(<IN>) {
|
|
if(/Link/ && /$NET_LIST[$n]/) {
|
|
# Idrop column added in 8.0
|
|
if($kernel_branch > 7.2) {
|
|
(undef, undef, undef, undef, $net_packs_in[$n], $net_error_in[$n], undef, $net_bytes_in[$n], $net_packs_out[$n], $net_error_out[$n], $net_bytes_out[$n]) = split(' ', $_);
|
|
} else {
|
|
(undef, undef, undef, undef, $net_packs_in[$n], $net_error_in[$n], $net_bytes_in[$n], $net_packs_out[$n], $net_error_out[$n], $net_bytes_out[$n]) = split(' ', $_);
|
|
}
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "OpenBSD" || $os eq "NetBSD") {
|
|
open(IN, "netstat -nibd |");
|
|
while(<IN>) {
|
|
if(/Link/ && /^$NET_LIST[$n]/) {
|
|
(undef, undef, undef, undef, $net_bytes_in[$n], $net_bytes_out[$n]) = split(' ', $_);
|
|
$net_packs_in[$n] = 0;
|
|
$net_error_in[$n] = 0;
|
|
$net_packs_out[$n] = 0;
|
|
$net_error_out[$n] = 0;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
}
|
|
chomp($net_bytes_in[$n],
|
|
$net_bytes_out[$n],
|
|
$net_packs_in[$n],
|
|
$net_packs_out[$n],
|
|
$net_error_in[$n],
|
|
$net_error_out[$n]);
|
|
$rrdata .= ":$net_bytes_in[$n]:$net_bytes_out[$n]:$net_packs_in[$n]:$net_packs_out[$n]:$net_error_in[$n]:$net_error_out[$n]";
|
|
}
|
|
|
|
RRDs::update($NET_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $NET_RRD: $err") if $err;
|
|
}
|
|
|
|
# SERV graph
|
|
# ----------------------------------------------------------------------------
|
|
sub serv_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $SERV_RRD)) {
|
|
logger("Creating '$SERV_RRD' file.");
|
|
eval {
|
|
RRDs::create($SERV_RRD,
|
|
"--step=300",
|
|
"DS:serv_i_ssh:GAUGE:600:0:U",
|
|
"DS:serv_i_ftp:GAUGE:600:0:U",
|
|
"DS:serv_i_telnet:GAUGE:600:0:U",
|
|
"DS:serv_i_imap:GAUGE:600:0:U",
|
|
"DS:serv_i_smb:GAUGE:600:0:U",
|
|
"DS:serv_i_fax:GAUGE:600:0:U",
|
|
"DS:serv_i_cups:GAUGE:600:0:U",
|
|
"DS:serv_i_pop3:GAUGE:600:0:U",
|
|
"DS:serv_i_smtp:GAUGE:600:0:U",
|
|
"DS:serv_i_spam:GAUGE:600:0:U",
|
|
"DS:serv_i_virus:GAUGE:600:0:U",
|
|
"DS:serv_i_f2b:GAUGE:600:0:U",
|
|
"DS:serv_i_val02:GAUGE:600:0:U",
|
|
"DS:serv_i_val03:GAUGE:600:0:U",
|
|
"DS:serv_i_val04:GAUGE:600:0:U",
|
|
"DS:serv_i_val05:GAUGE:600:0:U",
|
|
"DS:serv_l_ssh:GAUGE:600:0:U",
|
|
"DS:serv_l_ftp:GAUGE:600:0:U",
|
|
"DS:serv_l_telnet:GAUGE:600:0:U",
|
|
"DS:serv_l_imap:GAUGE:600:0:U",
|
|
"DS:serv_l_smb:GAUGE:600:0:U",
|
|
"DS:serv_l_fax:GAUGE:600:0:U",
|
|
"DS:serv_l_cups:GAUGE:600:0:U",
|
|
"DS:serv_l_pop3:GAUGE:600:0:U",
|
|
"DS:serv_l_smtp:GAUGE:600:0:U",
|
|
"DS:serv_l_spam:GAUGE:600:0:U",
|
|
"DS:serv_l_virus:GAUGE:600:0:U",
|
|
"DS:serv_l_f2b:GAUGE:600:0:U",
|
|
"DS:serv_l_val02:GAUGE:600:0:U",
|
|
"DS:serv_l_val03:GAUGE:600:0:U",
|
|
"DS:serv_l_val04:GAUGE:600:0:U",
|
|
"DS:serv_l_val05:GAUGE:600:0:U",
|
|
"RRA:AVERAGE:0.5:1:288",
|
|
"RRA:AVERAGE:0.5:6:336",
|
|
"RRA:AVERAGE:0.5:12:744",
|
|
"RRA:AVERAGE:0.5:288:365",
|
|
"RRA:MIN:0.5:1:288",
|
|
"RRA:MIN:0.5:6:336",
|
|
"RRA:MIN:0.5:12:744",
|
|
"RRA:MIN:0.5:288:365",
|
|
"RRA:MAX:0.5:1:288",
|
|
"RRA:MAX:0.5:6:336",
|
|
"RRA:MAX:0.5:12:744",
|
|
"RRA:MAX:0.5:288:365",
|
|
"RRA:LAST:0.5:1:288",
|
|
"RRA:LAST:0.5:6:336",
|
|
"RRA:LAST:0.5:12:744",
|
|
"RRA:LAST:0.5:288:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $SERV_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Since 2.4.1 new values are used (val_01) to support 'fail2ban' hits.
|
|
# These new values need to be renamed.
|
|
RRDs::tune($SERV_RRD,
|
|
"--data-source-rename=serv_i_val01:serv_i_f2b",
|
|
"--data-source-rename=serv_l_val01:serv_l_f2b",
|
|
);
|
|
|
|
our %serv_hist = ();
|
|
push(@graphs, "serv_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub serv_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $ssh = 0;
|
|
my $ftp = 0;
|
|
my $telnet = 0;
|
|
my $imap = 0;
|
|
my $smb = 0;
|
|
my $fax = 0;
|
|
my $cups = 0;
|
|
my $pop3 = 0;
|
|
my $smtp = 0;
|
|
my $spam = 0;
|
|
my $virus = 0;
|
|
my $f2b = 0;
|
|
my $val02 = 0;
|
|
my $val03 = 0;
|
|
my $val04 = 0;
|
|
my $val05 = 0;
|
|
|
|
my $date;
|
|
my $rrdata = "N";
|
|
|
|
# This graph is refreshed only every 5 minutes
|
|
my (undef, $min) = localtime(time);
|
|
if($min % 5) {
|
|
return;
|
|
}
|
|
|
|
if(-r $SECURE_LOG) {
|
|
$date = strftime("%b %e", localtime);
|
|
open(IN, "$SECURE_LOG");
|
|
while(<IN>) {
|
|
if(/^$date/) {
|
|
if(/ sshd\[/ && /Accepted /) {
|
|
$ssh++;
|
|
}
|
|
if($os eq "Linux") {
|
|
if(/START: pop3/) {
|
|
$pop3++;
|
|
}
|
|
if(/START: ftp/ ||
|
|
(/ proftpd\[/ && /Login successful./)) {
|
|
$ftp++;
|
|
}
|
|
if(/START: telnet/) {
|
|
$telnet++;
|
|
}
|
|
} elsif($os eq "FreeBSD") {
|
|
|
|
if(/login:/ && /login from /) {
|
|
$telnet++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $IMAP_LOG) {
|
|
$IMAP_DATE_LOG_FORMAT = $IMAP_DATE_LOG_FORMAT || "%b %d";
|
|
$date_dovecot = strftime($IMAP_DATE_LOG_FORMAT, localtime);
|
|
$date_uw = strftime("%b %e %T", localtime);
|
|
open(IN, "$IMAP_LOG");
|
|
while(<IN>) {
|
|
# UW-IMAP log
|
|
if(/$date_uw/) {
|
|
if(/ imapd\[/ && / Login user=/) {
|
|
$imap++;
|
|
}
|
|
}
|
|
# Dovecot log
|
|
if(/$date_dovecot /) {
|
|
if(/ imap-login: / && / Login: /) {
|
|
$imap++;
|
|
}
|
|
if(/ pop3-login: / && / Login: /) {
|
|
$pop3++;
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
my $smb_L = 0;
|
|
open(IN, "smbstatus -L 2>/dev/null |");
|
|
while(<IN>) {
|
|
if(/^----------/) {
|
|
$smb_L++;
|
|
next;
|
|
}
|
|
if($smb_L) {
|
|
$smb_L++ unless !$_;
|
|
}
|
|
}
|
|
close(IN);
|
|
$smb_L--;
|
|
my $smb_S = 0;
|
|
open(IN, "smbstatus -S 2>/dev/null |");
|
|
while(<IN>) {
|
|
if(/^----------/) {
|
|
$smb_S++;
|
|
next;
|
|
}
|
|
if($smb_S) {
|
|
$smb_S++ unless !$_;
|
|
}
|
|
}
|
|
close(IN);
|
|
$smb_S--;
|
|
$smb = $smb_L + $smb_S;
|
|
|
|
if(-r $HYLAFAX_LOG) {
|
|
$date = strftime("%m/%d/%y", localtime);
|
|
open(IN, "$HYLAFAX_LOG");
|
|
while(<IN>) {
|
|
if(/^$date/ && /SEND/) {
|
|
$fax++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $CUPS_LOG) {
|
|
$date = strftime("%d/%b/%Y", localtime);
|
|
open(IN, "$CUPS_LOG");
|
|
while(<IN>) {
|
|
if(/\[$date:/) {
|
|
$cups++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $FAIL2BAN_LOG) {
|
|
$date = strftime("%Y-%m-%d", localtime);
|
|
open(IN, $FAIL2BAN_LOG);
|
|
while(<IN>) {
|
|
if(/^$date/ && / fail2ban/ && / WARNING / && / Ban /) {
|
|
$f2b++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $MAIL_LOG) {
|
|
$date = strftime("%b %e", localtime);
|
|
open(IN, "$MAIL_LOG");
|
|
while(<IN>) {
|
|
if(/^$date/) {
|
|
if(/to=/ && /stat(us)?=sent/i) {
|
|
$smtp++;
|
|
}
|
|
if(/MailScanner/ && /Spam Checks:/ && /Found/ && /spam messages/) {
|
|
$spam++;
|
|
}
|
|
if(/MailScanner/ && /Virus Scanning:/ && /Found/ && /viruses/) {
|
|
$virus++;
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
$date = strftime("%Y-%m-%d", localtime);
|
|
if(-r "$CG_LOGDIR/$date.log") {
|
|
open(IN, "$CG_LOGDIR/$date.log");
|
|
while(<IN>) {
|
|
if(/DEQUEUER \[\d+\] (LOCAL\(.+\) delivered|SMTP.+ relayed)\:/) {
|
|
$smtp++;
|
|
}
|
|
if(/IMAP/ && / connected from /) {
|
|
$imap++;
|
|
}
|
|
if(/POP/ && / connected from /) {
|
|
$pop3++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $SPAMASSASSIN_LOG) {
|
|
$date = strftime("%b %e", localtime);
|
|
open(IN, $SPAMASSASSIN_LOG);
|
|
while(<IN>) {
|
|
if(/^$date/ && /spamd: identified spam/) {
|
|
$spam++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $CLAMAV_LOG) {
|
|
$date = strftime("%a %b %e", localtime);
|
|
open(IN, $CLAMAV_LOG);
|
|
while(<IN>) {
|
|
if(/^$date/ && / FOUND/) {
|
|
$virus++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
# I data (incremental)
|
|
$rrdata .= ":$ssh:$ftp:$telnet:$imap:$smb:$fax:$cups:$pop3:$smtp:$spam:$virus:$f2b:$val02:$val03:$val04:$val05";
|
|
|
|
# L data (load)
|
|
my $l_ssh = 0;
|
|
my $l_ftp = 0;
|
|
my $l_telnet = 0;
|
|
my $l_imap = 0;
|
|
my $l_smb = 0;
|
|
my $l_fax = 0;
|
|
my $l_cups = 0;
|
|
my $l_pop3 = 0;
|
|
my $l_smtp = 0;
|
|
my $l_spam = 0;
|
|
my $l_virus = 0;
|
|
my $l_f2b = 0;
|
|
my $l_val02 = 0;
|
|
my $l_val03 = 0;
|
|
my $l_val04 = 0;
|
|
my $l_val05 = 0;
|
|
|
|
$l_ssh = $ssh - $serv_hist{'ssh'};
|
|
$l_ssh = 0 unless $l_ssh != $ssh;
|
|
$l_ssh /= 300;
|
|
$serv_hist{'ssh'} = $ssh;
|
|
|
|
$l_ftp = $ftp - $serv_hist{'ftp'};
|
|
$l_ftp = 0 unless $l_ftp != $ftp;
|
|
$l_ftp /= 300;
|
|
$serv_hist{'ftp'} = $ftp;
|
|
|
|
$l_telnet = $telnet - $serv_hist{'telnet'};
|
|
$l_telnet = 0 unless $l_telnet != $telnet;
|
|
$l_telnet /= 300;
|
|
$serv_hist{'telnet'} = $telnet;
|
|
|
|
$l_imap = $imap - $serv_hist{'imap'};
|
|
$l_imap = 0 unless $l_imap != $imap;
|
|
$l_imap /= 300;
|
|
$serv_hist{'imap'} = $imap;
|
|
|
|
$l_smb = $smb - $serv_hist{'smb'};
|
|
$l_smb = 0 unless $l_smb != $smb;
|
|
$l_smb /= 300;
|
|
$serv_hist{'smb'} = $smb;
|
|
|
|
$l_fax = $fax - $serv_hist{'fax'};
|
|
$l_fax = 0 unless $l_fax != $fax;
|
|
$l_fax /= 300;
|
|
$serv_hist{'fax'} = $fax;
|
|
|
|
$l_cups = $cups - $serv_hist{'cups'};
|
|
$l_cups = 0 unless $l_cups != $cups;
|
|
$l_cups /= 300;
|
|
$serv_hist{'cups'} = $cups;
|
|
|
|
$l_pop3 = $pop3 - $serv_hist{'pop3'};
|
|
$l_pop3 = 0 unless $l_pop3 != $pop3;
|
|
$l_pop3 /= 300;
|
|
$serv_hist{'pop3'} = $pop3;
|
|
|
|
$l_smtp = $smtp - $serv_hist{'smtp'};
|
|
$l_smtp = 0 unless $l_smtp != $smtp;
|
|
$l_smtp /= 300;
|
|
$serv_hist{'smtp'} = $smtp;
|
|
|
|
$l_spam = $spam - $serv_hist{'spam'};
|
|
$l_spam = 0 unless $l_spam != $spam;
|
|
$l_spam /= 300;
|
|
$serv_hist{'spam'} = $spam;
|
|
|
|
$l_virus = $virus - $serv_hist{'virus'};
|
|
$l_virus = 0 unless $l_virus != $virus;
|
|
$l_virus /= 300;
|
|
$serv_hist{'virus'} = $virus;
|
|
|
|
$l_f2b = $f2b - $serv_hist{'f2b'};
|
|
$l_f2b = 0 unless $l_f2b != $f2b;
|
|
$l_f2b /= 300;
|
|
$serv_hist{'f2b'} = $f2b;
|
|
|
|
$l_val02 = $val02 - $serv_hist{'val02'};
|
|
$l_val02 = 0 unless $l_val02 != $val02;
|
|
$l_val02 /= 300;
|
|
$serv_hist{'val02'} = $val02;
|
|
|
|
$l_val03 = $val03 - $serv_hist{'val03'};
|
|
$l_val03 = 0 unless $l_val03 != $val03;
|
|
$l_val03 /= 300;
|
|
$serv_hist{'val03'} = $val03;
|
|
|
|
$l_val04 = $val04 - $serv_hist{'val04'};
|
|
$l_val04 = 0 unless $l_val04 != $val04;
|
|
$l_val04 /= 300;
|
|
$serv_hist{'val04'} = $val04;
|
|
|
|
$l_val05 = $val05 - $serv_hist{'val05'};
|
|
$l_val05 = 0 unless $l_val05 != $val05;
|
|
$l_val05 /= 300;
|
|
$serv_hist{'val05'} = $val05;
|
|
|
|
$rrdata .= ":$l_ssh:$l_ftp:$l_telnet:$l_imap:$l_smb:$l_fax:$l_cups:$l_pop3:$l_smtp:$l_spam:$l_virus:$l_f2b:$l_val02:$l_val03:$l_val04:$l_val05";
|
|
RRDs::update($SERV_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $SERV_RRD: $err") if $err;
|
|
}
|
|
|
|
# MAIL graph
|
|
# ----------------------------------------------------------------------------
|
|
sub mail_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $MAIL_RRD)) {
|
|
logger("Creating '$MAIL_RRD' file.");
|
|
eval {
|
|
RRDs::create($MAIL_RRD,
|
|
"--step=60",
|
|
"DS:mail_in:GAUGE:120:0:U",
|
|
"DS:mail_out:GAUGE:120:0:U",
|
|
"DS:mail_recvd:GAUGE:120:0:U",
|
|
"DS:mail_delvd:GAUGE:120:0:U",
|
|
"DS:mail_bytes_recvd:GAUGE:120:0:U",
|
|
"DS:mail_bytes_delvd:GAUGE:120:0:U",
|
|
"DS:mail_rejtd:GAUGE:120:0:U",
|
|
"DS:mail_spam:GAUGE:120:0:U",
|
|
"DS:mail_virus:GAUGE:120:0:U",
|
|
"DS:mail_bouncd:GAUGE:120:0:U",
|
|
"DS:mail_queued:GAUGE:120:0:U",
|
|
"DS:mail_discrd:GAUGE:120:0:U",
|
|
"DS:mail_held:GAUGE:120:0:U",
|
|
"DS:mail_forwrd:GAUGE:120:0:U",
|
|
"DS:mail_queues:GAUGE:120:0:U",
|
|
"DS:mail_val01:COUNTER:120:0:U",
|
|
"DS:mail_val02:COUNTER:120:0:U",
|
|
"DS:mail_val03:COUNTER:120:0:U",
|
|
"DS:mail_val04:COUNTER:120:0:U",
|
|
"DS:mail_val05:COUNTER:120:0:U",
|
|
"DS:mail_val06:GAUGE:120:0:U",
|
|
"DS:mail_val07:GAUGE:120:0:U",
|
|
"DS:mail_val08:GAUGE:120:0:U",
|
|
"DS:mail_val09:GAUGE:120:0:U",
|
|
"DS:mail_val10:GAUGE:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $MAIL_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Since 2.5.0 there is support for more message status.
|
|
# Some values need to be renamed.
|
|
RRDs::tune($MAIL_RRD,
|
|
"--data-source-rename=mail_mta_val10:mail_bouncd",
|
|
"--data-source-rename=mail_mta_val12:mail_discrd",
|
|
"--data-source-rename=mail_mta_val13:mail_held",
|
|
"--data-source-rename=mail_mta_val14:mail_forwrd",
|
|
"--data-source-rename=mail_mta_val15:mail_queues",
|
|
);
|
|
|
|
our $mail_hist = 0;
|
|
push(@graphs, "mail_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub mail_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $in_conn;
|
|
my $out_conn;
|
|
my $recvd;
|
|
my $delvd;
|
|
my $bytes_recvd;
|
|
my $bytes_delvd;
|
|
my $rejected;
|
|
my $queued;
|
|
my $spam;
|
|
my $virus;
|
|
my $gl_records;
|
|
my $gl_greylisted;
|
|
my $gl_whitelisted;
|
|
my @mta_h = (0) x 15;
|
|
my @mta = (0) x 15;
|
|
my @gen = (0) x 10;
|
|
|
|
my $n;
|
|
my $mail_log_seekpos;
|
|
my $mail_log_size;
|
|
my $sa_log_seekpos;
|
|
my $sa_log_size;
|
|
my $clamav_log_seekpos;
|
|
my $clamav_log_size;
|
|
my $rrdata = "N";
|
|
|
|
# Read last MAIL data from historic
|
|
($mail_log_seekpos, $sa_log_seekpos, $clamav_log_seekpos, @mta_h[0..15-1], @gen[0..10-1]) = split(';', $mail_hist);
|
|
$mail_log_seekpos = defined($mail_log_seekpos) ? int($mail_log_seekpos) : 0;
|
|
$sa_log_seekpos = defined($sa_log_seekpos) ? int($sa_log_seekpos) : 0;
|
|
$clamav_log_seekpos = defined($clamav_log_seekpos) ? int($clamav_log_seekpos) : 0;
|
|
|
|
$recvd = $delvd = $bytes_recvd = $bytes_delvd = 0;
|
|
$in_conn = $out_conn = $rejected = 0;
|
|
$bounced = $discarded = $held = $forwarded = 0;
|
|
$queued = $queues = 0;
|
|
if(lc($MAIL_MTA) eq "sendmail") {
|
|
if(open(IN, "mailstats -P |")) {
|
|
while(<IN>) {
|
|
if(/^ T\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
|
|
$recvd = $1;
|
|
$bytes_recvd = $2;
|
|
$delvd = $3;
|
|
$bytes_delvd = $4;
|
|
}
|
|
if(/^ C\s+(\d+)\s+(\d+)\s+(\d+)/) {
|
|
$in_conn = $1;
|
|
$out_conn = $2;
|
|
$rejected = $3;
|
|
}
|
|
}
|
|
close(IN);
|
|
$bytes_recvd *= 1024;
|
|
$bytes_delvd *= 1024;
|
|
}
|
|
if(open(IN, "mailq |")) {
|
|
while(<IN>) {
|
|
my ($tmp) = ($_ =~ m/^\w{14}[ *X-]\s*(\d{1,8}) /);
|
|
$queues += $tmp if $tmp;
|
|
if(/^\s+Total requests: (\d+)$/) {
|
|
$queued = $1;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
} elsif(lc($MAIL_MTA) eq "postfix") {
|
|
my @data;
|
|
|
|
for my $path (split /:/, $ENV{PATH}) {
|
|
if(-f "$path/pflogsumm" && -x _) {
|
|
open(IN, "pflogsumm -d today -h 0 -u 0 --smtpd_stats --no_bounce_detail --no_deferral_detail --no_reject_detail --no_no_msg_size --no_smtpd_warnings $MAIL_LOG 2>/dev/null |");
|
|
}
|
|
if(-f "$path/pflogsumm.pl" && -x _) {
|
|
open(IN, "pflogsumm.pl -d today -h 0 -u 0 --smtpd_stats --no_bounce_detail --no_deferral_detail --no_reject_detail --no_no_msg_size --no_smtpd_warnings $MAIL_LOG 2>/dev/null |");
|
|
}
|
|
}
|
|
@data = <IN>;
|
|
close(IN);
|
|
foreach(@data) {
|
|
if(/^\s*(\d{1,7})([ km])\s*received$/) {
|
|
$recvd = $1;
|
|
$recvd = $1 * 1024 if $2 eq "k";
|
|
$recvd = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*delivered$/) {
|
|
$delvd = $1;
|
|
$delvd = $1 * 1024 if $2 eq "k";
|
|
$delvd = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*forwarded$/) {
|
|
$forwarded = $1;
|
|
$forwarded = $1 * 1024 if $2 eq "k";
|
|
$forwarded = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*bounced$/) {
|
|
$bounced = $1;
|
|
$bounced = $1 * 1024 if $2 eq "k";
|
|
$bounced = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*rejected \(/) {
|
|
$rejected = $1;
|
|
$rejected = $1 * 1024 if $2 eq "k";
|
|
$rejected = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*held/) {
|
|
$held = $1;
|
|
$held = $1 * 1024 if $2 eq "k";
|
|
$held = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*discarded \(/) {
|
|
$discarded = $1;
|
|
$discarded = $1 * 1024 if $2 eq "k";
|
|
$discarded = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*bytes received$/) {
|
|
$bytes_recvd = $1;
|
|
$bytes_recvd = $1 * 1024 if $2 eq "k";
|
|
$bytes_recvd = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
if(/^\s*(\d{1,7})([ km])\s*bytes delivered$/) {
|
|
$bytes_delvd = $1;
|
|
$bytes_delvd = $1 * 1024 if $2 eq "k";
|
|
$bytes_delvd = $1 * 1024 * 1024 if $2 eq "m";
|
|
}
|
|
}
|
|
if(open(IN, "mailq |")) {
|
|
while(<IN>) {
|
|
if(/^-- (\d+) Kbytes in (\d+) Request/) {
|
|
$queues = $1;
|
|
$queued = $2;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
}
|
|
|
|
$gl_records = $gl_greylisted = $gl_whitelisted = 0;
|
|
if(lc($MAIL_GREYLIST) eq "milter-greylist") {
|
|
if(-r $MILTER_GL) {
|
|
open(IN, $MILTER_GL);
|
|
if(!seek(IN, -80, 2)) {
|
|
logger("Couldn't seek to the end ($MILTER_GL): $!");
|
|
return;
|
|
}
|
|
while(<IN>) {
|
|
if(/^# Summary:\s+(\d+) records,\s+(\d+) greylisted,\s+(\d+) whitelisted$/) {
|
|
$gl_records = $1;
|
|
$gl_greylisted = $2;
|
|
$gl_whitelisted = $3;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
}
|
|
|
|
$spam = $virus = 0;
|
|
if(-r $MAIL_LOG) {
|
|
open(IN, $MAIL_LOG);
|
|
if(!seek(IN, 0, 2)) {
|
|
logger("Couldn't seek to the end ($MAIL_LOG): $!");
|
|
return;
|
|
}
|
|
$mail_log_size = tell(IN);
|
|
if($mail_log_size < $mail_log_seekpos) {
|
|
$mail_log_seekpos = 0;
|
|
}
|
|
if(!seek(IN, $mail_log_seekpos, 0)) {
|
|
logger("Couldn't seek to $mail_log_seekpos ($MAIL_LOG): $!");
|
|
return;
|
|
}
|
|
while(<IN>) {
|
|
my @line;
|
|
if(/MailScanner/ && /Spam Checks:/ && /Found/ && /spam messages/) {
|
|
@line = split(' ', $_);
|
|
$spam += int($line[8]);
|
|
}
|
|
if(/MailScanner/ && /Virus Scanning:/ && /Found/ && /viruses/) {
|
|
@line = split(' ', $_);
|
|
$virus += int($line[8]);
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $SPAMASSASSIN_LOG) {
|
|
$date = strftime("%b %e", localtime);
|
|
open(IN, $SPAMASSASSIN_LOG);
|
|
if(!seek(IN, 0, 2)) {
|
|
logger("Couldn't seek to the end ($SPAMASSASSIN_LOG): $!");
|
|
return;
|
|
}
|
|
$sa_log_size = tell(IN);
|
|
if($sa_log_size < $sa_log_seekpos) {
|
|
$sa_log_seekpos = 0;
|
|
}
|
|
if(!seek(IN, $sa_log_seekpos, 0)) {
|
|
logger("Couldn't seek to $sa_log_seekpos ($SPAMASSASSIN_LOG): $!");
|
|
return;
|
|
}
|
|
while(<IN>) {
|
|
if(/^$date/ && /spamd: identified spam/) {
|
|
$spam++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
if(-r $CLAMAV_LOG) {
|
|
$date = strftime("%a %b %e", localtime);
|
|
open(IN, $CLAMAV_LOG);
|
|
if(!seek(IN, 0, 2)) {
|
|
logger("Couldn't seek to the end ($CLAMAV_LOG): $!");
|
|
return;
|
|
}
|
|
$clamav_log_size = tell(IN);
|
|
if($clamav_log_size < $clamav_log_seekpos) {
|
|
$clamav_log_seekpos = 0;
|
|
}
|
|
if(!seek(IN, $clamav_log_seekpos, 0)) {
|
|
logger("Couldn't seek to $clamav_log_seekpos ($CLAMAV_LOG): $!");
|
|
return;
|
|
}
|
|
while(<IN>) {
|
|
if(/^$date/ && / FOUND/) {
|
|
$virus++;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
$mta[0] = int($in_conn) - $mta_h[0];
|
|
$mta[0] = 0 unless $mta[0] != int($in_conn);
|
|
$mta[0] /= 60;
|
|
$mta_h[0] = int($in_conn);
|
|
|
|
$mta[1] = int($out_conn) - $mta_h[1];
|
|
$mta[1] = 0 unless $mta[1] != int($out_conn);
|
|
$mta[1] /= 60;
|
|
$mta_h[1] = int($out_conn);
|
|
|
|
$mta[2] = int($recvd) - $mta_h[2];
|
|
$mta[2] = 0 unless $mta[2] != int($recvd);
|
|
$mta[2] /= 60;
|
|
$mta_h[2] = int($recvd);
|
|
|
|
$mta[3] = int($delvd) - $mta_h[3];
|
|
$mta[3] = 0 unless $mta[3] != int($delvd);
|
|
$mta[3] /= 60;
|
|
$mta_h[3] = int($delvd);
|
|
|
|
$mta[4] = int($bytes_recvd) - $mta_h[4];
|
|
$mta[4] = 0 unless $mta[4] != int($bytes_recvd);
|
|
$mta[4] /= 60;
|
|
$mta_h[4] = int($bytes_recvd);
|
|
|
|
$mta[5] = int($bytes_delvd) - $mta_h[5];
|
|
$mta[5] = 0 unless $mta[5] != int($bytes_delvd);
|
|
$mta[5] /= 60;
|
|
$mta_h[5] = int($bytes_delvd);
|
|
|
|
$mta[6] = int($rejected) - $mta_h[6];
|
|
$mta[6] = 0 unless $mta[6] != int($rejected);
|
|
$mta[6] /= 60;
|
|
$mta_h[6] = int($rejected);
|
|
|
|
# avoid initial spike
|
|
$mta[7] = int($spam) unless !$mta_h[7];
|
|
$mta_h[7] = int($spam) unless $mta_h[7];
|
|
$mta[7] /= 60;
|
|
|
|
# avoid initial spike
|
|
$mta[8] = int($virus) unless !$mta_h[8];
|
|
$mta_h[8] = int($virus) unless $mta_h[8];
|
|
$mta[8] /= 60;
|
|
|
|
$mta[9] = int($bouncd) - $mta_h[9];
|
|
$mta[9] = 0 unless $mta[9] != int($bouncd);
|
|
$mta[9] /= 60;
|
|
$mta_h[9] = int($bouncd);
|
|
|
|
$mta[10] = int($queued);
|
|
|
|
$mta[11] = int($discrd) - $mta_h[11];
|
|
$mta[11] = 0 unless $mta[11] != int($discrd);
|
|
$mta[11] /= 60;
|
|
$mta_h[11] = int($discrd);
|
|
|
|
$mta[12] = int($held) - $mta_h[12];
|
|
$mta[12] = 0 unless $mta[12] != int($held);
|
|
$mta[12] /= 60;
|
|
$mta_h[12] = int($held);
|
|
|
|
$mta[13] = int($forwrd) - $mta_h[13];
|
|
$mta[13] = 0 unless $mta[13] != int($forwrd);
|
|
$mta[13] /= 60;
|
|
$mta_h[13] = int($forwrd);
|
|
|
|
$mta[14] = int($queues);
|
|
|
|
$gen[6] = int($gl_records);
|
|
$gen[7] = int($gl_greylisted);
|
|
$gen[8] = int($gl_whitelisted);
|
|
|
|
$mail_hist = join(";", $mail_log_size, $sa_log_size, $clamav_log_size, @mta_h, @gen);
|
|
for($n = 0; $n < 15; $n++) {
|
|
$rrdata .= ":" . $mta[$n];
|
|
}
|
|
for($n = 0; $n < 10; $n++) {
|
|
$rrdata .= ":" . $gen[$n];
|
|
}
|
|
|
|
RRDs::update($MAIL_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $MAIL_RRD: $err") if $err;
|
|
}
|
|
|
|
# PORT graph
|
|
# ----------------------------------------------------------------------------
|
|
sub port_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my @data;
|
|
my $n;
|
|
my $p;
|
|
|
|
if(-e $PORT_RRD) {
|
|
$info = RRDs::info($PORT_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 2 != $PORT_MAX) {
|
|
logger("Detected size mismatch between \$PORT_MAX ($PORT_MAX) and $PORT_RRD (" . scalar(@ds) / 2 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($PORT_RRD, "$PORT_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $PORT_RRD)) {
|
|
logger("Creating '$PORT_RRD' file.");
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
push(@tmp, "DS:port" . $n . "_in:GAUGE:120:0:U");
|
|
push(@tmp, "DS:port" . $n . "_out:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($PORT_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $PORT_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if($os eq "Linux") {
|
|
my $num;
|
|
my @line;
|
|
|
|
# set the iptables rules for each defined port
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
if($PORT_LIST[$n]) {
|
|
$p = lc($PORT_PROT[$n]);
|
|
$p = "all" unless $PORT_PROT[$n];
|
|
system("iptables -N MONITORIX_IN_$n 2>/dev/null");
|
|
system("iptables -I INPUT -p $p --dport $PORT_LIST[$n] -j MONITORIX_IN_$n -c 0 0");
|
|
system("iptables -N MONITORIX_OUT_$n 2>/dev/null");
|
|
system("iptables -I OUTPUT -p $p --sport $PORT_LIST[$n] -j MONITORIX_OUT_$n -c 0 0");
|
|
}
|
|
}
|
|
}
|
|
if($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
# set the ipfw rules for each defined port
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
if($PORT_LIST[$n]) {
|
|
$p = lc($PORT_PROT[$n]);
|
|
$p = "ip" unless $PORT_PROT[$n];
|
|
system("ipfw -q add $PORT_RULE count $p from me $PORT_LIST[$n] to any");
|
|
system("ipfw -q add $PORT_RULE count $p from any to me $PORT_LIST[$n]");
|
|
}
|
|
}
|
|
}
|
|
|
|
# Since 2.5.2 port values need to be converted to GAUGE.
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
RRDs::tune($PORT_RRD,
|
|
"--data-source-type=port" . $n . "_in:GAUGE",
|
|
"--data-source-type=port" . $n . "_out:GAUGE",
|
|
);
|
|
}
|
|
|
|
our @port_hist_in = ();
|
|
our @port_hist_out = ();
|
|
push(@graphs, "port_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub port_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @in;
|
|
my @out;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "iptables -nxvL INPUT |");
|
|
while(<IN>) {
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
$in[$n] = 0 unless $in[$n];
|
|
if(/ MONITORIX_IN_$n /) {
|
|
my (undef, $bytes) = split(' ', $_);
|
|
chomp($bytes);
|
|
$in[$n] = $bytes - $port_hist_in[$n];
|
|
$in[$n] = 0 unless $in[$n] != $bytes;
|
|
$port_hist_in[$n] = $bytes;
|
|
$in[$n] /= 60;
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
open(IN, "iptables -nxvL OUTPUT |");
|
|
while(<IN>) {
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
$out[$n] = 0 unless $out[$n];
|
|
if(/ MONITORIX_OUT_$n /) {
|
|
my (undef, $bytes) = split(' ', $_);
|
|
chomp($bytes);
|
|
$out[$n] = $bytes - $port_hist_out[$n];
|
|
$out[$n] = 0 unless $out[$n] != $bytes;
|
|
$port_hist_out[$n] = $bytes;
|
|
$out[$n] /= 60;
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
if($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
open(IN, "ipfw show $PORT_RULE 2>/dev/null |");
|
|
while(<IN>) {
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
$in[$n] = 0 unless $in[$n];
|
|
if(/ from any to me dst-port $PORT_LIST[$n]$/) {
|
|
my (undef, undef, $bytes) = split(' ', $_);
|
|
chomp($bytes);
|
|
$in[$n] = $bytes;
|
|
}
|
|
$out[$n] = 0 unless $out[$n];
|
|
if(/ from me $PORT_LIST[$n] to any$/) {
|
|
my (undef, undef, $bytes) = split(' ', $_);
|
|
chomp($bytes);
|
|
$out[$n] = $bytes;
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
for($n = 0; $n < $PORT_MAX; $n++) {
|
|
$rrdata .= ":$in[$n]:$out[$n]";
|
|
}
|
|
RRDs::update($PORT_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $PORT_RRD: $err") if $err;
|
|
}
|
|
|
|
# USER graph
|
|
# ----------------------------------------------------------------------------
|
|
sub user_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $USER_RRD)) {
|
|
logger("Creating '$USER_RRD' file.");
|
|
eval {
|
|
RRDs::create($USER_RRD,
|
|
"--step=60",
|
|
"DS:user_sys:GAUGE:120:0:U",
|
|
"DS:user_smb:GAUGE:120:0:U",
|
|
"DS:user_mac:GAUGE:120:0:U",
|
|
"DS:user_val1:GAUGE:120:0:U",
|
|
"DS:user_val2:GAUGE:120:0:U",
|
|
"DS:user_val3:GAUGE:120:0:U",
|
|
"DS:user_val4:GAUGE:120:0:U",
|
|
"DS:user_val5:GAUGE:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $USER_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "user_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub user_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $sys;
|
|
my $smb;
|
|
my $mac;
|
|
|
|
my @data;
|
|
my $rrdata = "N";
|
|
|
|
open(IN, "who -q |");
|
|
while(<IN>) {
|
|
if(/^#/) {
|
|
my @tmp = split('=', $_);
|
|
$sys = $tmp[scalar(@tmp) - 1];
|
|
chomp($sys);
|
|
$sys = int($sys);
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
|
|
$smb = 0;
|
|
open(IN, "smbstatus -b 2>/dev/null |");
|
|
while(<IN>) {
|
|
if(/^----------/) {
|
|
$smb++;
|
|
next;
|
|
}
|
|
if($smb) {
|
|
$smb++ unless !$_;
|
|
}
|
|
}
|
|
close(IN);
|
|
$smb--;
|
|
|
|
open(IN, "macusers 2>/dev/null |");
|
|
@data = <IN>;
|
|
close(IN);
|
|
$mac = scalar(@data) - 1;
|
|
$mac = 0 unless @data;
|
|
|
|
$rrdata .= ":$sys:$smb:$mac:0:0:0:0:0";
|
|
RRDs::update($USER_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $USER_RRD: $err") if $err;
|
|
}
|
|
|
|
# APACHE graph
|
|
# ----------------------------------------------------------------------------
|
|
sub apache_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
if(!defined(@APACHE_LIST)) {
|
|
logger("$myself: ERROR: missing or not defined APACHE_LIST option.");
|
|
return 0;
|
|
}
|
|
|
|
if(-e $APACHE_RRD) {
|
|
$info = RRDs::info($APACHE_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 5 != scalar(@APACHE_LIST)) {
|
|
logger("Detected size mismatch between \@APACHE_LIST (" . scalar(@APACHE_LIST) . ") and $APACHE_RRD (" . scalar(@ds) / 5 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($APACHE_RRD, "$APACHE_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $APACHE_RRD)) {
|
|
logger("Creating '$APACHE_RRD' file.");
|
|
for($n = 0; $n < scalar(@APACHE_LIST); $n++) {
|
|
push(@tmp, "DS:apache" . $n . "_acc:GAUGE:120:0:U");
|
|
push(@tmp, "DS:apache" . $n . "_kb:GAUGE:120:0:U");
|
|
push(@tmp, "DS:apache" . $n . "_cpu:GAUGE:120:0:U");
|
|
push(@tmp, "DS:apache" . $n . "_busy:GAUGE:120:0:U");
|
|
push(@tmp, "DS:apache" . $n . "_idle:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($APACHE_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $APACHE_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Since 2.5.0 first 5 values belong to the first Apache being monitored.
|
|
# These values need to be renamed.
|
|
RRDs::tune($APACHE_RRD,
|
|
"--data-source-rename=apache_acc:apache0_acc",
|
|
"--data-source-rename=apache_kb:apache0_kb",
|
|
"--data-source-rename=apache_cpu:apache0_cpu",
|
|
"--data-source-rename=apache_busy:apache0_busy",
|
|
"--data-source-rename=apache_idle:apache0_idle",
|
|
);
|
|
|
|
our %apache_hist = ();
|
|
push(@graphs, "apache_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub apache_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $acc;
|
|
my $kb;
|
|
my $cpu;
|
|
my $busy;
|
|
my $idle;
|
|
|
|
my $str;
|
|
my $rrdata = "N";
|
|
|
|
my $n = 0;
|
|
foreach(@APACHE_LIST) {
|
|
my $URL = $_ . "/server-status?auto";
|
|
my $ua = LWP::UserAgent->new(timeout => 30);
|
|
my $response = $ua->request(HTTP::Request->new('GET', $URL));
|
|
|
|
foreach(split('\n', $response->content)) {
|
|
if(/^Total Accesses:\s+(\d+)$/) {
|
|
$str = $n . "acc";
|
|
$acc = $1 - $apache_hist{$str};
|
|
$acc = 0 unless $acc != $1;
|
|
$acc /= 60;
|
|
$apache_hist{$str} = $1;
|
|
next;
|
|
}
|
|
if(/^Total kBytes:\s+(\d+)$/) {
|
|
$str = $n . "kb";
|
|
$kb = $1 - $apache_hist{$str};
|
|
$kb = 0 unless $kb != $1;
|
|
$apache_hist{$str} = $1;
|
|
next;
|
|
}
|
|
if(/^CPULoad:\s+(\d*\.\d+)$/) {
|
|
$cpu = abs($1);
|
|
next;
|
|
}
|
|
if(/^BusyWorkers:\s+(\d+)/ || /^BusyServers:\s+(\d+)/) {
|
|
$busy = int($1);
|
|
next;
|
|
}
|
|
if(/^IdleWorkers:\s+(\d+)/ || /^IdleServers:\s+(\d+)/) {
|
|
$idle = int($1);
|
|
last;
|
|
}
|
|
}
|
|
$rrdata .= ":$acc:$kb:$cpu:$busy:$idle";
|
|
$n++;
|
|
}
|
|
|
|
RRDs::update($APACHE_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $APACHE_RRD: $err") if $err;
|
|
}
|
|
|
|
# NGINX graph
|
|
# ----------------------------------------------------------------------------
|
|
sub nginx_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
|
|
if(!(-e $NGINX_RRD)) {
|
|
logger("Creating '$NGINX_RRD' file.");
|
|
eval {
|
|
RRDs::create($NGINX_RRD,
|
|
"--step=60",
|
|
"DS:nginx_requests:GAUGE:120:0:U",
|
|
"DS:nginx_total:GAUGE:120:0:U",
|
|
"DS:nginx_reading:GAUGE:120:0:U",
|
|
"DS:nginx_writing:GAUGE:120:0:U",
|
|
"DS:nginx_waiting:GAUGE:120:0:U",
|
|
"DS:nginx_bytes_in:GAUGE:120:0:U",
|
|
"DS:nginx_bytes_out:GAUGE:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $NGINX_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(!defined($NGINX_PORT)) {
|
|
logger("$myself: ERROR: undefined NGINX_PORT option.");
|
|
return 0;
|
|
}
|
|
|
|
if($os eq "Linux") {
|
|
system("iptables -N NGINX_IN 2>/dev/null");
|
|
system("iptables -I INPUT -p tcp --dport $NGINX_PORT -j NGINX_IN -c 0 0");
|
|
system("iptables -N NGINX_OUT 2>/dev/null");
|
|
system("iptables -I OUTPUT -p tcp --sport $NGINX_PORT -j NGINX_OUT -c 0 0");
|
|
}
|
|
if($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
system("ipfw delete $NGINX_RULE 2>/dev/null");
|
|
system("ipfw -q add $NGINX_RULE count tcp from me $NGINX_PORT to any");
|
|
system("ipfw -q add $NGINX_RULE count tcp from any to me $NGINX_PORT");
|
|
}
|
|
|
|
# Since 2.4.0 these two values need to be converted to GAUGE.
|
|
RRDs::tune($NGINX_RRD,
|
|
"--data-source-type=nginx_bytes_in:GAUGE",
|
|
"--data-source-type=nginx_bytes_out:GAUGE",
|
|
);
|
|
|
|
our %nginx_hist = ();
|
|
push(@graphs, "nginx_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub nginx_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $reqs;
|
|
my $tot;
|
|
my $reads;
|
|
my $writes;
|
|
my $waits;
|
|
my $in;
|
|
my $out;
|
|
my $val;
|
|
|
|
my $URL = "http://127.0.0.1:" . $NGINX_PORT . "/nginx_status";
|
|
my $ua = LWP::UserAgent->new(timeout => 30);
|
|
my $response = $ua->request(HTTP::Request->new('GET', $URL));
|
|
my $rrdata = "N";
|
|
|
|
foreach(split('\n', $response->content)) {
|
|
if(/^Active connections:\s+(\d+)\s*/) {
|
|
$tot = $1;
|
|
next;
|
|
}
|
|
if(/^\s+(\d+)\s+(\d+)\s+(\d+)\s*/) {
|
|
$reqs = $3 - $nginx_hist{'requests'};
|
|
$reqs = 0 unless $reqs != $3;
|
|
$nginx_hist{'requests'} = $3;
|
|
}
|
|
if(/^Reading:\s+(\d+).*Writing:\s+(\d+).*Waiting:\s+(\d+)\s*/) {
|
|
$reads = $1;
|
|
$writes = $2;
|
|
$waits = $3;
|
|
}
|
|
}
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "iptables -nxvL INPUT |");
|
|
while(<IN>) {
|
|
if(/ NGINX_IN /) {
|
|
(undef, $val) = split(' ', $_);
|
|
chomp($val);
|
|
$in = $val - $nginx_hist{'in'};
|
|
$in = 0 unless $in != $val;
|
|
$nginx_hist{'in'} = $val;
|
|
$in /= 60;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
open(IN, "iptables -nxvL OUTPUT |");
|
|
while(<IN>) {
|
|
if(/ NGINX_OUT /) {
|
|
(undef, $val) = split(' ', $_);
|
|
chomp($val);
|
|
$out = $val - $nginx_hist{'out'};
|
|
$out = 0 unless $out != $val;
|
|
$nginx_hist{'out'} = $val;
|
|
$out /= 60;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
if($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
open(IN, "ipfw show $NGINX_RULE 2>/dev/null |");
|
|
while(<IN>) {
|
|
if(/ from any to me dst-port $NGINX_PORT$/) {
|
|
(undef, undef, $val) = split(' ', $_);
|
|
chomp($val);
|
|
$in = $val - $nginx_hist{'in'};
|
|
$in = 0 unless $in != $val;
|
|
$nginx_hist{'in'} = $val;
|
|
$in /= 60;
|
|
}
|
|
if(/ from me $NGINX_PORT to any$/) {
|
|
(undef, undef, $val) = split(' ', $_);
|
|
chomp($val);
|
|
$out = $val - $nginx_hist{'out'};
|
|
$out = 0 unless $out != $val;
|
|
$nginx_hist{'out'} = $val;
|
|
$out /= 60;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
|
|
$rrdata .= ":$reqs:$tot:$reads:$writes:$waits:$in:$out";
|
|
RRDs::update($NGINX_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $NGINX_RRD: $err") if $err;
|
|
}
|
|
|
|
# LIGHTTPD graph
|
|
# ----------------------------------------------------------------------------
|
|
sub lighttpd_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
if(!defined(@LIGHTTPD_LIST)) {
|
|
logger("$myself: ERROR: missing or not defined LIGHTTPD_LIST option.");
|
|
return 0;
|
|
}
|
|
|
|
if(-e $LIGHTTPD_RRD) {
|
|
$info = RRDs::info($LIGHTTPD_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 9 != scalar(@LIGHTTPD_LIST)) {
|
|
logger("Detected size mismatch between \@LIGHTTPD_LIST (" . scalar(@LIGHTTPD_LIST) . ") and $LIGHTTPD_RRD (" . scalar(@ds) / 9 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($LIGHTTPD_RRD, "$LIGHTTPD_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $LIGHTTPD_RRD)) {
|
|
logger("Creating '$LIGHTTPD_RRD' file.");
|
|
for($n = 0; $n < scalar(@LIGHTTPD_LIST); $n++) {
|
|
push(@tmp, "DS:lighttpd" . $n . "_acc:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_kb:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_busy:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_idle:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_val01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_val02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_val03:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_val04:GAUGE:120:0:U");
|
|
push(@tmp, "DS:lighttpd" . $n . "_val05:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($LIGHTTPD_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $LIGHTTPD_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
our %lighttpd_hist = ();
|
|
push(@graphs, "lighttpd_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub lighttpd_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $acc;
|
|
my $kb;
|
|
my $busy;
|
|
my $idle;
|
|
|
|
my $str;
|
|
my $rrdata = "N";
|
|
|
|
my $n = 0;
|
|
foreach(@LIGHTTPD_LIST) {
|
|
my $URL = $_ . "/server-status?auto";
|
|
my $ua = LWP::UserAgent->new(timeout => 30);
|
|
my $response = $ua->request(HTTP::Request->new('GET', $URL));
|
|
|
|
foreach(split('\n', $response->content)) {
|
|
if(/^Total Accesses:\s+(\d+)$/) {
|
|
$str = $n . "acc";
|
|
$acc = $1 - $lighttpd_hist{$str};
|
|
$acc = 0 unless $acc != $1;
|
|
$acc /= 60;
|
|
$lighttpd_hist{$str} = $1;
|
|
next;
|
|
}
|
|
if(/^Total kBytes:\s+(\d+)$/) {
|
|
$str = $n . "kb";
|
|
$kb = $1 - $lighttpd_hist{$str};
|
|
$kb = 0 unless $kb != $1;
|
|
$lighttpd_hist{$str} = $1;
|
|
next;
|
|
}
|
|
if(/^BusyServers:\s+(\d+)/) {
|
|
$busy = int($1);
|
|
next;
|
|
}
|
|
if(/^IdleServers:\s+(\d+)/) {
|
|
$idle = int($1);
|
|
last;
|
|
}
|
|
}
|
|
$rrdata .= ":$acc:$kb:$busy:$idle:0:0:0:0:0";
|
|
$n++;
|
|
}
|
|
|
|
RRDs::update($LIGHTTPD_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $LIGHTTPD_RRD: $err") if $err;
|
|
}
|
|
|
|
# MYSQL graph
|
|
# ----------------------------------------------------------------------------
|
|
sub mysql_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $num;
|
|
my $n;
|
|
|
|
$MYSQL_CONN_TYPE = $MYSQL_CONN_TYPE || "Host";
|
|
if(lc($MYSQL_CONN_TYPE) eq "host") {
|
|
$num = scalar(@MYSQL_HOST_LIST);
|
|
if(!@MYSQL_HOST_LIST) {
|
|
logger("$myself: ERROR: invalid value or not defined MYSQL_HOST_LIST option.");
|
|
return 0;
|
|
}
|
|
if(!@MYSQL_PORT_LIST) {
|
|
logger("$myself: ERROR: invalid value or not defined MYSQL_PORT_LIST option.");
|
|
return 0;
|
|
}
|
|
if(!@MYSQL_USER_LIST) {
|
|
logger("$myself: ERROR: invalid value or not defined MYSQL_USER_LIST option.");
|
|
return 0;
|
|
}
|
|
if(!@MYSQL_PASS_LIST) {
|
|
logger("$myself: ERROR: invalid value or not defined MYSQL_PASS_LIST option.");
|
|
return 0;
|
|
}
|
|
} elsif(lc($MYSQL_CONN_TYPE) eq "socket") {
|
|
$num = scalar(@MYSQL_SOCK_LIST);
|
|
if(!@MYSQL_SOCK_LIST) {
|
|
logger("$myself: ERROR: invalid value or not defined MYSQL_SOCK_LIST option.");
|
|
return 0;
|
|
}
|
|
} else {
|
|
logger("$myself: ERROR: invalid value in MYSQL_CONN_TYPE option.");
|
|
return 0;
|
|
}
|
|
|
|
if(-e $MYSQL_RRD) {
|
|
$info = RRDs::info($MYSQL_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(lc($MYSQL_CONN_TYPE) eq "host") {
|
|
if(scalar(@ds) / 38 != scalar(@MYSQL_HOST_LIST)) {
|
|
logger("Detected size mismatch between \@MYSQL_HOST_LIST (" . scalar(@MYSQL_HOST_LIST) . ") and $MYSQL_RRD (" . scalar(@ds) / 38 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($MYSQL_RRD, "$MYSQL_RRD.bak");
|
|
}
|
|
}
|
|
if(lc($MYSQL_CONN_TYPE) eq "socket") {
|
|
if(scalar(@ds) / 38 != scalar(@MYSQL_SOCK_LIST)) {
|
|
logger("Detected size mismatch between \@MYSQL_SOCK_LIST (" . scalar(@MYSQL_SOCK_LIST) . ") and $MYSQL_RRD (" . scalar(@ds) / 38 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($MYSQL_RRD, "$MYSQL_RRD.bak");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!(-e $MYSQL_RRD)) {
|
|
logger("Creating '$MYSQL_RRD' file.");
|
|
for($n = 0; $n < $num; $n++) {
|
|
push(@tmp, "DS:mysql" . $n . "_queries:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_sq:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_tchr:GAUGE:120:0:100");
|
|
push(@tmp, "DS:mysql" . $n . "_qcu:GAUGE:120:0:100");
|
|
push(@tmp, "DS:mysql" . $n . "_ot:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_conns_u:GAUGE:120:0:100");
|
|
push(@tmp, "DS:mysql" . $n . "_conns:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_tlw:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_kbu:GAUGE:120:0:100");
|
|
push(@tmp, "DS:mysql" . $n . "_innbu:GAUGE:120:0:100");
|
|
push(@tmp, "DS:mysql" . $n . "_csel:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_ccom:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_cdel:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_cins:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_cinss:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_cupd:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_crep:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_creps:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_crol:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_acli:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_acon:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_brecv:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_bsent:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val03:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val04:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val05:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val10:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val11:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val12:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val13:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val14:GAUGE:120:0:U");
|
|
push(@tmp, "DS:mysql" . $n . "_val15:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($MYSQL_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $MYSQL_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Since 2.5.0 first NN values belong to the first MySQL being monitored.
|
|
# These values need to be renamed.
|
|
RRDs::tune($MYSQL_RRD,
|
|
"--data-source-rename=mysql_queries:mysql0_queries",
|
|
"--data-source-rename=mysql_slow_queries:mysql0_sq",
|
|
"--data-source-rename=mysql_tcache_hit_r:mysql0_tchr",
|
|
"--data-source-rename=mysql_qcache_usage:mysql0_qcu",
|
|
"--data-source-rename=mysql_opened_tbl:mysql0_ot",
|
|
"--data-source-rename=mysql_conns_u:mysql0_conns_u",
|
|
"--data-source-rename=mysql_conns:mysql0_conns",
|
|
"--data-source-rename=mysql_tlocks_w:mysql0_tlw",
|
|
"--data-source-rename=mysql_key_buf_u:mysql0_kbu",
|
|
"--data-source-rename=mysql_innodb_buf_u:mysql0_innbu",
|
|
"--data-source-rename=mysql_com_select:mysql0_csel",
|
|
"--data-source-rename=mysql_com_commit:mysql0_ccom",
|
|
"--data-source-rename=mysql_com_delete:mysql0_cdel",
|
|
"--data-source-rename=mysql_com_insert:mysql0_cins",
|
|
"--data-source-rename=mysql_com_insert_s:mysql0_cinss",
|
|
"--data-source-rename=mysql_com_update:mysql0_cupd",
|
|
"--data-source-rename=mysql_com_replace:mysql0_crep",
|
|
"--data-source-rename=mysql_com_replace_s:mysql0_creps",
|
|
"--data-source-rename=mysql_com_rollback:mysql0_crol",
|
|
"--data-source-rename=mysql_aborted_cli:mysql0_acli",
|
|
"--data-source-rename=mysql_aborted_conn:mysql0_acon",
|
|
"--data-source-rename=mysql_bytes_recv:mysql0_brecv",
|
|
"--data-source-rename=mysql_bytes_sent:mysql0_bsent",
|
|
"--data-source-rename=mysql_val01:mysql0_val01",
|
|
"--data-source-rename=mysql_val02:mysql0_val02",
|
|
"--data-source-rename=mysql_val03:mysql0_val03",
|
|
"--data-source-rename=mysql_val04:mysql0_val04",
|
|
"--data-source-rename=mysql_val05:mysql0_val05",
|
|
"--data-source-rename=mysql_val06:mysql0_val06",
|
|
"--data-source-rename=mysql_val07:mysql0_val07",
|
|
"--data-source-rename=mysql_val08:mysql0_val08",
|
|
"--data-source-rename=mysql_val09:mysql0_val09",
|
|
"--data-source-rename=mysql_val10:mysql0_val10",
|
|
"--data-source-rename=mysql_val11:mysql0_val11",
|
|
"--data-source-rename=mysql_val12:mysql0_val12",
|
|
"--data-source-rename=mysql_val13:mysql0_val13",
|
|
"--data-source-rename=mysql_val14:mysql0_val14",
|
|
"--data-source-rename=mysql_val15:mysql0_val15",
|
|
);
|
|
|
|
our %mysql_hist = ();
|
|
push(@graphs, "mysql_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub mysql_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $num;
|
|
my $str;
|
|
my $n = 0;
|
|
my $rrdata = "N";
|
|
|
|
my $print_error = 0;
|
|
if($opt_d eq "all" || $debug) {
|
|
$print_error = 1;
|
|
}
|
|
|
|
$MYSQL_CONN_TYPE = $MYSQL_CONN_TYPE || "Host";
|
|
if(lc($MYSQL_CONN_TYPE) eq "host") {
|
|
$num = scalar(@MYSQL_HOST_LIST);
|
|
}
|
|
if(lc($MYSQL_CONN_TYPE) eq "socket") {
|
|
$num = scalar(@MYSQL_SOCK_LIST);
|
|
}
|
|
|
|
for($n = 0; $n < $num; $n++) {
|
|
my $host = $MYSQL_HOST_LIST[$n];
|
|
my $port = $MYSQL_PORT_LIST[$n];
|
|
my $user = $MYSQL_USER_LIST[$n];
|
|
my $pass = $MYSQL_PASS_LIST[$n];
|
|
my $sock = $MYSQL_SOCK_LIST[$n];
|
|
my $dbh;
|
|
if(lc($MYSQL_CONN_TYPE) eq "host") {
|
|
unless ($host && $port && $user && $pass) {
|
|
logger("$myself: ERROR: undefined configuration.");
|
|
next;
|
|
}
|
|
$dbh = DBI->connect(
|
|
"DBI:mysql:host=$host;port=$port",
|
|
$user,
|
|
$pass,
|
|
{ PrintError => $print_error, }
|
|
) or logger("$myself: Cannot connect to MySQL '$host:$port'.") and next;
|
|
}
|
|
if(lc($MYSQL_CONN_TYPE) eq "socket") {
|
|
unless ($sock) {
|
|
logger("$myself: ERROR: undefined configuration.");
|
|
next;
|
|
}
|
|
$dbh = DBI->connect(
|
|
"DBI:mysql:mysql_socket=$sock",
|
|
{ PrintError => $print_error, }
|
|
) or logger("$myself: Cannot connect to MySQL '$sock'.") and next;
|
|
}
|
|
|
|
# SHOW STATUS
|
|
my $aborted_clients = 0;
|
|
my $aborted_connects = 0;
|
|
my $connections = 0;
|
|
my $connections_real = 0;
|
|
my $innodb_buffer_pool_pages_free = 0;
|
|
my $innodb_buffer_pool_pages_total = 0;
|
|
my $key_blocks_used = 0;
|
|
my $key_blocks_unused = 0;
|
|
my $max_used_connections = 0;
|
|
my $qcache_free_memory = 0;
|
|
my $qcache_hits = 0;
|
|
my $qcache_inserts = 0;
|
|
my $queries = 0;
|
|
my $opened_tables = 0;
|
|
my $slow_queries = 0;
|
|
my $table_locks_waited = 0;
|
|
my $threads_created = 0;
|
|
my $sql = "show status";
|
|
my $sth = $dbh->prepare($sql);
|
|
$sth->execute;
|
|
while((my $name, $value) = $sth->fetchrow_array) {
|
|
if($name eq "Aborted_clients") {
|
|
$str = $n . "aborted_clients";
|
|
$aborted_clients = $value - $mysql_hist{$str};
|
|
$aborted_clients = 0 unless $aborted_clients != $value;
|
|
$aborted_clients /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Aborted_connects") {
|
|
$str = $n . "aborted_connects";
|
|
$aborted_connects = $value - $mysql_hist{$str};
|
|
$aborted_connects = 0 unless $aborted_connects != $value;
|
|
$aborted_connects /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Connections") {
|
|
$str = $n . "connections";
|
|
$connections_real = int($value);
|
|
$connections = $value - $mysql_hist{$str};
|
|
$connections = 0 unless $connections != $value;
|
|
$connections /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Innodb_buffer_pool_pages_free") {
|
|
$innodb_buffer_pool_pages_free = int($value);
|
|
}
|
|
if($name eq "Innodb_buffer_pool_pages_total") {
|
|
$innodb_buffer_pool_pages_total = int($value);
|
|
}
|
|
if($name eq "Key_blocks_unused") {
|
|
$key_blocks_unused = int($value);
|
|
}
|
|
if($name eq "Key_blocks_used") {
|
|
$key_blocks_used = int($value);
|
|
}
|
|
if($name eq "Max_used_connections") {
|
|
$max_used_connections = int($value);
|
|
}
|
|
if($name eq "Opened_tables") {
|
|
$str = $n . "opened_tables";
|
|
$opened_tables = $value - $mysql_hist{$str};
|
|
$opened_tables = 0 unless $opened_tables != $value;
|
|
$opened_tables /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Qcache_free_memory") {
|
|
$qcache_free_memory = int($value);
|
|
}
|
|
if($name eq "Qcache_hits") {
|
|
$qcache_hits = int($value);
|
|
}
|
|
if($name eq "Qcache_inserts") {
|
|
$qcache_inserts = int($value);
|
|
}
|
|
if($name eq "Queries") {
|
|
$str = $n . "queries";
|
|
$queries = $value - $mysql_hist{$str};
|
|
$queries = 0 unless $queries != $value;
|
|
$queries /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Slow_queries") {
|
|
$str = $n . "slow_queries";
|
|
$slow_queries = $value - $mysql_hist{$str};
|
|
$slow_queries = 0 unless $slow_queries != $value;
|
|
$slow_queries /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Table_locks_waited") {
|
|
$str = $n . "table_locks_waited";
|
|
$table_locks_waited = $value - $mysql_hist{$str};
|
|
$table_locks_waited = 0 unless $table_locks_waited != $value;
|
|
$table_locks_waited /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Threads_created") {
|
|
$threads_created = int($value);
|
|
}
|
|
}
|
|
$sth->finish;
|
|
|
|
# SHOW GLOBAL STATUS
|
|
my $bytes_received = 0;
|
|
my $bytes_sent = 0;
|
|
my $com_commit = 0;
|
|
my $com_delete = 0;
|
|
my $com_insert = 0;
|
|
my $com_insert_s = 0;
|
|
my $com_replace = 0;
|
|
my $com_replace_s = 0;
|
|
my $com_rollback = 0;
|
|
my $com_select = 0;
|
|
my $com_update = 0;
|
|
my $sql = "show global status";
|
|
my $sth = $dbh->prepare($sql);
|
|
$sth->execute;
|
|
while((my $name, $value) = $sth->fetchrow_array) {
|
|
if($name eq "Bytes_received") {
|
|
$str = $n . "bytes_received";
|
|
$bytes_received = $value - $mysql_hist{$str};
|
|
$bytes_received = 0 unless $bytes_received != $value;
|
|
$bytes_received /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Bytes_sent") {
|
|
$str = $n . "bytes_sent";
|
|
$bytes_sent = $value - $mysql_hist{$str};
|
|
$bytes_sent = 0 unless $bytes_sent != $value;
|
|
$bytes_sent /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_commit") {
|
|
$str = $n . "com_commit";
|
|
$com_commit = $value - $mysql_hist{$str};
|
|
$com_commit = 0 unless $com_commit != $value;
|
|
$com_commit /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_delete") {
|
|
$str = $n . "com_delete";
|
|
$com_delete = $value - $mysql_hist{$str};
|
|
$com_delete = 0 unless $com_delete != $value;
|
|
$com_delete /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_insert") {
|
|
$str = $n . "com_insert";
|
|
$com_insert = $value - $mysql_hist{$str};
|
|
$com_insert = 0 unless $com_insert != $value;
|
|
$com_insert /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_insert_select") {
|
|
$str = $n . "com_insert_s";
|
|
$com_insert_s = $value - $mysql_hist{$str};
|
|
$com_insert_s = 0 unless $com_insert_s != $value;
|
|
$com_insert_s /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_replace") {
|
|
$str = $n . "com_replace";
|
|
$com_replace = $value - $mysql_hist{$str};
|
|
$com_replace = 0 unless $com_replace != $value;
|
|
$com_replace /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_replace_select") {
|
|
$str = $n . "com_replace_s";
|
|
$com_replace_s = $value - $mysql_hist{$str};
|
|
$com_replace_s = 0 unless $com_replace_s != $value;
|
|
$com_replace_s /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_rollback") {
|
|
$str = $n . "com_rollback";
|
|
$com_rollback = $value - $mysql_hist{$str};
|
|
$com_rollback = 0 unless $com_rollback != $value;
|
|
$com_rollback /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_select") {
|
|
$str = $n . "com_select";
|
|
$com_select = $value - $mysql_hist{$str};
|
|
$com_select = 0 unless $com_select != $value;
|
|
$com_select /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
if($name eq "Com_update") {
|
|
$str = $n . "com_update";
|
|
$com_update = $value - $mysql_hist{$str};
|
|
$com_update = 0 unless $com_update != $value;
|
|
$com_update /= 60;
|
|
$mysql_hist{$str} = $value;
|
|
}
|
|
}
|
|
$sth->finish;
|
|
|
|
# SHOW VARIABLES
|
|
my $query_cache_size = 0;
|
|
my $max_connections = 0;
|
|
my $sql = "show variables";
|
|
my $sth = $dbh->prepare($sql);
|
|
$sth->execute;
|
|
while((my $name, $value) = $sth->fetchrow_array) {
|
|
if($name eq "max_connections") {
|
|
$max_connections = int($value);
|
|
}
|
|
if($name eq "query_cache_size") {
|
|
$query_cache_size = int($value);
|
|
}
|
|
}
|
|
$sth->finish;
|
|
$dbh->disconnect;
|
|
|
|
my $tcache_hit_rate = 0;
|
|
my $qcache_usage = 0;
|
|
my $connections_usage = 0;
|
|
my $key_buffer_usage = 0;
|
|
my $innodb_buffer_pool_usage = 0;
|
|
|
|
$tcache_hit_rate = (1 - ($threads_created / $connections_real)) * 100
|
|
unless !$connections_real;
|
|
$qcache_usage = (1 - ($qcache_free_memory / $query_cache_size)) * 100
|
|
unless !$query_cache_size;
|
|
$connections_usage = ($max_used_connections / $max_connections) * 100
|
|
unless !$max_connections;
|
|
$key_buffer_usage = ($key_blocks_used / ($key_blocks_used + $key_blocks_unused)) * 100
|
|
unless !($key_blocks_used + $key_blocks_unused);
|
|
$innodb_buffer_pool_usage = (1 - ($innodb_buffer_pool_pages_free / $innodb_buffer_pool_pages_total)) * 100
|
|
unless !$innodb_buffer_pool_pages_total;
|
|
|
|
$connections_usage = $connections_usage > 100 ? 100 : $connections_usage;
|
|
|
|
$rrdata .= ":$queries:$slow_queries:$tcache_hit_rate:$qcache_usage:$opened_tables:$connections_usage:$connections:$table_locks_waited:$key_buffer_usage:$innodb_buffer_pool_usage:$com_select:$com_commit:$com_delete:$com_insert:$com_insert_s:$com_update:$com_replace:$com_replace_s:$com_rollback:$aborted_clients:$aborted_connects:$bytes_received:$bytes_sent:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0";
|
|
}
|
|
|
|
RRDs::update($MYSQL_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $MYSQL_RRD: $err") if $err;
|
|
}
|
|
|
|
# SQUID graph
|
|
# ----------------------------------------------------------------------------
|
|
sub squid_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $SQUID_RRD)) {
|
|
logger("Creating '$SQUID_RRD' file.");
|
|
eval {
|
|
RRDs::create($SQUID_RRD,
|
|
"--step=60",
|
|
"DS:squid_g1_1:GAUGE:120:0:U",
|
|
"DS:squid_g1_2:GAUGE:120:0:U",
|
|
"DS:squid_g1_3:GAUGE:120:0:U",
|
|
"DS:squid_g1_4:GAUGE:120:0:U",
|
|
"DS:squid_g1_5:GAUGE:120:0:U",
|
|
"DS:squid_g1_6:GAUGE:120:0:U",
|
|
"DS:squid_g1_7:GAUGE:120:0:U",
|
|
"DS:squid_g1_8:GAUGE:120:0:U",
|
|
"DS:squid_g1_9:GAUGE:120:0:U",
|
|
"DS:squid_g2_1:GAUGE:120:0:U",
|
|
"DS:squid_g2_2:GAUGE:120:0:U",
|
|
"DS:squid_g2_3:GAUGE:120:0:U",
|
|
"DS:squid_g2_4:GAUGE:120:0:U",
|
|
"DS:squid_g2_5:GAUGE:120:0:U",
|
|
"DS:squid_g2_6:GAUGE:120:0:U",
|
|
"DS:squid_g2_7:GAUGE:120:0:U",
|
|
"DS:squid_g2_8:GAUGE:120:0:U",
|
|
"DS:squid_g2_9:GAUGE:120:0:U",
|
|
"DS:squid_rq_1:GAUGE:120:0:U",
|
|
"DS:squid_rq_2:GAUGE:120:0:U",
|
|
"DS:squid_rq_3:GAUGE:120:0:U",
|
|
"DS:squid_rq_4:GAUGE:120:0:U",
|
|
"DS:squid_rq_5:GAUGE:120:0:U",
|
|
"DS:squid_rq_6:GAUGE:120:0:U",
|
|
"DS:squid_rq_7:GAUGE:120:0:U",
|
|
"DS:squid_rq_8:GAUGE:120:0:U",
|
|
"DS:squid_rq_9:GAUGE:120:0:U",
|
|
"DS:squid_m_1:GAUGE:120:0:U",
|
|
"DS:squid_m_2:GAUGE:120:0:U",
|
|
"DS:squid_m_3:GAUGE:120:0:U",
|
|
"DS:squid_m_4:GAUGE:120:0:U",
|
|
"DS:squid_m_5:GAUGE:120:0:U",
|
|
"DS:squid_ic_1:GAUGE:120:0:U",
|
|
"DS:squid_ic_2:GAUGE:120:0:U",
|
|
"DS:squid_ic_3:GAUGE:120:0:U",
|
|
"DS:squid_ic_4:GAUGE:120:0:U",
|
|
"DS:squid_ic_5:GAUGE:120:0:U",
|
|
"DS:squid_io_1:GAUGE:120:0:U",
|
|
"DS:squid_io_2:GAUGE:120:0:U",
|
|
"DS:squid_io_3:GAUGE:120:0:U",
|
|
"DS:squid_io_4:GAUGE:120:0:U",
|
|
"DS:squid_io_5:GAUGE:120:0:U",
|
|
"DS:squid_s_1:GAUGE:120:0:U",
|
|
"DS:squid_s_2:GAUGE:120:0:U",
|
|
"DS:squid_s_3:GAUGE:120:0:U",
|
|
"DS:squid_s_4:GAUGE:120:0:U",
|
|
"DS:squid_s_5:GAUGE:120:0:U",
|
|
"DS:squid_tc_1:GAUGE:120:0:U",
|
|
"DS:squid_tc_2:GAUGE:120:0:U",
|
|
"DS:squid_tc_3:GAUGE:120:0:U",
|
|
"DS:squid_ts_1:GAUGE:120:0:U",
|
|
"DS:squid_ts_2:GAUGE:120:0:U",
|
|
"DS:squid_ts_3:GAUGE:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $SQUID_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
our %squid_hist = ();
|
|
push(@graphs, "squid_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub squid_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my %g12 = ();
|
|
my $seek_pos;
|
|
my $logsize;
|
|
my @data;
|
|
my $all;
|
|
my $value;
|
|
my $g_result;
|
|
my $g_status;
|
|
|
|
my $rq_client_http_req;
|
|
my $rq_client_http_hit;
|
|
my $rq_server_http_req;
|
|
my $rq_server_ftp_req;
|
|
my $rq_server_other_req;
|
|
my $rq_aborted_req;
|
|
my $rq_swap_files_cleaned;
|
|
my $rq_unlink_requests;
|
|
|
|
my $tc_client_http_in;
|
|
my $tc_client_http_out;
|
|
my $ts_server_all_in;
|
|
my $ts_server_all_out;
|
|
|
|
my $m_alloc;
|
|
my $m_inuse;
|
|
|
|
my $ic_requests;
|
|
my $ic_hits;
|
|
my $ic_misses;
|
|
|
|
my $io_http;
|
|
my $io_ftp;
|
|
my $io_gopher;
|
|
my $io_wais;
|
|
|
|
my $s_entries;
|
|
my $s_maximum;
|
|
my $s_current;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
$seek_pos = $squid_hist{'seek_pos'};
|
|
$seek_pos = defined($seek_pos) ? int($seek_pos) : 0;
|
|
open(IN, $SQUID_LOG);
|
|
if(!seek(IN, 0, 2)) {
|
|
logger("Couldn't seek to the end ($SQUID_LOG): $!");
|
|
return;
|
|
}
|
|
$logsize = tell(IN);
|
|
if($logsize < $seek_pos) {
|
|
$seek_pos = 0;
|
|
}
|
|
if(!seek(IN, $seek_pos, 0)) {
|
|
logger("Couldn't seek to $seek_pos ($SQUID_LOG): $!");
|
|
return;
|
|
}
|
|
if(defined($squid_hist{'seek_pos'})) { # avoid initial spike
|
|
while(<IN>) {
|
|
(undef, undef, undef, $value) = split(' ', $_);
|
|
($g_result, $g_status) = split('/', $value);
|
|
$g12{$g_result}++;
|
|
$g12{$g_status}++;
|
|
}
|
|
}
|
|
close(IN);
|
|
foreach(@SQUID_GRAPH_1) {
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($g12{$_}) ? int($g12{$_}) : 0;
|
|
}
|
|
foreach(@SQUID_GRAPH_2) {
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($g12{$_}) ? int($g12{$_}) : 0;
|
|
}
|
|
$squid_hist{'seek_pos'} = $logsize;
|
|
|
|
open(IN, "$SQUID_CMD mgr:counters |");
|
|
while(<IN>) {
|
|
if(/^client_http\.requests = (\d+)$/) {
|
|
$rq_client_http_req = $1 - $squid_hist{'rq_client_http_req'};
|
|
$rq_client_http_req = 0 unless $rq_client_http_req != $1;
|
|
$rq_client_http_req /= 60;
|
|
$squid_hist{'rq_client_http_req'} = $1;
|
|
next;
|
|
}
|
|
if(/^client_http\.hits = (\d+)$/) {
|
|
$rq_client_http_hit = $1 - $squid_hist{'rq_client_http_hit'};
|
|
$rq_client_http_hit = 0 unless $rq_client_http_hit != $1;
|
|
$rq_client_http_hit /= 60;
|
|
$squid_hist{'rq_client_http_hit'} = $1;
|
|
next;
|
|
}
|
|
if(/^client_http\.kbytes_in = (\d+)$/) {
|
|
$tc_client_http_in = $1 - $squid_hist{'tc_client_http_in'};
|
|
$tc_client_http_in = 0 unless $tc_client_http_in != $1;
|
|
$tc_client_http_in *= 1024;
|
|
$tc_client_http_in /= 60;
|
|
$squid_hist{'tc_client_http_in'} = $1;
|
|
next;
|
|
}
|
|
if(/^client_http\.kbytes_out = (\d+)$/) {
|
|
$tc_client_http_out = $1 - $squid_hist{'tc_client_http_out'};
|
|
$tc_client_http_out = 0 unless $tc_client_http_out != $1;
|
|
$tc_client_http_out *= 1024;
|
|
$tc_client_http_out /= 60;
|
|
$squid_hist{'tc_client_http_out'} = $1;
|
|
next;
|
|
}
|
|
if(/^server\.all\.kbytes_in = (\d+)$/) {
|
|
$ts_server_all_in = $1 - $squid_hist{'ts_server_all_in'};
|
|
$ts_server_all_in = 0 unless $ts_server_all_in != $1;
|
|
$ts_server_all_in *= 1024;
|
|
$ts_server_all_in /= 60;
|
|
$squid_hist{'ts_server_all_in'} = $1;
|
|
next;
|
|
}
|
|
if(/^server\.all\.kbytes_out = (\d+)$/) {
|
|
$ts_server_all_out = $1 - $squid_hist{'ts_server_all_out'};
|
|
$ts_server_all_out = 0 unless $ts_server_all_out != $1;
|
|
$ts_server_all_out *= 1024;
|
|
$ts_server_all_out /= 60;
|
|
$squid_hist{'ts_server_all_out'} = $1;
|
|
next;
|
|
}
|
|
if(/^server\.http\.requests = (\d+)$/) {
|
|
$rq_server_http_req = $1 - $squid_hist{'rq_server_http_req'};
|
|
$rq_server_http_req = 0 unless $rq_server_http_req != $1;
|
|
$rq_server_http_req /= 60;
|
|
$squid_hist{'rq_server_http_req'} = $1;
|
|
next;
|
|
}
|
|
if(/^server\.ftp\.requests = (\d+)$/) {
|
|
$rq_server_ftp_req = $1 - $squid_hist{'rq_server_ftp_req'};
|
|
$rq_server_ftp_req = 0 unless $rq_server_ftp_req != $1;
|
|
$rq_server_ftp_req /= 60;
|
|
$squid_hist{'rq_server_ftp_req'} = $1;
|
|
next;
|
|
}
|
|
if(/^server\.other\.requests = (\d+)$/) {
|
|
$rq_server_other_req = $1 - $squid_hist{'rq_server_other_req'};
|
|
$rq_server_other_req = 0 unless $rq_server_other_req != $1;
|
|
$rq_server_other_req /= 60;
|
|
$squid_hist{'rq_server_other_req'} = $1;
|
|
next;
|
|
}
|
|
if(/^unlink\.requests = (\d+)$/) {
|
|
$rq_unlink_requests = $1 - $squid_hist{'rq_unlink_requests'};
|
|
$rq_unlink_requests = 0 unless $rq_unlink_requests != $1;
|
|
$rq_unlink_requests /= 60;
|
|
$squid_hist{'rq_unlink_requests'} = $1;
|
|
next;
|
|
}
|
|
if(/^swap\.files_cleaned = (\d+)$/) {
|
|
$rq_swap_files_cleaned = $1 - $squid_hist{'rq_swap_files_cleaned'};
|
|
$rq_swap_files_cleaned = 0 unless $rq_swap_files_cleaned != $1;
|
|
$rq_swap_files_cleaned /= 60;
|
|
$squid_hist{'rq_swap_files_cleaned'} = $1;
|
|
next;
|
|
}
|
|
if(/^aborted_requests = (\d+)$/) {
|
|
$rq_aborted_req = $1 - $squid_hist{'rq_aborted_req'};
|
|
$rq_aborted_req = 0 unless $rq_aborted_req != $1;
|
|
$rq_aborted_req /= 60;
|
|
$squid_hist{'rq_aborted_req'} = $1;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
$rrdata .= ":$rq_client_http_req:$rq_client_http_hit:$rq_server_http_req:$rq_server_ftp_req:$rq_server_other_req:$rq_aborted_req:$rq_swap_files_cleaned:$rq_unlink_requests:0";
|
|
|
|
open(IN, "$SQUID_CMD mgr:mem |");
|
|
while(<IN>) {
|
|
if(/^Total /) {
|
|
(undef, undef, $m_alloc, undef, undef, undef, undef, $m_inuse) = split(' ', $_);
|
|
chomp($m_alloc);
|
|
chomp($m_inuse);
|
|
$m_alloc;
|
|
$m_inuse;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
$rrdata .= ":$m_alloc:$m_inuse:0:0:0";
|
|
|
|
open(IN, "$SQUID_CMD mgr:ipcache |");
|
|
while(<IN>) {
|
|
if(/^IPcache Requests:\s+(\d+)$/) {
|
|
$ic_requests = $1 - $squid_hist{'ic_requests'};
|
|
$ic_requests = 0 unless $ic_requests != $1;
|
|
$ic_requests /= 60;
|
|
$squid_hist{'ic_requests'} = $1;
|
|
next;
|
|
}
|
|
if(/^IPcache Hits:\s+(\d+)$/) {
|
|
$ic_hits = $1 - $squid_hist{'ic_hits'};
|
|
$ic_hits = 0 unless $ic_hits != $1;
|
|
$ic_hits /= 60;
|
|
$squid_hist{'ic_hits'} = $1;
|
|
next;
|
|
}
|
|
if(/^IPcache Misses:\s+(\d+)$/) {
|
|
$ic_misses = $1 - $squid_hist{'ic_misses'};
|
|
$ic_misses = 0 unless $ic_misses != $1;
|
|
$ic_misses /= 60;
|
|
$squid_hist{'ic_misses'} = $1;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
$rrdata .= ":$ic_requests:$ic_hits:$ic_misses:0:0";
|
|
|
|
open(IN, "$SQUID_CMD mgr:io |");
|
|
@data = <IN>;
|
|
close(IN);
|
|
$all = join('', @data);
|
|
$all =~ s/\n/ /g;
|
|
($value) = ($all =~ m/ HTTP I\/O number of reads.*?(\d+)/g);
|
|
chomp($value);
|
|
$io_http = $value - $squid_hist{'io_http'};
|
|
$io_http = 0 unless $io_http != $value;
|
|
$io_http /= 60;
|
|
$squid_hist{'io_http'} = $value;
|
|
($value) = ($all =~ m/ FTP I\/O number of reads.*?(\d+)/g);
|
|
chomp($value);
|
|
$io_ftp = $value - $squid_hist{'io_ftp'};
|
|
$io_ftp = 0 unless $io_ftp != $value;
|
|
$io_ftp /= 60;
|
|
$squid_hist{'io_ftp'} = $value;
|
|
($value) = ($all =~ m/ Gopher I\/O number of reads.*?(\d+)/g);
|
|
chomp($value);
|
|
$io_gopher = $value - $squid_hist{'io_gopher'};
|
|
$io_gopher = 0 unless $io_gopher != $value;
|
|
$io_gopher /= 60;
|
|
$squid_hist{'io_gopher'} = $value;
|
|
($value) = ($all =~ m/ WAIS I\/O number of reads.*?(\d+)/g);
|
|
chomp($value);
|
|
$io_wais = $value - $squid_hist{'io_wais'};
|
|
$io_wais = 0 unless $io_wais != $value;
|
|
$io_wais /= 60;
|
|
$squid_hist{'io_wais'} = $value;
|
|
$rrdata .= ":$io_http:$io_ftp:$io_gopher:$io_wais:0";
|
|
|
|
open(IN, "$SQUID_CMD mgr:storedir |");
|
|
while(<IN>) {
|
|
if(/^Store Entries\s+:\s+(\d+)$/) {
|
|
$s_entries = $1;
|
|
next;
|
|
}
|
|
if(/^Maximum Swap Size\s+:\s+(\d+)/) {
|
|
$s_maximum = $1;
|
|
next;
|
|
}
|
|
if(/^Current Store Swap Size\s*:\s+(\d+)/) {
|
|
$s_current = $1;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
$rrdata .= ":$s_entries:$s_maximum:$s_current:0:0";
|
|
$rrdata .= ":$tc_client_http_in:$tc_client_http_out:0";
|
|
$rrdata .= ":$ts_server_all_in:$ts_server_all_out:0";
|
|
RRDs::update($SQUID_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $SQUID_RRD: $err") if $err;
|
|
}
|
|
|
|
# NFSS graph
|
|
# ----------------------------------------------------------------------------
|
|
sub nfss_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $NFSS_RRD)) {
|
|
logger("Creating '$NFSS_RRD' file.");
|
|
eval {
|
|
RRDs::create($NFSS_RRD,
|
|
"--step=60",
|
|
"DS:nfss_0:COUNTER:120:0:U",
|
|
"DS:nfss_1:COUNTER:120:0:U",
|
|
"DS:nfss_2:COUNTER:120:0:U",
|
|
"DS:nfss_3:COUNTER:120:0:U",
|
|
"DS:nfss_4:COUNTER:120:0:U",
|
|
"DS:nfss_5:COUNTER:120:0:U",
|
|
"DS:nfss_6:COUNTER:120:0:U",
|
|
"DS:nfss_7:COUNTER:120:0:U",
|
|
"DS:nfss_8:COUNTER:120:0:U",
|
|
"DS:nfss_9:COUNTER:120:0:U",
|
|
"DS:nfss_10:COUNTER:120:0:U",
|
|
"DS:nfss_11:COUNTER:120:0:U",
|
|
"DS:nfss_12:COUNTER:120:0:U",
|
|
"DS:nfss_13:COUNTER:120:0:U",
|
|
"DS:nfss_14:COUNTER:120:0:U",
|
|
"DS:nfss_15:COUNTER:120:0:U",
|
|
"DS:nfss_16:COUNTER:120:0:U",
|
|
"DS:nfss_17:COUNTER:120:0:U",
|
|
"DS:nfss_18:COUNTER:120:0:U",
|
|
"DS:nfss_19:COUNTER:120:0:U",
|
|
"DS:nfss_20:COUNTER:120:0:U",
|
|
"DS:nfss_21:COUNTER:120:0:U",
|
|
"DS:nfss_22:COUNTER:120:0:U",
|
|
"DS:nfss_23:COUNTER:120:0:U",
|
|
"DS:nfss_24:COUNTER:120:0:U",
|
|
"DS:nfss_25:COUNTER:120:0:U",
|
|
"DS:nfss_26:COUNTER:120:0:U",
|
|
"DS:nfss_27:COUNTER:120:0:U",
|
|
"DS:nfss_28:COUNTER:120:0:U",
|
|
"DS:nfss_29:COUNTER:120:0:U",
|
|
"DS:nfss_30:COUNTER:120:0:U",
|
|
"DS:nfss_31:COUNTER:120:0:U",
|
|
"DS:nfss_32:COUNTER:120:0:U",
|
|
"DS:nfss_33:COUNTER:120:0:U",
|
|
"DS:nfss_34:COUNTER:120:0:U",
|
|
"DS:nfss_35:COUNTER:120:0:U",
|
|
"DS:nfss_36:COUNTER:120:0:U",
|
|
"DS:nfss_37:COUNTER:120:0:U",
|
|
"DS:nfss_38:COUNTER:120:0:U",
|
|
"DS:nfss_39:COUNTER:120:0:U",
|
|
"DS:nfss_40:COUNTER:120:0:U",
|
|
"DS:nfss_41:COUNTER:120:0:U",
|
|
"DS:nfss_42:COUNTER:120:0:U",
|
|
"DS:nfss_43:COUNTER:120:0:U",
|
|
"DS:nfss_44:COUNTER:120:0:U",
|
|
"DS:nfss_45:COUNTER:120:0:U",
|
|
"DS:nfss_46:COUNTER:120:0:U",
|
|
"DS:nfss_47:COUNTER:120:0:U",
|
|
"DS:nfss_48:COUNTER:120:0:U",
|
|
"DS:nfss_49:COUNTER:120:0:U",
|
|
"DS:nfss_rc_1:COUNTER:120:0:U",
|
|
"DS:nfss_rc_2:COUNTER:120:0:U",
|
|
"DS:nfss_rc_3:COUNTER:120:0:U",
|
|
"DS:nfss_rc_4:COUNTER:120:0:U",
|
|
"DS:nfss_rc_5:COUNTER:120:0:U",
|
|
"DS:nfss_fh_1:COUNTER:120:0:U",
|
|
"DS:nfss_fh_2:COUNTER:120:0:U",
|
|
"DS:nfss_fh_3:COUNTER:120:0:U",
|
|
"DS:nfss_fh_4:COUNTER:120:0:U",
|
|
"DS:nfss_fh_5:COUNTER:120:0:U",
|
|
"DS:nfss_io_1:COUNTER:120:0:U",
|
|
"DS:nfss_io_2:COUNTER:120:0:U",
|
|
"DS:nfss_io_3:COUNTER:120:0:U",
|
|
"DS:nfss_th_0:COUNTER:120:0:U",
|
|
"DS:nfss_th_1:COUNTER:120:0:U",
|
|
"DS:nfss_th_2:COUNTER:120:0:U",
|
|
"DS:nfss_th_3:COUNTER:120:0:U",
|
|
"DS:nfss_th_4:COUNTER:120:0:U",
|
|
"DS:nfss_th_5:COUNTER:120:0:U",
|
|
"DS:nfss_th_6:COUNTER:120:0:U",
|
|
"DS:nfss_th_7:COUNTER:120:0:U",
|
|
"DS:nfss_th_8:COUNTER:120:0:U",
|
|
"DS:nfss_th_9:COUNTER:120:0:U",
|
|
"DS:nfss_th_10:COUNTER:120:0:U",
|
|
"DS:nfss_net_1:COUNTER:120:0:U",
|
|
"DS:nfss_net_2:COUNTER:120:0:U",
|
|
"DS:nfss_net_3:COUNTER:120:0:U",
|
|
"DS:nfss_net_4:COUNTER:120:0:U",
|
|
"DS:nfss_net_5:COUNTER:120:0:U",
|
|
"DS:nfss_rpc_1:COUNTER:120:0:U",
|
|
"DS:nfss_rpc_2:COUNTER:120:0:U",
|
|
"DS:nfss_rpc_3:COUNTER:120:0:U",
|
|
"DS:nfss_rpc_4:COUNTER:120:0:U",
|
|
"DS:nfss_rpc_5:COUNTER:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $NFSS_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "nfss_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub nfss_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @rc;
|
|
my @fh;
|
|
my @io;
|
|
my @th;
|
|
my @net;
|
|
my @rpc;
|
|
my @nfss;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "/proc/net/rpc/nfsd");
|
|
while(<IN>) {
|
|
if(/^rc\s+(\d+)\s+(\d+)\s+(\d+)$/) {
|
|
@rc = ($1, $2, $3);
|
|
}
|
|
if(/^fh\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/) {
|
|
@fh = ($1, $2, $3, $4, $5);
|
|
}
|
|
if(/^io\s+(\d+)\s+(\d+)$/) {
|
|
@io = ($1, $2);
|
|
}
|
|
if(/^th /) {
|
|
my @tmp = split(' ', $_);
|
|
(undef, undef, @th) = @tmp;
|
|
}
|
|
if(/^net\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/) {
|
|
@net = ($1, $2, $3, $4);
|
|
}
|
|
if(/^rpc\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/) {
|
|
@rpc = ($1, $2, $3, $4, $5);
|
|
}
|
|
$NFSS_VERSION = "4ops" if $NFSS_VERSION eq "4";
|
|
if(/^proc$NFSS_VERSION /) {
|
|
my @tmp = split(' ', $_);
|
|
(undef, undef, @nfss) = @tmp;
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
# this part must be finished!!!! XXX
|
|
}
|
|
|
|
for($n = 0; $n < 50; $n++) {
|
|
if(!defined($nfss[$n])) {
|
|
$nfss[$n] = 0;
|
|
}
|
|
$rrdata .= ":" . $nfss[$n];
|
|
}
|
|
$rrdata .= ":$rc[0]:$rc[1]:$rc[2]:0:0";
|
|
$rrdata .= ":$fh[0]:$fh[1]:$fh[2]:$fh[3]:$fh[4]";
|
|
$rrdata .= ":$io[0]:$io[1]:0";
|
|
for($n = 0; $n < 11; $n++) {
|
|
$rrdata .= ":" . int($th[$n]);
|
|
}
|
|
$rrdata .= ":$net[0]:$net[1]:$net[2]:$net[3]:0";
|
|
$rrdata .= ":$rpc[0]:$rpc[1]:$rpc[2]:$rpc[3]:$rpc[4]";
|
|
RRDs::update($NFSS_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $NFSS_RRD: $err") if $err;
|
|
}
|
|
|
|
# NFSC graph
|
|
# ----------------------------------------------------------------------------
|
|
sub nfsc_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $NFSC_RRD)) {
|
|
logger("Creating '$NFSC_RRD' file.");
|
|
eval {
|
|
RRDs::create($NFSC_RRD,
|
|
"--step=60",
|
|
"DS:nfsc_0:COUNTER:120:0:U",
|
|
"DS:nfsc_1:COUNTER:120:0:U",
|
|
"DS:nfsc_2:COUNTER:120:0:U",
|
|
"DS:nfsc_3:COUNTER:120:0:U",
|
|
"DS:nfsc_4:COUNTER:120:0:U",
|
|
"DS:nfsc_5:COUNTER:120:0:U",
|
|
"DS:nfsc_6:COUNTER:120:0:U",
|
|
"DS:nfsc_7:COUNTER:120:0:U",
|
|
"DS:nfsc_8:COUNTER:120:0:U",
|
|
"DS:nfsc_9:COUNTER:120:0:U",
|
|
"DS:nfsc_10:COUNTER:120:0:U",
|
|
"DS:nfsc_11:COUNTER:120:0:U",
|
|
"DS:nfsc_12:COUNTER:120:0:U",
|
|
"DS:nfsc_13:COUNTER:120:0:U",
|
|
"DS:nfsc_14:COUNTER:120:0:U",
|
|
"DS:nfsc_15:COUNTER:120:0:U",
|
|
"DS:nfsc_16:COUNTER:120:0:U",
|
|
"DS:nfsc_17:COUNTER:120:0:U",
|
|
"DS:nfsc_18:COUNTER:120:0:U",
|
|
"DS:nfsc_19:COUNTER:120:0:U",
|
|
"DS:nfsc_20:COUNTER:120:0:U",
|
|
"DS:nfsc_21:COUNTER:120:0:U",
|
|
"DS:nfsc_22:COUNTER:120:0:U",
|
|
"DS:nfsc_23:COUNTER:120:0:U",
|
|
"DS:nfsc_24:COUNTER:120:0:U",
|
|
"DS:nfsc_25:COUNTER:120:0:U",
|
|
"DS:nfsc_26:COUNTER:120:0:U",
|
|
"DS:nfsc_27:COUNTER:120:0:U",
|
|
"DS:nfsc_28:COUNTER:120:0:U",
|
|
"DS:nfsc_29:COUNTER:120:0:U",
|
|
"DS:nfsc_30:COUNTER:120:0:U",
|
|
"DS:nfsc_31:COUNTER:120:0:U",
|
|
"DS:nfsc_32:COUNTER:120:0:U",
|
|
"DS:nfsc_33:COUNTER:120:0:U",
|
|
"DS:nfsc_34:COUNTER:120:0:U",
|
|
"DS:nfsc_35:COUNTER:120:0:U",
|
|
"DS:nfsc_36:COUNTER:120:0:U",
|
|
"DS:nfsc_37:COUNTER:120:0:U",
|
|
"DS:nfsc_38:COUNTER:120:0:U",
|
|
"DS:nfsc_39:COUNTER:120:0:U",
|
|
"DS:nfsc_40:COUNTER:120:0:U",
|
|
"DS:nfsc_41:COUNTER:120:0:U",
|
|
"DS:nfsc_42:COUNTER:120:0:U",
|
|
"DS:nfsc_43:COUNTER:120:0:U",
|
|
"DS:nfsc_44:COUNTER:120:0:U",
|
|
"DS:nfsc_45:COUNTER:120:0:U",
|
|
"DS:nfsc_46:COUNTER:120:0:U",
|
|
"DS:nfsc_47:COUNTER:120:0:U",
|
|
"DS:nfsc_48:COUNTER:120:0:U",
|
|
"DS:nfsc_49:COUNTER:120:0:U",
|
|
"DS:nfsc_rpc_1:COUNTER:120:0:U",
|
|
"DS:nfsc_rpc_2:COUNTER:120:0:U",
|
|
"DS:nfsc_rpc_3:COUNTER:120:0:U",
|
|
"DS:nfsc_rpc_4:COUNTER:120:0:U",
|
|
"DS:nfsc_rpc_5:COUNTER:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $NFSC_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "nfsc_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub nfsc_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @rpc;
|
|
my @nfsc;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "/proc/net/rpc/nfs");
|
|
while(<IN>) {
|
|
if(/^rpc\s+(\d+)\s+(\d+)\s+(\d+)$/) {
|
|
@rpc = ($1, $2, $3);
|
|
}
|
|
if(/^proc$NFSC_VERSION /) {
|
|
my @tmp = split(' ', $_);
|
|
(undef, undef, @nfsc) = @tmp;
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
# this part must be finished!!!! XXX
|
|
}
|
|
|
|
for($n = 0; $n < 50; $n++) {
|
|
if(!defined($nfsc[$n])) {
|
|
$nfsc[$n] = 0;
|
|
}
|
|
$rrdata .= ":" . $nfsc[$n];
|
|
}
|
|
|
|
$rrdata .= ":$rpc[0]:$rpc[1]:$rpc[2]:0:0";
|
|
RRDs::update($NFSC_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $NFSC_RRD: $err") if $err;
|
|
}
|
|
|
|
# BIND graph
|
|
# ----------------------------------------------------------------------------
|
|
sub bind_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
if(-e $BIND_RRD) {
|
|
$info = RRDs::info($BIND_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 135 != scalar(@BIND_URL_LIST)) {
|
|
logger("Detected size mismatch between \@BIND_URL_LIST (" . scalar(@BIND_URL_LIST) . ") and $BIND_RRD (" . scalar(@ds) / 135 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($BIND_RRD, "$BIND_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $BIND_RRD)) {
|
|
logger("Creating '$BIND_RRD' file.");
|
|
for($n = 0; $n < scalar(@BIND_URL_LIST); $n++) {
|
|
push(@tmp, "DS:bind" . $n . "_totalinq:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq01:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq02:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq03:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq04:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq05:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq10:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq11:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq12:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq13:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq14:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq15:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq16:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq17:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq18:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq19:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_inq20:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq01:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq02:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq03:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq04:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq05:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq10:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq11:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq12:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq13:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq14:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq15:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq16:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq17:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq18:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq19:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ouq20:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss03:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss04:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss05:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss10:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss11:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss12:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss13:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss14:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss15:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss16:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss17:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss18:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss19:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_ss20:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs03:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs04:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs05:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs10:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs11:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs12:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs13:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs14:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs15:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs16:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs17:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs18:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs19:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_rs20:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr01:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr02:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr03:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr04:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr05:GAUGE:120:U:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr10:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr11:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr12:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr13:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr14:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr15:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr16:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr17:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr18:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr19:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_crr20:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio03:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio04:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio05:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio10:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio11:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio12:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio13:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio14:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio15:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio16:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio17:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio18:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio19:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_sio20:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_totaluse:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_inuse:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_blksize:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_ctxtsize:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_lost:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_val01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_val02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_mem_val03:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_tsk_workthrds:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_tsk_defquantm:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_tsk_tasksrun:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_tsk_val01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_tsk_val02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:bind" . $n . "_tsk_val03:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($BIND_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $BIND_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
our %bind_hist = ();
|
|
push(@graphs, "bind_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub bind_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $totalinq;
|
|
my %inq = ();
|
|
my %ouq = ();
|
|
my %ss = ();
|
|
my %rs = ();
|
|
my %crr = ();
|
|
my $str;
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
my $e = 0;
|
|
foreach(@BIND_URL_LIST) {
|
|
my $ua = LWP::UserAgent->new(timeout => 30);
|
|
my $response = $ua->request(HTTP::Request->new('GET', $_));
|
|
my $data = XMLin($response->content);
|
|
my $value;
|
|
|
|
$value = $data->{bind}->{statistics}->{server}->{requests}->{opcode}->{counter};
|
|
$str = $e . "totalinq";
|
|
$totalinq = $value - $bind_hist{$str};
|
|
$totalinq = 0 unless $totalinq != $value;
|
|
$totalinq /= 60;
|
|
$bind_hist{$str} = $value;
|
|
|
|
$value = $data->{bind}->{statistics}->{server}->{'queries-in'}->{rdtype};
|
|
foreach(keys %{$value}) {
|
|
$str = $e . "inq_$_";
|
|
$inq{$str} = $value->{$_}->{counter} - $bind_hist{$str};
|
|
$inq{$str} = 0 unless $inq{$str} != $value->{$_}->{counter};
|
|
$inq{$str} /= 60;
|
|
$bind_hist{$str} = $value->{$_}->{counter};
|
|
}
|
|
|
|
my $views_default = $data->{bind}->{statistics}->{views}->{view}->{_default};
|
|
$value = $views_default->{rdtype};
|
|
foreach(keys %{$value}) {
|
|
$str = $e . "ouq_$_";
|
|
$ouq{$str} = $value->{$_}->{counter} - $bind_hist{$str};
|
|
$ouq{$str} = 0 unless $ouq{$str} != $value->{$_}->{counter};
|
|
$ouq{$str} /= 60;
|
|
$bind_hist{$str} = $value->{$_}->{counter};
|
|
}
|
|
|
|
$value = $data->{bind}->{statistics}->{server}->{nsstat};
|
|
foreach(keys %{$value}) {
|
|
$str = $e . "ss_$_";
|
|
$ss{$str} = $value->{$_}->{counter} - $bind_hist{$str};
|
|
$ss{$str} = 0 unless $ss{$str} != $value->{$_}->{counter};
|
|
$ss{$str} /= 60;
|
|
$bind_hist{$str} = $value->{$_}->{counter};
|
|
}
|
|
|
|
$value = $views_default->{resstat};
|
|
foreach(keys %{$value}) {
|
|
$str = $e . "rs_$_";
|
|
$rs{$str} = $value->{$_}->{counter} - $bind_hist{$str};
|
|
$rs{$str} = 0 unless $rs{$str} != $value->{$_}->{counter};
|
|
$rs{$str} /= 60;
|
|
$bind_hist{$str} = $value->{$_}->{counter};
|
|
}
|
|
|
|
$value = $views_default->{cache}->{rrset};
|
|
foreach(keys %{$value}) {
|
|
$str = $e . "crr_$_";
|
|
$crr{$str} = $value->{$_}->{counter};
|
|
}
|
|
|
|
# Socket I/O Statistics
|
|
# $value = $data->{bind}->{statistics}->{server}->{sockstat};
|
|
# foreach(keys %{$value}) {
|
|
# $str = $e . "sio_$_";
|
|
# $sio{$str} = $value->{$_}->{counter} - $bind_hist{$str};
|
|
# $sio{$str} = 0 unless $sio{$str} != $value->{$_}->{counter};
|
|
# $sio{$str} /= 60;
|
|
# $bind_hist{$str} = $value->{$_}->{counter};
|
|
# }
|
|
|
|
$rrdata .= ":$totalinq";
|
|
my $i = @BIND_IN_QUERIES_LIST[$e];
|
|
for($n = 0; $n < 20; $n++) {
|
|
my $j = @$i[$n];
|
|
$str = $e . "inq_$j";
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($inq{$str}) ? $inq{$str} : 0;
|
|
}
|
|
$i = @BIND_OUT_QUERIES_LIST[$e];
|
|
for($n = 0; $n < 20; $n++) {
|
|
my $j = @$i[$n];
|
|
$str = $e . "ouq_$j";
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($ouq{$str}) ? $ouq{$str} : 0;
|
|
}
|
|
$i = @BIND_SERVER_STATS_LIST[$e];
|
|
for($n = 0; $n < 20; $n++) {
|
|
my $j = @$i[$n];
|
|
$str = $e . "ss_$j";
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($ss{$str}) ? $ss{$str} : 0;
|
|
}
|
|
$i = @BIND_RESOLVER_STATS_LIST[$e];
|
|
for($n = 0; $n < 20; $n++) {
|
|
my $j = @$i[$n];
|
|
$str = $e . "rs_$j";
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($rs{$str}) ? $rs{$str} : 0;
|
|
}
|
|
$i = @BIND_CACHE_RRSETS_LIST[$e];
|
|
for($n = 0; $n < 20; $n++) {
|
|
my $j = @$i[$n];
|
|
$str = $e . "crr_$j";
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($crr{$str}) ? $crr{$str} : 0;
|
|
}
|
|
# $i = @BIND_SOCKET_IO_STATS_LIST[$e];
|
|
for($n = 0; $n < 20; $n++) {
|
|
my $j = @$i[$n];
|
|
$str = $e . "sio_$j";
|
|
$rrdata .= ":";
|
|
$rrdata .= defined($sio{$str}) ? $sio{$str} : 0;
|
|
}
|
|
$value = $data->{bind}->{statistics}->{memory};
|
|
$rrdata .= ":" . $value->{summary}->{TotalUse};
|
|
$rrdata .= ":" . $value->{summary}->{InUse};
|
|
$rrdata .= ":" . $value->{summary}->{BlockSize};
|
|
$rrdata .= ":" . $value->{summary}->{ContextSize};
|
|
$rrdata .= ":" . $value->{summary}->{Lost};
|
|
$rrdata .= ":0:0:0";
|
|
$value = $data->{bind}->{statistics}->{taskmgr};
|
|
$rrdata .= ":" . $value->{'thread-model'}->{'worker-threads'};
|
|
$rrdata .= ":" . $value->{'thread-model'}->{'default-quantum'};
|
|
$rrdata .= ":" . $value->{'thread-model'}->{'tasks-running'};
|
|
$rrdata .= ":0:0:0";
|
|
|
|
$e++;
|
|
}
|
|
|
|
RRDs::update($BIND_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $BIND_RRD: $err") if $err;
|
|
}
|
|
|
|
# NTP graph
|
|
# ----------------------------------------------------------------------------
|
|
sub ntp_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
if(-e $NTP_RRD) {
|
|
$info = RRDs::info($NTP_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 14 != scalar(@NTP_HOST_LIST)) {
|
|
logger("Detected size mismatch between \@NTP_HOST_LIST (" . scalar(@NTP_HOST_LIST) . ") and $NTP_RRD (" . scalar(@ds) / 14 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($NTP_RRD, "$NTP_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $NTP_RRD)) {
|
|
logger("Creating '$NTP_RRD' file.");
|
|
for($n = 0; $n < scalar(@NTP_HOST_LIST); $n++) {
|
|
push(@tmp, "DS:ntp" . $n . "_del:GAUGE:120:U:U");
|
|
push(@tmp, "DS:ntp" . $n . "_off:GAUGE:120:U:U");
|
|
push(@tmp, "DS:ntp" . $n . "_jit:GAUGE:120:U:U");
|
|
push(@tmp, "DS:ntp" . $n . "_str:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c01:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c02:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c03:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c04:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c05:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c06:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c07:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c08:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c09:GAUGE:120:0:U");
|
|
push(@tmp, "DS:ntp" . $n . "_c10:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($NTP_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $NTP_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "ntp_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub ntp_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @data;
|
|
my $del;
|
|
my $off;
|
|
my $jit;
|
|
my $str;
|
|
my $cod;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
my $e = 0;
|
|
foreach(@NTP_HOST_LIST) {
|
|
open(IN, "ntpq -pn $_ |");
|
|
@data = <IN>;
|
|
close(IN);
|
|
$cod = $str = $del = $off = $jit = 0;
|
|
foreach(@data) {
|
|
if(/^\*/) {
|
|
(undef, $cod, $str, undef, undef, undef, undef, $del, $off, $jit) = split(' ', $_);
|
|
$cod =~ s/\.//g;
|
|
chomp($jit);
|
|
last;
|
|
}
|
|
}
|
|
$del = 0 unless defined($del);
|
|
$off = 0 unless defined($off);
|
|
$jit = 0 unless defined($jit);
|
|
$str = 0 unless defined($str);
|
|
$del /= 1000;
|
|
$off /= 1000;
|
|
$jit /= 1000;
|
|
$rrdata .= ":$del:$off:$jit:$str";
|
|
foreach my $i (@NTP_CODE_LIST[$e]) {
|
|
for($n = 0; $n < 10; $n++) {
|
|
if($cod eq @$i[$n]) {
|
|
$rrdata .= ":1";
|
|
} else {
|
|
$rrdata .= ":0";
|
|
}
|
|
}
|
|
}
|
|
$e++;
|
|
}
|
|
|
|
RRDs::update($NTP_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $NTP_RRD: $err") if $err;
|
|
}
|
|
|
|
# FAIL2BAN graph
|
|
# ----------------------------------------------------------------------------
|
|
sub fail2ban_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
if(-e $FAIL2BAN_RRD) {
|
|
$info = RRDs::info($FAIL2BAN_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 9 != scalar(@FAIL2BAN_LIST)) {
|
|
logger("Detected size mismatch between \@FAIL2BAN_LIST (" . scalar(@FAIL2BAN_LIST) . ") and $FAIL2BAN_RRD (" . scalar(@ds) / 9 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($FAIL2BAN_RRD, "$FAIL2BAN_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $FAIL2BAN_RRD)) {
|
|
logger("Creating '$FAIL2BAN_RRD' file.");
|
|
for($n = 0; $n < scalar(@FAIL2BAN_LIST); $n++) {
|
|
push(@tmp, "DS:fail2ban" . $n . "_j1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j2:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j3:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j4:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j5:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j6:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j7:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j8:GAUGE:120:0:U");
|
|
push(@tmp, "DS:fail2ban" . $n . "_j9:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($FAIL2BAN_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $FAIL2BAN_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
our $fail2ban_hist = 0;
|
|
push(@graphs, "fail2ban_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub fail2ban_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my $seek_pos;
|
|
my $logsize;
|
|
my @jails;
|
|
|
|
my $n;
|
|
my $str;
|
|
my $rrdata = "N";
|
|
|
|
if(! -r $FAIL2BAN_LOG) {
|
|
logger("Couldn't find file $FAIL2BAN_LOG: $!");
|
|
return;
|
|
}
|
|
|
|
$seek_pos = $fail2ban_hist;
|
|
$seek_pos = defined($seek_pos) ? int($seek_pos) : 0;
|
|
open(IN, $FAIL2BAN_LOG);
|
|
if(!seek(IN, 0, 2)) {
|
|
logger("Couldn't seek to the end ($FAIL2BAN_LOG): $!");
|
|
return;
|
|
}
|
|
$logsize = tell(IN);
|
|
if($logsize < $seek_pos) {
|
|
$seek_pos = 0;
|
|
}
|
|
if(!seek(IN, $seek_pos, 0)) {
|
|
logger("Couldn't seek to $seek_pos ($FAIL2BAN_LOG): $!");
|
|
return;
|
|
}
|
|
if($fail2ban_hist > 0) { # avoid initial spike
|
|
$date = strftime("%Y-%m-%d", localtime);
|
|
while(<IN>) {
|
|
if(/^$date/) {
|
|
my $e = 0;
|
|
while($e < scalar(@FAIL2BAN_LIST)) {
|
|
foreach my $i (@FAIL2BAN_LIST[$e]) {
|
|
my $e2 = 0;
|
|
foreach my $j (@$i) {
|
|
($str = $j) =~ s/\[/\\[/;
|
|
$str =~ s/\]/\\]/;
|
|
$jails[$e][$e2] = 0 unless defined $jails[$e][$e2];
|
|
if(/ $str Ban /) {
|
|
$jails[$e][$e2]++;
|
|
}
|
|
$e2++;
|
|
}
|
|
}
|
|
$e++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
close(IN);
|
|
|
|
my $e = 0;
|
|
while($e < scalar(@FAIL2BAN_LIST)) {
|
|
for($n = 0; $n < 9; $n++) {
|
|
$jails[$e][$n] = 0 unless defined $jails[$e][$n];
|
|
$rrdata .= ":" . $jails[$e][$n];
|
|
}
|
|
$e++;
|
|
}
|
|
|
|
$fail2ban_hist = $logsize;
|
|
|
|
RRDs::update($FAIL2BAN_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $FAIL2BAN_RRD: $err") if $err;
|
|
}
|
|
|
|
# ICECAST graph
|
|
# ----------------------------------------------------------------------------
|
|
sub icecast_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my $n;
|
|
|
|
if(-e $ICECAST_RRD) {
|
|
$info = RRDs::info($ICECAST_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 36 != scalar(@ICECAST_URL_LIST)) {
|
|
logger("Detected size mismatch between \@ICECAST_URL_LIST (" . scalar(@ICECAST_URL_LIST) . ") and $ICECAST_RRD (" . scalar(@ds) / 36 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($ICECAST_RRD, "$ICECAST_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $ICECAST_RRD)) {
|
|
logger("Creating '$ICECAST_RRD' file.");
|
|
for($n = 0; $n < scalar(@ICECAST_URL_LIST); $n++) {
|
|
push(@tmp, "DS:icecast" . $n . "_mp0_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp0_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp0_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp0_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp1_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp1_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp1_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp1_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp2_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp2_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp2_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp2_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp3_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp3_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp3_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp3_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp4_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp4_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp4_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp4_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp5_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp5_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp5_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp5_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp6_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp6_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp6_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp6_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp7_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp7_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp7_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp7_v1:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp8_ls:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp8_br:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp8_v0:GAUGE:120:0:U");
|
|
push(@tmp, "DS:icecast" . $n . "_mp8_v1:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($ICECAST_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $ICECAST_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "icecast_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub icecast_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @ls;
|
|
my @br;
|
|
|
|
my $n;
|
|
my $rrdata = "N";
|
|
|
|
my $e = 0;
|
|
foreach(@ICECAST_URL_LIST) {
|
|
my $ua = LWP::UserAgent->new(timeout => 30);
|
|
my $response = $ua->request(HTTP::Request->new('GET', $_));
|
|
my $data = $response->content;
|
|
|
|
$data =~ s/\n//g;
|
|
undef(@ls);
|
|
undef(@br);
|
|
foreach my $i (@ICECAST_MP_LIST[$e]) {
|
|
foreach(@$i) {
|
|
my $m = "Mount Point " . $_;
|
|
my ($b) = ($data =~ m/$m.*?<tr><td>Bitrate:<\/td><td class=\"streamdata\">(\d*?)<\/td><\/tr>/g);
|
|
my ($l) = ($data =~ m/$m.*?<tr><td>Current Listeners:<\/td><td class=\"streamdata\">(\d*?)<\/td>/g);
|
|
$b = 0 unless defined($b);
|
|
$l = 0 unless defined($l);
|
|
push(@ls, $l);
|
|
push(@br, $b);
|
|
}
|
|
for($n = 0; $n < 9; $n++) {
|
|
$ls[$n] = 0 unless defined($ls[$n]);
|
|
$br[$n] = 0 unless defined($br[$n]);
|
|
$rrdata .= ":" . $ls[$n];
|
|
$rrdata .= ":" . $br[$n];
|
|
$rrdata .= ":" . "0";
|
|
$rrdata .= ":" . "0";
|
|
}
|
|
}
|
|
$e++;
|
|
}
|
|
|
|
RRDs::update($ICECAST_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $ICECAST_RRD: $err") if $err;
|
|
}
|
|
|
|
# INT graph
|
|
# ----------------------------------------------------------------------------
|
|
sub int_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
if(!(-e $INT_RRD)) {
|
|
logger("Creating '$INT_RRD' file.");
|
|
eval {
|
|
RRDs::create($INT_RRD,
|
|
"--step=60",
|
|
"DS:int_0:COUNTER:120:0:U",
|
|
"DS:int_1:COUNTER:120:0:U",
|
|
"DS:int_2:COUNTER:120:0:U",
|
|
"DS:int_3:COUNTER:120:0:U",
|
|
"DS:int_4:COUNTER:120:0:U",
|
|
"DS:int_5:COUNTER:120:0:U",
|
|
"DS:int_6:COUNTER:120:0:U",
|
|
"DS:int_7:COUNTER:120:0:U",
|
|
"DS:int_8:COUNTER:120:0:U",
|
|
"DS:int_9:COUNTER:120:0:U",
|
|
"DS:int_10:COUNTER:120:0:U",
|
|
"DS:int_11:COUNTER:120:0:U",
|
|
"DS:int_12:COUNTER:120:0:U",
|
|
"DS:int_13:COUNTER:120:0:U",
|
|
"DS:int_14:COUNTER:120:0:U",
|
|
"DS:int_15:COUNTER:120:0:U",
|
|
"DS:int_16:COUNTER:120:0:U",
|
|
"DS:int_17:COUNTER:120:0:U",
|
|
"DS:int_18:COUNTER:120:0:U",
|
|
"DS:int_19:COUNTER:120:0:U",
|
|
"DS:int_20:COUNTER:120:0:U",
|
|
"DS:int_21:COUNTER:120:0:U",
|
|
"DS:int_22:COUNTER:120:0:U",
|
|
"DS:int_23:COUNTER:120:0:U",
|
|
"DS:int_24:COUNTER:120:0:U",
|
|
"DS:int_25:COUNTER:120:0:U",
|
|
"DS:int_26:COUNTER:120:0:U",
|
|
"DS:int_27:COUNTER:120:0:U",
|
|
"DS:int_28:COUNTER:120:0:U",
|
|
"DS:int_29:COUNTER:120:0:U",
|
|
"DS:int_30:COUNTER:120:0:U",
|
|
"DS:int_31:COUNTER:120:0:U",
|
|
"DS:int_32:COUNTER:120:0:U",
|
|
"DS:int_33:COUNTER:120:0:U",
|
|
"DS:int_34:COUNTER:120:0:U",
|
|
"DS:int_35:COUNTER:120:0:U",
|
|
"DS:int_36:COUNTER:120:0:U",
|
|
"DS:int_37:COUNTER:120:0:U",
|
|
"DS:int_38:COUNTER:120:0:U",
|
|
"DS:int_39:COUNTER:120:0:U",
|
|
"DS:int_40:COUNTER:120:0:U",
|
|
"DS:int_41:COUNTER:120:0:U",
|
|
"DS:int_42:COUNTER:120:0:U",
|
|
"DS:int_43:COUNTER:120:0:U",
|
|
"DS:int_44:COUNTER:120:0:U",
|
|
"DS:int_45:COUNTER:120:0:U",
|
|
"DS:int_46:COUNTER:120:0:U",
|
|
"DS:int_47:COUNTER:120:0:U",
|
|
"DS:int_48:COUNTER:120:0:U",
|
|
"DS:int_49:COUNTER:120:0:U",
|
|
"DS:int_50:COUNTER:120:0:U",
|
|
"DS:int_51:COUNTER:120:0:U",
|
|
"DS:int_52:COUNTER:120:0:U",
|
|
"DS:int_53:COUNTER:120:0:U",
|
|
"DS:int_54:COUNTER:120:0:U",
|
|
"DS:int_55:COUNTER:120:0:U",
|
|
"DS:int_56:COUNTER:120:0:U",
|
|
"DS:int_57:COUNTER:120:0:U",
|
|
"DS:int_58:COUNTER:120:0:U",
|
|
"DS:int_59:COUNTER:120:0:U",
|
|
"DS:int_60:COUNTER:120:0:U",
|
|
"DS:int_61:COUNTER:120:0:U",
|
|
"DS:int_62:COUNTER:120:0:U",
|
|
"DS:int_63:COUNTER:120:0:U",
|
|
"DS:int_64:COUNTER:120:0:U",
|
|
"DS:int_65:COUNTER:120:0:U",
|
|
"DS:int_66:COUNTER:120:0:U",
|
|
"DS:int_67:COUNTER:120:0:U",
|
|
"DS:int_68:COUNTER:120:0:U",
|
|
"DS:int_69:COUNTER:120:0:U",
|
|
"DS:int_70:COUNTER:120:0:U",
|
|
"DS:int_71:COUNTER:120:0:U",
|
|
"DS:int_72:COUNTER:120:0:U",
|
|
"DS:int_73:COUNTER:120:0:U",
|
|
"DS:int_74:COUNTER:120:0:U",
|
|
"DS:int_75:COUNTER:120:0:U",
|
|
"DS:int_76:COUNTER:120:0:U",
|
|
"DS:int_77:COUNTER:120:0:U",
|
|
"DS:int_78:COUNTER:120:0:U",
|
|
"DS:int_79:COUNTER:120:0:U",
|
|
"DS:int_80:COUNTER:120:0:U",
|
|
"DS:int_81:COUNTER:120:0:U",
|
|
"DS:int_82:COUNTER:120:0:U",
|
|
"DS:int_83:COUNTER:120:0:U",
|
|
"DS:int_84:COUNTER:120:0:U",
|
|
"DS:int_85:COUNTER:120:0:U",
|
|
"DS:int_86:COUNTER:120:0:U",
|
|
"DS:int_87:COUNTER:120:0:U",
|
|
"DS:int_88:COUNTER:120:0:U",
|
|
"DS:int_89:COUNTER:120:0:U",
|
|
"DS:int_90:COUNTER:120:0:U",
|
|
"DS:int_91:COUNTER:120:0:U",
|
|
"DS:int_92:COUNTER:120:0:U",
|
|
"DS:int_93:COUNTER:120:0:U",
|
|
"DS:int_94:COUNTER:120:0:U",
|
|
"DS:int_95:COUNTER:120:0:U",
|
|
"DS:int_96:COUNTER:120:0:U",
|
|
"DS:int_97:COUNTER:120:0:U",
|
|
"DS:int_98:COUNTER:120:0:U",
|
|
"DS:int_99:COUNTER:120:0:U",
|
|
"DS:int_100:COUNTER:120:0:U",
|
|
"DS:int_101:COUNTER:120:0:U",
|
|
"DS:int_102:COUNTER:120:0:U",
|
|
"DS:int_103:COUNTER:120:0:U",
|
|
"DS:int_104:COUNTER:120:0:U",
|
|
"DS:int_105:COUNTER:120:0:U",
|
|
"DS:int_106:COUNTER:120:0:U",
|
|
"DS:int_107:COUNTER:120:0:U",
|
|
"DS:int_108:COUNTER:120:0:U",
|
|
"DS:int_109:COUNTER:120:0:U",
|
|
"DS:int_110:COUNTER:120:0:U",
|
|
"DS:int_111:COUNTER:120:0:U",
|
|
"DS:int_112:COUNTER:120:0:U",
|
|
"DS:int_113:COUNTER:120:0:U",
|
|
"DS:int_114:COUNTER:120:0:U",
|
|
"DS:int_115:COUNTER:120:0:U",
|
|
"DS:int_116:COUNTER:120:0:U",
|
|
"DS:int_117:COUNTER:120:0:U",
|
|
"DS:int_118:COUNTER:120:0:U",
|
|
"DS:int_119:COUNTER:120:0:U",
|
|
"DS:int_120:COUNTER:120:0:U",
|
|
"DS:int_121:COUNTER:120:0:U",
|
|
"DS:int_122:COUNTER:120:0:U",
|
|
"DS:int_123:COUNTER:120:0:U",
|
|
"DS:int_124:COUNTER:120:0:U",
|
|
"DS:int_125:COUNTER:120:0:U",
|
|
"DS:int_126:COUNTER:120:0:U",
|
|
"DS:int_127:COUNTER:120:0:U",
|
|
"DS:int_128:COUNTER:120:0:U",
|
|
"DS:int_129:COUNTER:120:0:U",
|
|
"DS:int_130:COUNTER:120:0:U",
|
|
"DS:int_131:COUNTER:120:0:U",
|
|
"DS:int_132:COUNTER:120:0:U",
|
|
"DS:int_133:COUNTER:120:0:U",
|
|
"DS:int_134:COUNTER:120:0:U",
|
|
"DS:int_135:COUNTER:120:0:U",
|
|
"DS:int_136:COUNTER:120:0:U",
|
|
"DS:int_137:COUNTER:120:0:U",
|
|
"DS:int_138:COUNTER:120:0:U",
|
|
"DS:int_139:COUNTER:120:0:U",
|
|
"DS:int_140:COUNTER:120:0:U",
|
|
"DS:int_141:COUNTER:120:0:U",
|
|
"DS:int_142:COUNTER:120:0:U",
|
|
"DS:int_143:COUNTER:120:0:U",
|
|
"DS:int_144:COUNTER:120:0:U",
|
|
"DS:int_145:COUNTER:120:0:U",
|
|
"DS:int_146:COUNTER:120:0:U",
|
|
"DS:int_147:COUNTER:120:0:U",
|
|
"DS:int_148:COUNTER:120:0:U",
|
|
"DS:int_149:COUNTER:120:0:U",
|
|
"DS:int_150:COUNTER:120:0:U",
|
|
"DS:int_151:COUNTER:120:0:U",
|
|
"DS:int_152:COUNTER:120:0:U",
|
|
"DS:int_153:COUNTER:120:0:U",
|
|
"DS:int_154:COUNTER:120:0:U",
|
|
"DS:int_155:COUNTER:120:0:U",
|
|
"DS:int_156:COUNTER:120:0:U",
|
|
"DS:int_157:COUNTER:120:0:U",
|
|
"DS:int_158:COUNTER:120:0:U",
|
|
"DS:int_159:COUNTER:120:0:U",
|
|
"DS:int_160:COUNTER:120:0:U",
|
|
"DS:int_161:COUNTER:120:0:U",
|
|
"DS:int_162:COUNTER:120:0:U",
|
|
"DS:int_163:COUNTER:120:0:U",
|
|
"DS:int_164:COUNTER:120:0:U",
|
|
"DS:int_165:COUNTER:120:0:U",
|
|
"DS:int_166:COUNTER:120:0:U",
|
|
"DS:int_167:COUNTER:120:0:U",
|
|
"DS:int_168:COUNTER:120:0:U",
|
|
"DS:int_169:COUNTER:120:0:U",
|
|
"DS:int_170:COUNTER:120:0:U",
|
|
"DS:int_171:COUNTER:120:0:U",
|
|
"DS:int_172:COUNTER:120:0:U",
|
|
"DS:int_173:COUNTER:120:0:U",
|
|
"DS:int_174:COUNTER:120:0:U",
|
|
"DS:int_175:COUNTER:120:0:U",
|
|
"DS:int_176:COUNTER:120:0:U",
|
|
"DS:int_177:COUNTER:120:0:U",
|
|
"DS:int_178:COUNTER:120:0:U",
|
|
"DS:int_179:COUNTER:120:0:U",
|
|
"DS:int_180:COUNTER:120:0:U",
|
|
"DS:int_181:COUNTER:120:0:U",
|
|
"DS:int_182:COUNTER:120:0:U",
|
|
"DS:int_183:COUNTER:120:0:U",
|
|
"DS:int_184:COUNTER:120:0:U",
|
|
"DS:int_185:COUNTER:120:0:U",
|
|
"DS:int_186:COUNTER:120:0:U",
|
|
"DS:int_187:COUNTER:120:0:U",
|
|
"DS:int_188:COUNTER:120:0:U",
|
|
"DS:int_189:COUNTER:120:0:U",
|
|
"DS:int_190:COUNTER:120:0:U",
|
|
"DS:int_191:COUNTER:120:0:U",
|
|
"DS:int_192:COUNTER:120:0:U",
|
|
"DS:int_193:COUNTER:120:0:U",
|
|
"DS:int_194:COUNTER:120:0:U",
|
|
"DS:int_195:COUNTER:120:0:U",
|
|
"DS:int_196:COUNTER:120:0:U",
|
|
"DS:int_197:COUNTER:120:0:U",
|
|
"DS:int_198:COUNTER:120:0:U",
|
|
"DS:int_199:COUNTER:120:0:U",
|
|
"DS:int_200:COUNTER:120:0:U",
|
|
"DS:int_201:COUNTER:120:0:U",
|
|
"DS:int_202:COUNTER:120:0:U",
|
|
"DS:int_203:COUNTER:120:0:U",
|
|
"DS:int_204:COUNTER:120:0:U",
|
|
"DS:int_205:COUNTER:120:0:U",
|
|
"DS:int_206:COUNTER:120:0:U",
|
|
"DS:int_207:COUNTER:120:0:U",
|
|
"DS:int_208:COUNTER:120:0:U",
|
|
"DS:int_209:COUNTER:120:0:U",
|
|
"DS:int_210:COUNTER:120:0:U",
|
|
"DS:int_211:COUNTER:120:0:U",
|
|
"DS:int_212:COUNTER:120:0:U",
|
|
"DS:int_213:COUNTER:120:0:U",
|
|
"DS:int_214:COUNTER:120:0:U",
|
|
"DS:int_215:COUNTER:120:0:U",
|
|
"DS:int_216:COUNTER:120:0:U",
|
|
"DS:int_217:COUNTER:120:0:U",
|
|
"DS:int_218:COUNTER:120:0:U",
|
|
"DS:int_219:COUNTER:120:0:U",
|
|
"DS:int_220:COUNTER:120:0:U",
|
|
"DS:int_221:COUNTER:120:0:U",
|
|
"DS:int_222:COUNTER:120:0:U",
|
|
"DS:int_223:COUNTER:120:0:U",
|
|
"DS:int_224:COUNTER:120:0:U",
|
|
"DS:int_225:COUNTER:120:0:U",
|
|
"DS:int_226:COUNTER:120:0:U",
|
|
"DS:int_227:COUNTER:120:0:U",
|
|
"DS:int_228:COUNTER:120:0:U",
|
|
"DS:int_229:COUNTER:120:0:U",
|
|
"DS:int_230:COUNTER:120:0:U",
|
|
"DS:int_231:COUNTER:120:0:U",
|
|
"DS:int_232:COUNTER:120:0:U",
|
|
"DS:int_233:COUNTER:120:0:U",
|
|
"DS:int_234:COUNTER:120:0:U",
|
|
"DS:int_235:COUNTER:120:0:U",
|
|
"DS:int_236:COUNTER:120:0:U",
|
|
"DS:int_237:COUNTER:120:0:U",
|
|
"DS:int_238:COUNTER:120:0:U",
|
|
"DS:int_239:COUNTER:120:0:U",
|
|
"DS:int_240:COUNTER:120:0:U",
|
|
"DS:int_241:COUNTER:120:0:U",
|
|
"DS:int_242:COUNTER:120:0:U",
|
|
"DS:int_243:COUNTER:120:0:U",
|
|
"DS:int_244:COUNTER:120:0:U",
|
|
"DS:int_245:COUNTER:120:0:U",
|
|
"DS:int_246:COUNTER:120:0:U",
|
|
"DS:int_247:COUNTER:120:0:U",
|
|
"DS:int_248:COUNTER:120:0:U",
|
|
"DS:int_249:COUNTER:120:0:U",
|
|
"DS:int_250:COUNTER:120:0:U",
|
|
"DS:int_251:COUNTER:120:0:U",
|
|
"DS:int_252:COUNTER:120:0:U",
|
|
"DS:int_253:COUNTER:120:0:U",
|
|
"DS:int_254:COUNTER:120:0:U",
|
|
"DS:int_255:COUNTER:120:0:U",
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $INT_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
push(@graphs, "int_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub int_update {
|
|
my $myself = (caller(0))[3];
|
|
my ($debug) = @_;
|
|
|
|
my @int;
|
|
|
|
my $n;
|
|
my $maxints;
|
|
my $rrdata = "N";
|
|
|
|
if($os eq "Linux") {
|
|
open(IN, "/proc/stat");
|
|
while(<IN>) {
|
|
if(/^intr/) {
|
|
my @tmp = split(' ', $_);
|
|
(undef, undef, @int) = @tmp;
|
|
last;
|
|
}
|
|
}
|
|
close(IN);
|
|
} elsif($os eq "FreeBSD" || $os eq "OpenBSD") {
|
|
open(IN, "vmstat -i |");
|
|
my @allfields;
|
|
my $num;
|
|
my $name;
|
|
my $ticks;
|
|
$maxints = 0;
|
|
while(<IN>) {
|
|
if(/^\D{3}\d+/) {
|
|
@allfields = split(' ', $_);
|
|
$num = $allfields[0];
|
|
$name = $allfields[1];
|
|
$ticks = $allfields[$#allfields - 1];
|
|
chomp($ticks);
|
|
if($name eq "timer") {
|
|
$num = 0;
|
|
} else {
|
|
$num =~ s/^\D{3}//;
|
|
$num =~ s/://;
|
|
}
|
|
$int[$num] += $ticks;
|
|
$maxints = $maxints < $num ? $num : $maxints;
|
|
}
|
|
}
|
|
close(IN);
|
|
for($n = 0; $n < $maxints; $n++) {
|
|
$int[$n] = !$int[$n] ? 0 : $int[$n];
|
|
}
|
|
}
|
|
|
|
for($n = 0; $n < scalar(@int); $n++) {
|
|
if(($n % 256) != $n) {
|
|
$int[$n % 256] += $int[$n];
|
|
}
|
|
}
|
|
|
|
for($n = 0; $n < 256; $n++) {
|
|
if(!defined($int[$n])) {
|
|
$int[$n] = 0;
|
|
}
|
|
$rrdata .= ":" . $int[$n];
|
|
}
|
|
|
|
RRDs::update($INT_RRD, $rrdata);
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $INT_RRD: $err") if $err;
|
|
}
|
|
|
|
# PC graph
|
|
# ----------------------------------------------------------------------------
|
|
sub pc_init {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my $info;
|
|
my @ds;
|
|
my @tmp;
|
|
my @data;
|
|
my $n;
|
|
my $p;
|
|
|
|
if(!grep {$_ eq $os} ("Linux")) {
|
|
logger("$myself is not supported yet by your operating system ($os).");
|
|
return;
|
|
}
|
|
|
|
if(-e $PC_RRD) {
|
|
$info = RRDs::info($PC_RRD);
|
|
for my $key (keys %$info) {
|
|
if(index($key, 'ds[') == 0) {
|
|
if(index($key, '.type') != -1) {
|
|
push(@ds, substr($key, 3, index($key, ']') - 3));
|
|
}
|
|
}
|
|
}
|
|
if(scalar(@ds) / 2 != $PC_MAX) {
|
|
logger("Detected size mismatch between \$PC_MAX ($PC_MAX) and $PC_RRD (" . scalar(@ds) / 2 . "). Resizing it accordingly. All historic data will be lost. Backup file created.");
|
|
rename($PC_RRD, "$PC_RRD.bak");
|
|
}
|
|
}
|
|
|
|
if(!(-e $PC_RRD)) {
|
|
logger("Creating '$PC_RRD' file.");
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
push(@tmp, "DS:pc" . $n . "_in:GAUGE:120:0:U");
|
|
push(@tmp, "DS:pc" . $n . "_out:GAUGE:120:0:U");
|
|
}
|
|
eval {
|
|
RRDs::create($PC_RRD,
|
|
"--step=60",
|
|
@tmp,
|
|
"RRA:AVERAGE:0.5:1:1440",
|
|
"RRA:AVERAGE:0.5:30:336",
|
|
"RRA:AVERAGE:0.5:60:744",
|
|
"RRA:AVERAGE:0.5:1440:365",
|
|
"RRA:MIN:0.5:1:1440",
|
|
"RRA:MIN:0.5:30:336",
|
|
"RRA:MIN:0.5:60:744",
|
|
"RRA:MIN:0.5:1440:365",
|
|
"RRA:MAX:0.5:1:1440",
|
|
"RRA:MAX:0.5:30:336",
|
|
"RRA:MAX:0.5:60:744",
|
|
"RRA:MAX:0.5:1440:365",
|
|
"RRA:LAST:0.5:1:1440",
|
|
"RRA:LAST:0.5:30:336",
|
|
"RRA:LAST:0.5:60:744",
|
|
"RRA:LAST:0.5:1440:365",
|
|
);
|
|
};
|
|
my $err = RRDs::error;
|
|
if($@ || $err) {
|
|
logger("$@") unless !$@;
|
|
if($err) {
|
|
logger("ERROR: while creating $PC_RRD: $err");
|
|
if($err eq "RRDs::error") {
|
|
logger("... is the RRDtool Perl package installed?");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if($os eq "Linux") {
|
|
if(!$NET_GATEWAY) {
|
|
logger("You must assign a valid ethernet interface in \$NET_GATEWAY");
|
|
return;
|
|
}
|
|
# remove the changed PC or those that no longer exist (daily)
|
|
open(IN, "iptables -nxvL FORWARD | grep _daily |");
|
|
@data = <IN>;
|
|
close(IN);
|
|
my $rule;
|
|
my $num;
|
|
my $exist;
|
|
foreach my $d (@data) {
|
|
$exist = 0;
|
|
(undef, undef, $name) = split(' ', $d);
|
|
$name =~ s/_daily//;
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
if($name eq $PC_LIST[$n]) {
|
|
$exist = 1;
|
|
last;
|
|
}
|
|
}
|
|
if(!$exist) {
|
|
logger("removing unused iptables rule: pc=$name");
|
|
$rule = system("iptables -nxvL FORWARD --line-numbers | grep -w $name" . "_daily 2>/dev/null");
|
|
$rule = split(' ', $rule);
|
|
system("iptables -D FORWARD $rule");
|
|
system("iptables -F $name" . "_daily");
|
|
system("iptables -X $name" . "_daily");
|
|
}
|
|
}
|
|
|
|
# set the iptables rules for each defined PC
|
|
my $ip;
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
if($PC_LIST[$n]) {
|
|
if(!($ip = $PC_IP[$n])) {
|
|
if(!(gethostbyname($PC_LIST[$n]))) {
|
|
logger("DNS problem with: ", $PC_LIST[$n]);
|
|
}
|
|
$ip = inet_ntoa((gethostbyname($PC_LIST[$n]))[4]);
|
|
$ip = $ip . "/32";
|
|
}
|
|
undef(@data);
|
|
open(IN, "iptables -nxvL $PC_LIST[$n]_daily 2>/dev/null |");
|
|
@data = <IN>;
|
|
close(IN);
|
|
if(!scalar(@data)) {
|
|
system("iptables -N $PC_LIST[$n]_daily");
|
|
system("iptables -I FORWARD -j $PC_LIST[$n]_daily");
|
|
system("iptables -A $PC_LIST[$n]_daily -s $ip -d 0/0 -o $NET_GATEWAY");
|
|
system("iptables -A $PC_LIST[$n]_daily -s 0/0 -d $ip -i $NET_GATEWAY");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Since 2.5.2 PC_LAN values need to be converted to GAUGE.
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
RRDs::tune($PC_RRD,
|
|
"--data-source-type=pc" . $n . "_in:GAUGE",
|
|
"--data-source-type=pc" . $n . "_out:GAUGE",
|
|
);
|
|
}
|
|
|
|
our @pc_hist_in = ();
|
|
our @pc_hist_out = ();
|
|
push(@graphs, "pc_update");
|
|
if($opt_d eq "all" || $debug) {
|
|
logger("$myself: Ok");
|
|
}
|
|
}
|
|
|
|
sub pc_update {
|
|
my $myself = (caller(0))[3];
|
|
|
|
my @in;
|
|
my @out;
|
|
|
|
my $n;
|
|
my $ip;
|
|
my $rrdata = "N";
|
|
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
if($PC_LIST[$n]) {
|
|
if(!($ip = $PC_IP[$n])) {
|
|
if(!(gethostbyname($PC_LIST[$n]))) {
|
|
logger("DNS problem with: ", $PC_LIST[$n]);
|
|
}
|
|
$ip = inet_ntoa((gethostbyname($PC_LIST[$n]))[4]);
|
|
}
|
|
$ip =~ s/\/\d+//;
|
|
open(IN, "iptables -nxvL $PC_LIST[$n]_daily |");
|
|
$in[$n] = 0 unless $in[$n];
|
|
$out[$n] = 0 unless $out[$n];
|
|
while(<IN>) {
|
|
my (undef, $bytes, undef, undef, undef, undef, $source) = split(' ', $_);
|
|
if($source =~ /0.0.0.0/) {
|
|
$in[$n] = $bytes - $pc_hist_in[$n];
|
|
$in[$n] = 0 unless $in[$n] != $bytes;
|
|
$pc_hist_in[$n] = $bytes;
|
|
$in[$n] /= 60;
|
|
}
|
|
if($source eq $ip) {
|
|
$out[$n] = $bytes - $pc_hist_out[$n];
|
|
$out[$n] = 0 unless $out[$n] != $bytes;
|
|
$pc_hist_out[$n] = $bytes;
|
|
$out[$n] /= 60;
|
|
}
|
|
}
|
|
close(IN);
|
|
}
|
|
}
|
|
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
$rrdata .= ":$in[$n]:$out[$n]";
|
|
}
|
|
|
|
RRDs::update($PC_RRD, $rrdata);
|
|
if($opt_d eq "all") {
|
|
logger("$myself: $rrdata");
|
|
}
|
|
my $err = RRDs::error;
|
|
logger("ERROR: while updating $PC_RRD: $err") if $err;
|
|
}
|
|
|
|
sub get_counters {
|
|
my $in;
|
|
my $out;
|
|
|
|
my $n;
|
|
my $ip;
|
|
my $day = (localtime(time - 60))[3];
|
|
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
if($PC_LIST[$n]) {
|
|
if(!($ip = $PC_IP[$n])) {
|
|
if(!(gethostbyname($PC_LIST[$n]))) {
|
|
logger("DNS problem with: ", $PC_LIST[$n]);
|
|
}
|
|
$ip = inet_ntoa((gethostbyname($PC_LIST[$n]))[4]);
|
|
}
|
|
$ip =~ s/\/\d+//;
|
|
open(IN, "iptables -nxvL $PC_LIST[$n]_daily |");
|
|
while(<IN>) {
|
|
my (undef, $bytes, undef, undef, undef, undef, $source) = split(' ', $_);
|
|
if($source eq $ip) {
|
|
$out = $bytes;
|
|
}
|
|
if($source =~ /0.0.0.0/) {
|
|
$in = $bytes;
|
|
}
|
|
}
|
|
close(IN);
|
|
if(! -w $USAGE_DIR) {
|
|
logger("WARNING: directory '" . $USAGE_DIR ."' doesn't exists or is not writable.");
|
|
last;
|
|
} else {
|
|
open(OUT, ">> " . $USAGE_DIR . $PC_LIST[$n]);
|
|
print(OUT "$day $in $out\n");
|
|
close(OUT);
|
|
logger("Saved the daily traffic counter for '$PC_LIST[$n]'.") unless !$opt_d;
|
|
}
|
|
system("iptables -Z $PC_LIST[$n]_daily >/dev/null 2>/dev/null");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
sub send_reports {
|
|
my $myself = (caller(0))[3];
|
|
my $n;
|
|
my $to;
|
|
|
|
if(! -x $REPORT_DIR . "send_reports") {
|
|
logger("$myself: unable to find the script '" . $REPORT_DIR . "send_reports" . "'.");
|
|
return;
|
|
}
|
|
logger("Sending monthly traffic reports.");
|
|
for($n = 0; $n < $PC_MAX; $n++) {
|
|
if($PC_LIST[$n]) {
|
|
$to = $PC_REPORT_MAIL[$n];
|
|
$to = $PC_DEFAULT_MAIL unless $PC_REPORT_MAIL[$n];
|
|
logger("$myself: $PC_LIST[$n] -> $to [$PC_REPORT_LANG]");
|
|
system("cd $REPORT_DIR ; " . $REPORT_DIR . "send_reports -h $PC_LIST[$n] -c $opt_c &");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# Main
|
|
# ----------------------------------------------------------------------------
|
|
getopts("d:vc:p:") || usage();
|
|
|
|
if($opt_v) {
|
|
print("Monitorix version " . VERSION . " (" . RELDATE . ")\n");
|
|
print("by Jordi Sanfeliu <jordi\@fibranet.cat>\n");
|
|
print("http://www.monitorix.org/\n\n");
|
|
exit(0);
|
|
}
|
|
if(!$opt_c) {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
$opt_c = abs_path($opt_c) unless $^V lt 5.6.2;
|
|
if(!stat($opt_c)) {
|
|
die("can't open file $opt_c.\n");
|
|
}
|
|
|
|
# get the current OS and kernel branch and check its support
|
|
my $release;
|
|
($os, undef, $release) = uname();
|
|
my ($major, $minor) = split('\.', $release);
|
|
$kernel_branch = $major . "." . $minor;
|
|
if(!grep {$_ eq $os} @suppsys) {
|
|
die("FATAL: your operating system ($os) is not supported.\n");
|
|
}
|
|
|
|
# check configuration file syntax (and load it)
|
|
if(grep {$_ eq $os} ("FreeBSD", "OpenBSD", "NetBSD")) {
|
|
$SIG{'CHLD'} = 'DEFAULT';
|
|
}
|
|
if(system("perl -wc $opt_c >/dev/null 2>&1")) {
|
|
die("FATAL: configuration file '$opt_c' had compilation errors.\n");
|
|
}
|
|
require $opt_c;
|
|
|
|
|
|
$0 = sprintf("%s %s%s%s%s",
|
|
$^V lt 5.6.2 ? monitorix : abs_path($0),
|
|
$opt_c ? "-c $opt_c" : "",
|
|
$opt_p ? " -p $opt_p" : "",
|
|
$opt_d ? " -d $opt_d" : "",
|
|
$opt_v ? " -v" : "");
|
|
|
|
daemonize();
|
|
logger("Starting Monitorix version " . VERSION . " (pid $$).");
|
|
|
|
if($opt_p) {
|
|
$opt_p = abs_path($opt_p);
|
|
open(PIDFILE, "> $opt_p")
|
|
|| die("could not open $opt_p for writing");
|
|
print(PIDFILE "$$");
|
|
close(PIDFILE);
|
|
}
|
|
|
|
# change to safety directory
|
|
unless(chdir("/tmp")) {
|
|
logger("can't chdir to /tmp: $!");
|
|
unless(chdir("/lost+found")) {
|
|
die("Can't chdir to /lost+found: $!");
|
|
}
|
|
}
|
|
|
|
if($opt_d) {
|
|
if($opt_d ne "none" && $opt_d ne "all") {
|
|
@graphs_debug = split(',', $opt_d);
|
|
foreach my $t (@graphs_debug) {
|
|
if(!grep {$_ eq $t} (@GRAPH_NAME)) {
|
|
die("Invalid debug key '$t'");
|
|
}
|
|
}
|
|
}
|
|
logger("Entering in debug mode.");
|
|
logger("Changed process name to '$0'.");
|
|
}
|
|
|
|
# save the path of the configuration file
|
|
open(OUT, "> $BASE_DIR/cgi-bin/monitorix.conf.path");
|
|
print(OUT "$opt_c\n");
|
|
close(OUT);
|
|
|
|
# initialize all enabled graphs
|
|
logger("Initializing graphs.") unless !$opt_d;
|
|
flush_accounting_rules();
|
|
|
|
my $func;
|
|
foreach my $g (@GRAPH_NAME) {
|
|
if($GRAPH_ENABLE{$g} eq "Y") {
|
|
$func = $g . "_init";
|
|
eval {&$func();};
|
|
if($@) {
|
|
logger("WARNING: unexpected errors in function $func()");
|
|
}
|
|
}
|
|
}
|
|
if($PC_LAN eq "Y") {
|
|
pc_init();
|
|
}
|
|
|
|
if(!scalar(@graphs)) {
|
|
logger("nothing to do, exiting.");
|
|
exit(0);
|
|
}
|
|
|
|
# create 'index.html' file
|
|
logger("Generating the 'index.html' file.") unless !$opt_d;
|
|
create_index();
|
|
logger("Ok, done.") unless !$opt_d;
|
|
|
|
alarm(1);
|
|
while(1) {
|
|
pause();
|
|
}
|