|
package Catcher; |
|
|
|
use strict; |
|
use warnings; |
|
use Carp; |
|
use Carp qw (cluck); |
|
use File::Basename; |
|
use POSIX qw(strftime); |
|
|
|
# Nagios error levels |
|
use constant { |
|
NG_OK => 0, |
|
NG_WARNING => 1, |
|
NG_CRITICAL => 2, |
|
NG_UNKNOWN => 3 |
|
}; |
|
|
|
our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $NG_REPORT_DIRECTORY); |
|
my ($NG_REPORT_FILENAME); |
|
|
|
# Private (internals) |
|
# Recommended settings |
|
my $_SUCCESS = 0; |
|
my $_ERROR = 0; |
|
my $_LEVEL = NG_OK; |
|
my $_DISABLE_WARNINGS = 0; |
|
my $_STOP_ON_WARNING = 0; |
|
|
|
|
|
# Internal |
|
sub _warn { |
|
if(!$_DISABLE_WARNINGS) { |
|
$_ERROR = $_[0]; |
|
$_LEVEL = NG_WARNING; |
|
$_SUCCESS = 0; |
|
if($_STOP_ON_WARNING) { |
|
die $_[0]; |
|
} else { |
|
warn $_[0]; |
|
} |
|
} |
|
} |
|
|
|
# Exported |
|
sub ERROR { |
|
$_ERROR = shift; |
|
$_LEVEL = NG_CRITICAL; |
|
$_SUCCESS = 0; |
|
die $_ERROR; |
|
} |
|
|
|
BEGIN { |
|
require Exporter; |
|
our $VERSION = "1.0.0"; |
|
our @ISA = qw(Exporter); |
|
# Exported by default |
|
our @EXPORT = qw(ERROR END_PROGRAM warningsOn warningsOff dieOnWarn setNagiosFilename setSuccessMessage); |
|
# Can be optionally exported |
|
our @EXPORT_OK = qw(trace $NG_REPORT_DIRECTORY); |
|
# Tags |
|
our %EXPORT_TAGS = ( |
|
ReportVars => [qw(reportVar incVar setReportVars)] |
|
); |
|
# Resulting @EXPORT_OK is @EXPORT_OK = qw(trace $NG_REPORT_DIRECTORY reportVar incVar setReportVars); |
|
Exporter::export_ok_tags('ReportVars'); |
|
|
|
# Guess the default Nagios report filename |
|
$NG_REPORT_FILENAME = basename($0, '.pl'); |
|
# Destination folder for the .nagios file |
|
# Can be accessed and modified (for tests) although it is discouraged to it. |
|
$NG_REPORT_DIRECTORY = "/var/log/apps"; |
|
|
|
# Catch DIE signals |
|
$SIG{__DIE__} = sub { ERROR $_[0] }; |
|
# Catch WARN signals |
|
$SIG{__WARN__} = sub { _warn $_[0] }; |
|
} |
|
|
|
# Nagios reporting variables |
|
my %report_vars = (); |
|
my $success_message = "OK Execution normale"; |
|
|
|
# Exported |
|
# Setter for the nagios report filename |
|
sub setNagiosFilename { |
|
($NG_REPORT_FILENAME) = shift; |
|
} |
|
|
|
# Exported |
|
# A program must finish with this instruction. |
|
sub END_PROGRAM { |
|
($_) = @_; |
|
if(defined $_) { |
|
setSuccessMessage($_); |
|
} |
|
if(!$_ERROR && !$_LEVEL) { |
|
$_SUCCESS = 1; |
|
} |
|
} |
|
|
|
# Exported |
|
# When warnings are enabled, the last warning will be reported (if there is no error). |
|
sub warningsOn { |
|
$_DISABLE_WARNINGS = 0; |
|
} |
|
|
|
# Exported |
|
# When warnings are disabled, the errors of "warn" level are totally ignored, but still printed. |
|
sub warningsOff { |
|
$_DISABLE_WARNINGS = 1; |
|
} |
|
|
|
# Exported |
|
# Trigger die when __WARN__ is encountered. |
|
# It transforms the first warn instruction into a die instruction. |
|
sub dieOnWarn { |
|
($_STOP_ON_WARNING) = shift; |
|
} |
|
|
|
### Variables management |
|
# Variable can be defined in order to be reported in Nagios |
|
# Add a variable |
|
sub reportVar { |
|
my ($key, $value) = @_; |
|
$report_vars{$key} = $value; |
|
} |
|
|
|
sub getReportVar { |
|
my ($key) = @_; |
|
return $report_vars{$key}; |
|
} |
|
|
|
sub incVar { |
|
my ($key) = @_; |
|
$report_vars{$key}++; |
|
} |
|
|
|
sub setReportVars { |
|
%report_vars = @_; |
|
} |
|
|
|
sub setSuccessMessage { |
|
($success_message) = @_; |
|
} |
|
|
|
# Exportable |
|
sub trace { |
|
my (@args) = shift(); |
|
foreach my $line (@args) { |
|
print "$line\n"; |
|
} |
|
} |
|
|
|
# Private |
|
my $sanitizePath = sub { |
|
($_) = @_; |
|
# hack for not removing last directory |
|
$_ = "$_/."; |
|
# Is the destination directory exist ? |
|
unless(-e) { croak "Directory $_ does not exist !" } |
|
return dirname($_); |
|
}; |
|
my $writeReport = sub { |
|
my $dest = &$sanitizePath($NG_REPORT_DIRECTORY)."/".$NG_REPORT_FILENAME.".nagios"; |
|
my $safeError; |
|
if($_SUCCESS) { |
|
$safeError = $success_message; |
|
} else { |
|
$safeError = $_ERROR; |
|
} |
|
# Delete special chars |
|
$safeError =~ s/[\|,]+/\-/g; |
|
# Keep the first line |
|
my @safeErrorArray = split("\n", $safeError); |
|
$safeError = $safeErrorArray[0]; |
|
my $content = (strftime "%F-%T", localtime).",$_LEVEL,$safeError"; |
|
# Construct vars restitution |
|
my @reportVars = (); |
|
while (my($k, $v) = each(%report_vars)) { |
|
push @reportVars, "$k=$v"; |
|
} |
|
my $reportVarsString = join ' ; ', @reportVars; |
|
if(length($reportVarsString)) { |
|
$content .= " | ".$reportVarsString; |
|
} |
|
open REPORT, ">".$dest; |
|
print REPORT $content; |
|
close REPORT; |
|
}; |
|
|
|
END { |
|
&$writeReport(); |
|
if(!$_SUCCESS) { |
|
if($_LEVEL == NG_WARNING) { |
|
trace "WARNING : $_ERROR"; |
|
} elsif($_LEVEL == NG_CRITICAL) { |
|
trace "CRITICAL : $_ERROR"; |
|
} elsif($_LEVEL == NG_UNKNOWN) { |
|
trace "UNKNOWN : $_ERROR"; |
|
} |
|
exit(1); |
|
} else { |
|
trace "SUCCESS"; |
|
exit(0); |
|
} |
|
}; |
|
|
|
|
|
|
|
1; |
|
__END__ |
|
=head1 NAME |
|
|
|
Catcher - Perl extension for error handling |
|
|
|
=head1 SYNOPSIS |
|
|
|
use Catcher; |
|
#...some piece of code |
|
END_PROGRAM; |
|
|
|
# Declare errors with custom message |
|
use Catcher; |
|
ERROR "Custom error !"; |
|
# the program ends here |
|
END_PROGRAM; |
|
|
|
# Warning handling for Nagios can be disabled for ugly scripts |
|
use Catcher; |
|
warningsOff; |
|
END_PROGRAM; |
|
|
|
# Warnings can be temporarly disabled |
|
use Catcher; |
|
warningsOff; |
|
# ugly instructions |
|
warningsOn; |
|
# supposed safe instructions |
|
END_PROGRAM; |
|
|
|
# For critical scripts, a warning can trigger an error |
|
use Catcher; |
|
dieOnWarn(1); |
|
# critical instructions |
|
END_PROGRAM; |
|
|
|
# Reporting variable can be defined |
|
use Catcher; |
|
use Catcher qw(ReportVars); |
|
reportVar('user_creation', 0); |
|
incVar('user_creation'); |
|
incVar('user_creation'); |
|
incVar('user_creation'); |
|
reportVar('user_modification', 0); |
|
END_PROGRAM; |
|
|
|
# Reporting variables can be defined in a foreign hash |
|
use Catcher; |
|
use Catcher qw(:ReportVars); |
|
%vars = ( |
|
user_creation => 4, |
|
user_modification => 2 |
|
); |
|
setReportVars(%vars); |
|
END_PROGRAM; |
|
|
|
# Customise the success message |
|
use Catcher; |
|
END_PROGRAM("Custom message"); |
|
|
|
# Customise the success message (other method) |
|
use Catcher; |
|
# foo... |
|
setSuccessMessage("foo ok"); |
|
# bar... |
|
setSuccessMessage("bar ok"); |
|
END_PROGRAM; |
|
|
|
|