mirror of https://github.com/digint/btrbk
btrbk: add transaction logging to syslog
Add configuration option transaction_syslog, which can be set to a short name of a syslog facility, like user or local5. Most of the ones besides localX do not really make sense, but whatever, let the user decide. The only logging that is relevant for logging to syslog is the logging generated inside sub action, so it's easy to hijack all messages in there and also send them to syslog if needed. All output is done via print_formatted, which expects a file handle. So, abuse a file handle to a string to be able to change as less code as needed for this feature. Since syslog already adds the timestamps for us, I added a syslog formatting pattern, which is very similar to tlog, omitting the timestap.pull/88/head
parent
81feb41619
commit
59d96420c8
|
@ -2,6 +2,7 @@ btrbk-current
|
||||||
|
|
||||||
* Bugfix: set correct parent section when propagating targets
|
* Bugfix: set correct parent section when propagating targets
|
||||||
(close: #85).
|
(close: #85).
|
||||||
|
* Add syslog output for transaction log.
|
||||||
|
|
||||||
btrbk-0.23.0
|
btrbk-0.23.0
|
||||||
|
|
||||||
|
|
39
btrbk
39
btrbk
|
@ -45,6 +45,8 @@ use warnings FATAL => qw( all );
|
||||||
use Carp qw(confess);
|
use Carp qw(confess);
|
||||||
use Getopt::Long qw(GetOptions);
|
use Getopt::Long qw(GetOptions);
|
||||||
use Time::Local qw( timelocal timegm timegm_nocheck );
|
use Time::Local qw( timelocal timegm timegm_nocheck );
|
||||||
|
use Sys::Syslog;
|
||||||
|
use Sys::Syslog qw(:standard :macros);
|
||||||
|
|
||||||
our $VERSION = "0.23.1-dev";
|
our $VERSION = "0.23.1-dev";
|
||||||
our $AUTHOR = 'Axel Burri <axel@tty0.ch>';
|
our $AUTHOR = 'Axel Burri <axel@tty0.ch>';
|
||||||
|
@ -69,6 +71,11 @@ my $ssh_cipher_match = qr/[a-z0-9][a-z0-9@.-]+/;
|
||||||
my $safe_cmd_match = qr/[0-9a-zA-Z_@=\+\-\.\/]+/; # $file_match plus '=': good enough for our purpose
|
my $safe_cmd_match = qr/[0-9a-zA-Z_@=\+\-\.\/]+/; # $file_match plus '=': good enough for our purpose
|
||||||
|
|
||||||
my %day_of_week_map = ( sunday => 0, monday => 1, tuesday => 2, wednesday => 3, thursday => 4, friday => 5, saturday => 6 );
|
my %day_of_week_map = ( sunday => 0, monday => 1, tuesday => 2, wednesday => 3, thursday => 4, friday => 5, saturday => 6 );
|
||||||
|
my %syslog_facility_map = (
|
||||||
|
user => LOG_USER, mail => LOG_MAIL, daemon => LOG_DAEMON, auth => LOG_AUTH, lpr => LOG_LPR, news => LOG_NEWS,
|
||||||
|
cron => LOG_CRON, authpriv => LOG_AUTHPRIV, local0 => LOG_LOCAL0, local1 => LOG_LOCAL1, local2 => LOG_LOCAL2,
|
||||||
|
local3 => LOG_LOCAL3, local4 => LOG_LOCAL4, local5 => LOG_LOCAL5, local6 => LOG_LOCAL6, local7 => LOG_LOCAL7,
|
||||||
|
);
|
||||||
|
|
||||||
my %config_options = (
|
my %config_options = (
|
||||||
# NOTE: the parser always maps "no" to undef
|
# NOTE: the parser always maps "no" to undef
|
||||||
|
@ -94,6 +101,7 @@ my %config_options = (
|
||||||
ssh_cipher_spec => { default => "default", accept_regexp => qr/^$ssh_cipher_match(,$ssh_cipher_match)*$/ },
|
ssh_cipher_spec => { default => "default", accept_regexp => qr/^$ssh_cipher_match(,$ssh_cipher_match)*$/ },
|
||||||
rate_limit => { default => undef, accept => [ "no" ], accept_regexp => qr/^[0-9]+[kmgt]?$/, require_bin => '/usr/bin/pv' },
|
rate_limit => { default => undef, accept => [ "no" ], accept_regexp => qr/^[0-9]+[kmgt]?$/, require_bin => '/usr/bin/pv' },
|
||||||
transaction_log => { default => undef, accept_file => { absolute => 1 } },
|
transaction_log => { default => undef, accept_file => { absolute => 1 } },
|
||||||
|
transaction_syslog => { default => undef, accept => [ keys %syslog_facility_map ] },
|
||||||
|
|
||||||
raw_target_compress => { default => undef, accept => [ "no", "gzip", "bzip2", "xz" ] },
|
raw_target_compress => { default => undef, accept => [ "no", "gzip", "bzip2", "xz" ] },
|
||||||
raw_target_compress_level => { default => "default", accept => [ "default" ], accept_numeric => 1 },
|
raw_target_compress_level => { default => "default", accept => [ "default" ], accept_numeric => 1 },
|
||||||
|
@ -178,6 +186,7 @@ my %table_formats = (
|
||||||
long => [ qw( localtime type status duration target_host target_subvol source_host source_subvol parent_subvol message ) ],
|
long => [ qw( localtime type status duration target_host target_subvol source_host source_subvol parent_subvol message ) ],
|
||||||
raw => [ qw( time localtime type status duration target_url source_url parent_url message ) ],
|
raw => [ qw( time localtime type status duration target_url source_url parent_url message ) ],
|
||||||
tlog => [ qw( localtime type status duration target_url source_url parent_url message ) ],
|
tlog => [ qw( localtime type status duration target_url source_url parent_url message ) ],
|
||||||
|
syslog => [ qw( type status duration target_url source_url parent_url message ) ],
|
||||||
},
|
},
|
||||||
|
|
||||||
origin_tree => { table => [ qw( tree uuid parent_uuid received_uuid ) ],
|
origin_tree => { table => [ qw( tree uuid parent_uuid received_uuid ) ],
|
||||||
|
@ -202,6 +211,7 @@ my $err = "";
|
||||||
my $abrt = ""; # last ABORTED() message
|
my $abrt = ""; # last ABORTED() message
|
||||||
my $output_format;
|
my $output_format;
|
||||||
my $tlog_fh;
|
my $tlog_fh;
|
||||||
|
my $syslog_facility;
|
||||||
my $current_transaction;
|
my $current_transaction;
|
||||||
my @transaction_log;
|
my @transaction_log;
|
||||||
my %config_override;
|
my %config_override;
|
||||||
|
@ -319,7 +329,7 @@ sub ABORTED($;$)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub init_transaction_log($)
|
sub init_transaction_log($$)
|
||||||
{
|
{
|
||||||
my $file = shift;
|
my $file = shift;
|
||||||
if(defined($file) && (not $dryrun)) {
|
if(defined($file) && (not $dryrun)) {
|
||||||
|
@ -332,6 +342,11 @@ sub init_transaction_log($)
|
||||||
ERROR "Failed to open transaction log '$file': $!";
|
ERROR "Failed to open transaction log '$file': $!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
my $config_syslog_facility = shift;
|
||||||
|
if(defined($config_syslog_facility) && (not $dryrun)) {
|
||||||
|
$syslog_facility = $syslog_facility_map{$config_syslog_facility};
|
||||||
|
openlog("btrbk", 0, $syslog_facility);
|
||||||
|
}
|
||||||
action("startup", status => "v$VERSION", message => "$VERSION_INFO");
|
action("startup", status => "v$VERSION", message => "$VERSION_INFO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,6 +356,7 @@ sub close_transaction_log()
|
||||||
DEBUG "Closing transaction log";
|
DEBUG "Closing transaction log";
|
||||||
close $tlog_fh || ERROR "Failed to close transaction log: $!";
|
close $tlog_fh || ERROR "Failed to close transaction log: $!";
|
||||||
}
|
}
|
||||||
|
closelog if defined $syslog_facility;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub action($@)
|
sub action($@)
|
||||||
|
@ -352,6 +368,16 @@ sub action($@)
|
||||||
$h->{time} = $time;
|
$h->{time} = $time;
|
||||||
$h->{localtime} = timestamp($time, 'debug-iso');
|
$h->{localtime} = timestamp($time, 'debug-iso');
|
||||||
print_formatted("transaction", [ $h ], output_format => "tlog", no_header => 1, outfile => $tlog_fh) if($tlog_fh);
|
print_formatted("transaction", [ $h ], output_format => "tlog", no_header => 1, outfile => $tlog_fh) if($tlog_fh);
|
||||||
|
if (defined($syslog_facility)) {
|
||||||
|
my $msg = q{};
|
||||||
|
open my $msg_fh, '+<', \$msg;
|
||||||
|
print_formatted("transaction", [ $h ], output_format => "syslog", no_header => 1, outfile => $msg_fh);
|
||||||
|
seek($msg_fh, 0, 0);
|
||||||
|
while (my $line = <$msg_fh>) {
|
||||||
|
syslog(LOG_INFO, $line);
|
||||||
|
}
|
||||||
|
close $msg_fh;
|
||||||
|
}
|
||||||
push @transaction_log, $h;
|
push @transaction_log, $h;
|
||||||
return $h;
|
return $h;
|
||||||
}
|
}
|
||||||
|
@ -3162,7 +3188,7 @@ sub print_formatted(@)
|
||||||
print $fh join(' ', map { "$_=\"" . ($row->{$_} // "") . "\""; } @$keys) . "\n";
|
print $fh join(' ', map { "$_=\"" . ($row->{$_} // "") . "\""; } @$keys) . "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif($format eq "tlog")
|
elsif($format eq "tlog" || $format eq "syslog")
|
||||||
{
|
{
|
||||||
# output: value0 value1, ...
|
# output: value0 value1, ...
|
||||||
unless($args{no_header}) {
|
unless($args{no_header}) {
|
||||||
|
@ -3619,7 +3645,8 @@ MAIN:
|
||||||
# thing used from the configuration is the SSH and transaction log
|
# thing used from the configuration is the SSH and transaction log
|
||||||
# stuff.
|
# stuff.
|
||||||
#
|
#
|
||||||
init_transaction_log(config_key($config, "transaction_log"));
|
init_transaction_log(config_key($config, "transaction_log"),
|
||||||
|
config_key($config, "transaction_syslog"));
|
||||||
|
|
||||||
my $src_url = $filter_args[0] || die;
|
my $src_url = $filter_args[0] || die;
|
||||||
my $archive_url = $filter_args[1] || die;
|
my $archive_url = $filter_args[1] || die;
|
||||||
|
@ -4518,7 +4545,8 @@ MAIN:
|
||||||
#
|
#
|
||||||
# identify and delete incomplete backups
|
# identify and delete incomplete backups
|
||||||
#
|
#
|
||||||
init_transaction_log(config_key($config, "transaction_log"));
|
init_transaction_log(config_key($config, "transaction_log"),
|
||||||
|
config_key($config, "transaction_syslog"));
|
||||||
|
|
||||||
my @out;
|
my @out;
|
||||||
foreach my $sroot (vinfo_subsection($config, 'volume')) {
|
foreach my $sroot (vinfo_subsection($config, 'volume')) {
|
||||||
|
@ -4615,7 +4643,8 @@ MAIN:
|
||||||
|
|
||||||
if($action_run)
|
if($action_run)
|
||||||
{
|
{
|
||||||
init_transaction_log(config_key($config, "transaction_log"));
|
init_transaction_log(config_key($config, "transaction_log"),
|
||||||
|
config_key($config, "transaction_syslog"));
|
||||||
|
|
||||||
if($resume_only) {
|
if($resume_only) {
|
||||||
INFO "Skipping snapshot creation (option \"-r\" present)";
|
INFO "Skipping snapshot creation (option \"-r\" present)";
|
||||||
|
|
|
@ -75,6 +75,15 @@ subvolume delete) as well as abort messages are logged to <file>, in a
|
||||||
space-separated table format.
|
space-separated table format.
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
\fBtransaction_syslog\fR <facility>
|
||||||
|
.RS 4
|
||||||
|
If set, all transactions (snapshot create, subvolume send-receive,
|
||||||
|
subvolume delete) as well as abort messages are logged to syslog, in a
|
||||||
|
space-separated format. The facility parameter accepts a short
|
||||||
|
lowercase syslog facility name, like \[lq]daemon\[rq] or \[lq]local7\[rq].
|
||||||
|
The program name used in the messages is "btrbk".
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
\fBtimestamp_format\fR short|long|long-iso
|
\fBtimestamp_format\fR short|long|long-iso
|
||||||
.RS 4
|
.RS 4
|
||||||
Timestamp format used as postfix for new snapshot subvolume
|
Timestamp format used as postfix for new snapshot subvolume
|
||||||
|
|
Loading…
Reference in New Issue