Skip to content

Instantly share code, notes, and snippets.

@maugsburger
Forked from DirkR/duplyreport.pl
Last active November 30, 2016 19:29
Show Gist options
  • Save maugsburger/0f27031978487e4447194641213ee50d to your computer and use it in GitHub Desktop.
Save maugsburger/0f27031978487e4447194641213ee50d to your computer and use it in GitHub Desktop.
dyplyreport.pl - a duply syslog wrapper. This script runs duply (a duplicity backup wrapper), filters all the bias and writes all important information into syslog.
#!/usr/bin/env perl
# vi: sw=4 ts=4 et
# (C) 2011 Dirk Ruediger <dirk@niebegeg.net>
# (C) 2013 Moritz Augsburger
# Feel free do hack or adopt it!
#
# A syslog wrapper for duply. It runs duply for multiple profiles,
# filers "bias" out and writes all important and unexpected messages to syslog.
#
# One mail for all profiles together is generated.
#
# usage:
# Like duply. all arguments are passed to duply
#
# duplyreport.pl [--syslog|-s] [--mail|-m=<mailto>] -p profilename1 [-p profilename2 [-p…]] duply arguments
#
# etc.
# The script should not produce any output to console.
use warnings;
use strict;
use Getopt::Long qw(:config pass_through);
use Date::Format;
use Sys::Hostname;
my $procname = 'duply';
my $state = 'nostate';
my $buffer = '';
my $mailto = '';
my $syslog = 0;
my @profiles;
my $mail_content = '';
my @mail_parts;
my $msg;
my $errorcount = 0;
my $result = GetOptions (
"syslog|s" => \$syslog,
"mail|m=s" => \$mailto,
"profile|p=s" => \@profiles,
);
my $timestr = time2str('%c', time);
if( $syslog ) {
use Unix::Syslog qw(:subs :macros);
openlog "duply", LOG_PID | LOG_INFO, LOG_LOCAL0;
}
if( $mailto ne '' ) {
if ($mailto !~ m/^[A-Za-z0-9](([_\.\-\+]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$/) {
my $message = "Invalid mail address format: $mailto";
$mailto = '';
logger('error', $message);
exit 1;
} else {
use MIME::Lite;
}
}
sub logger {
my $level = shift || 'info';
my $message = shift || '';
if ($syslog) {
my $loglevel = LOG_INFO;
if ($level ne 'error') {
$loglevel = LOG_ERR;
}
syslog($loglevel, $message);
}
if ($mailto ne '') {
$mail_content .= uc($level). " $message\n";
}
}
sub sendmail {
return if $mailto eq '';
$msg = MIME::Lite->new(
To => $mailto,
Type =>'TEXT',
Data => $mail_content,
);
if ( $errorcount > 0 ) {
$msg->add('Subject', "Duply report ".$timestr." on ".hostname().": $errorcount ERRORS");
} else {
$msg->add('Subject', "Duply report ".$timestr." on ".hostname().": ALL OK");
}
$msg->attach($_) foreach( @mail_parts );
$msg->send();
}
sub mydie {
$msg = @_;
logger( 'error', $msg );
$errorcount++;
sendmail();
die $msg;
}
if( @profiles < 1 ) {
mydie("No profiles to run specified");
}
foreach (@profiles) {
my $proc;
my $profile = $_;
my $mail_proc_content = '';
my @myduplyarg;
push @myduplyarg, $profile, @ARGV;
my $localerrorcount = 0;
unless (open($proc, "LC_ALL=C $procname @myduplyarg 2>&1 |")) {
logger('error', "Could not start $procname @myduplyarg process: $!");
$localerrorcount++;
next;
}
while (<$proc>) {
$mail_proc_content .= $_;
chomp;
$localerrorcount++ if /FAILED/;
next if
/^(Using|Autoset|Test -|Cleanup -|Deleting local) / ||
/^Skipping n\/a script / ||
/^Reading globbing filelist / ||
/^Synchronizing remote metadata to local cache/ ||
/^Local and Remote metadata are synchronized, no sync needed/ ||
/^Generating delta - (new|deleted|changed) file/ ||
/^-+\[ Backup Statistics \]-+/ ||
/^gpg: Signature made / ||
/^NcFTP version is [0-9.]+/ ||
/^(StartTime|EndTime|ElapsedTime|SourceFiles|NewFileSize|ChangedFileSize|ChangedDeltaSize|DeltaEntries|RawDeltaSize|Errors) [0-9.]+/ ||
/^WARNING:$/ ||
/^(Duplicity version '[0-9.]+' does not support providing the password as|env var for rsync backend. For security reasons you should consider to|update to a version greater than '[0-9.]+' of duplicity.)/ ||
/^Verify complete: \d+ files compared, 0 differences found/ ||
/^Copying duplicity\S* to local cache/ ||
/^Skipping n\/a script '\S+\/(pre|post)'\./ ||
/^Running '\/\S+\/(pre|post)' - OK/ ||
/File descriptor.*leaked on lvcreate invocation\./ ||
/Logical volume ".*" (created|successfully removed)/;
s/^--- //;
s/ at [0-9:.]+ - Runtime [0-9:.-]+ ---//;
next if /^\s*$/;
if (m/^Start duply/) {
logger('info', "**Start 'duply @myduplyarg'**");
next;
}
if (m/^(Changed|New|Deleted)Files (\d+)/) {
$buffer .= ", $1: $2";
next;
}
# TotalDestinationSizeChange 1587367 (1.51 MB)
if (m/^TotalDestinationSizeChange.*\(([0-9.]+) ([MGK]B)\)/) {
$buffer = "DiffSize=$1$2, $buffer";
next;
}
if (m/^SourceFileSize.*\(([0-9.]+) ([MGK]B)\)/) {
$buffer = "Size=$1$2$buffer";
next;
}
if (m/^Start running command ([A-Z]+).*/) {
$state = $1;
next;
}
if (m/^No old backup sets found, nothing deleted/ && ($state eq 'PURGE')) {
next;
}
if (m/^Last full backup date/ && ($state eq 'PURGE' || $state eq 'VERIFY')) {
next;
}
if (m/Verify complete: \d+ files compared, 0 differences found/ && ($state eq 'VERIFY')) {
next;
}
if (m/^Finished state OK/) {
next;
}
if (m/^---+$/) {
logger('info', "[$state] $buffer");
$buffer = '';
next;
}
logger('info', "[$state] $_");
}
close($proc);
if ($? > 0) {
logger('error', "$procname @myduplyarg exited with: $?");
$localerrorcount++;
} elsif ($localerrorcount > 0) {
logger('error', "$procname @myduplyarg had $localerrorcount errors");
} else {
$mail_content .= "$procname @myduplyarg successfully terminated\n";
}
$mail_content .= "\n";
$errorcount += $localerrorcount;
if ( $mailto ne '' ) {
push @mail_parts, MIME::Lite->new(
Type => 'TEXT',
Data => $mail_proc_content,
Filename => "$procname $profile @ARGV",
Disposition => 'attachment',
Top => 0,
);
}
}
if ($syslog) {
closelog;
}
sendmail();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment