1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/lib/pgBackRest/Common/Log.pm

712 lines
25 KiB
Perl
Raw Normal View History

2014-02-03 03:03:05 +03:00
####################################################################################################################################
# COMMON LOG MODULE
2014-02-03 03:03:05 +03:00
####################################################################################################################################
New simpler configuration and consistent project/exe/path naming. * The repo-path option now always refers to the repository where backups and archive are stored, whether local or remote, so the repo-remote-path option has been removed. The new spool-path option can be used to define a location for queueing WAL segments when archiving asynchronously. Otherwise, a local repository is no longer required. * Implemented a new config format which should be far simpler to use. See the User Guide and Configuration Reference for details but for a simple configuration all options can now be placed in the stanza section. Options that are shared between stanzas can be placed in the [global] section. More complex configurations can still make use of command sections though this should be a rare use case. * The default configuration filename is now pgbackrest.conf instead of pg_backrest.conf. This was done for consistency with other naming changes but also to prevent old config files from being loaded accidentally. * The default repository name was changed from /var/lib/backup to /var/lib/pgbackrest. * Lock files are now stored in /tmp/pgbackrest by default. These days /run/pgbackrest would be the preferred location but that would require init scripts which are not part of this release. The lock-path option can be used to configure the lock directory. * Log files are now stored in /var/log/pgbackrest by default and no longer have the date appended so they can be managed with logrotate. The log-path option can be used to configure the lock directory. * Executable filename changed from pg_backrest to pgbackrest.
2016-04-14 15:30:54 +02:00
package pgBackRest::Common::Log;
2014-02-03 03:03:05 +03:00
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess longmess);
2014-07-28 01:13:23 +03:00
use Exporter qw(import);
our @EXPORT = qw();
use Fcntl qw(:DEFAULT :flock);
use File::Basename qw(dirname);
use Scalar::Util qw(blessed reftype);
use Time::HiRes qw(gettimeofday usleep);
2014-06-07 18:51:27 +03:00
New simpler configuration and consistent project/exe/path naming. * The repo-path option now always refers to the repository where backups and archive are stored, whether local or remote, so the repo-remote-path option has been removed. The new spool-path option can be used to define a location for queueing WAL segments when archiving asynchronously. Otherwise, a local repository is no longer required. * Implemented a new config format which should be far simpler to use. See the User Guide and Configuration Reference for details but for a simple configuration all options can now be placed in the stanza section. Options that are shared between stanzas can be placed in the [global] section. More complex configurations can still make use of command sections though this should be a rare use case. * The default configuration filename is now pgbackrest.conf instead of pg_backrest.conf. This was done for consistency with other naming changes but also to prevent old config files from being loaded accidentally. * The default repository name was changed from /var/lib/backup to /var/lib/pgbackrest. * Lock files are now stored in /tmp/pgbackrest by default. These days /run/pgbackrest would be the preferred location but that would require init scripts which are not part of this release. The lock-path option can be used to configure the lock directory. * Log files are now stored in /var/log/pgbackrest by default and no longer have the date appended so they can be managed with logrotate. The log-path option can be used to configure the lock directory. * Executable filename changed from pg_backrest to pgbackrest.
2016-04-14 15:30:54 +02:00
use pgBackRest::Common::Exception;
use pgBackRest::Common::String;
2014-02-03 03:03:05 +03:00
####################################################################################################################################
# Boolean constants
####################################################################################################################################
use constant true => 1;
push @EXPORT, qw(true);
use constant false => 0;
push @EXPORT, qw(false);
2014-02-14 01:11:53 +03:00
####################################################################################################################################
# Log level constants
####################################################################################################################################
use constant TRACE => 'TRACE';
push @EXPORT, qw(TRACE);
use constant DEBUG => 'DEBUG';
push @EXPORT, qw(DEBUG);
use constant DETAIL => 'DETAIL';
push @EXPORT, qw(DETAIL);
use constant INFO => 'INFO';
push @EXPORT, qw(INFO);
use constant WARN => 'WARN';
push @EXPORT, qw(WARN);
use constant PROTOCOL => 'PROTOCOL';
push @EXPORT, qw(PROTOCOL);
use constant ERROR => 'ERROR';
push @EXPORT, qw(ERROR);
use constant ASSERT => 'ASSERT';
push @EXPORT, qw(ASSERT);
use constant OFF => 'OFF';
push @EXPORT, qw(OFF);
2014-02-14 01:11:53 +03:00
####################################################################################################################################
# Log levels ranked by severity
####################################################################################################################################
my %oLogLevelRank;
$oLogLevelRank{TRACE}{rank} = 8;
$oLogLevelRank{DEBUG}{rank} = 7;
$oLogLevelRank{DETAIL}{rank} = 6;
$oLogLevelRank{INFO}{rank} = 5;
$oLogLevelRank{WARN}{rank} = 4;
$oLogLevelRank{PROTOCOL}{rank} = 3;
$oLogLevelRank{ERROR}{rank} = 2;
$oLogLevelRank{ASSERT}{rank} = 1;
2014-02-14 01:11:53 +03:00
$oLogLevelRank{OFF}{rank} = 0;
2014-02-13 21:54:43 +03:00
2014-07-28 01:13:23 +03:00
####################################################################################################################################
# Module globals
2014-07-28 01:13:23 +03:00
####################################################################################################################################
my $hLogFile = undef;
my $strLogFileCache = undef;
my $strLogLevelFile = OFF;
my $strLogLevelConsole = OFF;
my $strLogLevelStdErr = WARN;
2014-07-28 01:13:23 +03:00
# Test globals
2014-07-28 01:13:23 +03:00
my $bTest = false;
2015-01-25 19:20:12 +02:00
my $fTestDelay;
my $oTestPoint;
2014-07-28 01:13:23 +03:00
####################################################################################################################################
# Test constants
####################################################################################################################################
use constant TEST => 'TEST';
push @EXPORT, qw(TEST);
use constant TEST_ENCLOSE => 'PgBaCkReStTeSt';
push @EXPORT, qw(TEST_ENCLOSE);
use constant TEST_MANIFEST_BUILD => 'MANIFEST-BUILD';
push @EXPORT, qw(TEST_MANIFEST_BUILD);
use constant TEST_BACKUP_RESUME => 'BACKUP-RESUME';
push @EXPORT, qw(TEST_BACKUP_RESUME);
use constant TEST_BACKUP_NORESUME => 'BACKUP-NORESUME';
push @EXPORT, qw(TEST_BACKUP_NORESUME);
use constant TEST_BACKUP_START => 'BACKUP-START';
push @EXPORT, qw(TEST_BACKUP_START);
use constant TEST_BACKUP_STOP => 'BACKUP-STOP';
push @EXPORT, qw(TEST_BACKUP_STOP);
use constant TEST_KEEP_ALIVE => 'KEEP_ALIVE';
push @EXPORT, qw(TEST_KEEP_ALIVE);
use constant TEST_ARCHIVE_PUSH_ASYNC_START => 'ARCHIVE-PUSH-ASYNC-START';
push @EXPORT, qw(TEST_ARCHIVE_PUSH_ASYNC_START);
2014-02-03 03:03:05 +03:00
####################################################################################################################################
# logFileSet - set the file messages will be logged to
2014-02-03 03:03:05 +03:00
####################################################################################################################################
sub logFileSet
2014-02-03 03:03:05 +03:00
{
my $strFile = shift;
2014-06-04 05:02:56 +03:00
# Only open the log file if file logging is enabled
if ($strLogLevelFile ne OFF)
2014-02-03 03:03:05 +03:00
{
filePathCreate(dirname($strFile), '0770', true, true);
2014-02-03 03:03:05 +03:00
New simpler configuration and consistent project/exe/path naming. * The repo-path option now always refers to the repository where backups and archive are stored, whether local or remote, so the repo-remote-path option has been removed. The new spool-path option can be used to define a location for queueing WAL segments when archiving asynchronously. Otherwise, a local repository is no longer required. * Implemented a new config format which should be far simpler to use. See the User Guide and Configuration Reference for details but for a simple configuration all options can now be placed in the stanza section. Options that are shared between stanzas can be placed in the [global] section. More complex configurations can still make use of command sections though this should be a rare use case. * The default configuration filename is now pgbackrest.conf instead of pg_backrest.conf. This was done for consistency with other naming changes but also to prevent old config files from being loaded accidentally. * The default repository name was changed from /var/lib/backup to /var/lib/pgbackrest. * Lock files are now stored in /tmp/pgbackrest by default. These days /run/pgbackrest would be the preferred location but that would require init scripts which are not part of this release. The lock-path option can be used to configure the lock directory. * Log files are now stored in /var/log/pgbackrest by default and no longer have the date appended so they can be managed with logrotate. The log-path option can be used to configure the lock directory. * Executable filename changed from pg_backrest to pgbackrest.
2016-04-14 15:30:54 +02:00
$strFile .= '.log';
my $bExists = false;
2014-06-04 05:02:56 +03:00
if (-e $strFile)
{
$bExists = true;
}
2014-02-03 03:03:05 +03:00
$hLogFile = fileOpen($strFile, O_WRONLY | O_CREAT | O_APPEND, '0660');
2014-02-03 03:03:05 +03:00
if ($bExists)
{
syswrite($hLogFile, "\n");
}
2014-05-27 16:00:24 +03:00
syswrite($hLogFile, "-------------------PROCESS START-------------------\n");
# Write out anything that was cached before the file was opened
if (defined($strLogFileCache))
{
syswrite($hLogFile, $strLogFileCache);
undef($strLogFileCache);
}
}
2014-02-03 03:03:05 +03:00
}
push @EXPORT, qw(logFileSet);
2015-01-25 19:20:12 +02:00
####################################################################################################################################
# logLevelSet - set the log level for file and console
####################################################################################################################################
sub logLevelSet
{
my $strLevelFileParam = shift;
my $strLevelConsoleParam = shift;
my $strLevelStdErrParam = shift;
2014-06-04 05:02:56 +03:00
# Load FileCommon module
require pgBackRest::FileCommon;
pgBackRest::FileCommon->import();
if (defined($strLevelFileParam))
{
if (!defined($oLogLevelRank{uc($strLevelFileParam)}{rank}))
{
confess &log(ERROR, "file log level ${strLevelFileParam} does not exist");
}
2014-06-04 05:02:56 +03:00
$strLogLevelFile = uc($strLevelFileParam);
2014-02-13 21:54:43 +03:00
}
if (defined($strLevelConsoleParam))
2014-02-13 21:54:43 +03:00
{
if (!defined($oLogLevelRank{uc($strLevelConsoleParam)}{rank}))
{
confess &log(ERROR, "console log level ${strLevelConsoleParam} does not exist");
}
2014-02-13 21:54:43 +03:00
$strLogLevelConsole = uc($strLevelConsoleParam);
2014-02-13 21:54:43 +03:00
}
if (defined($strLevelStdErrParam))
{
if (!defined($oLogLevelRank{uc($strLevelStdErrParam)}{rank}))
{
confess &log(ERROR, "stdout log level ${strLevelStdErrParam} does not exist");
}
$strLogLevelStdErr = uc($strLevelStdErrParam);
}
2014-02-13 21:54:43 +03:00
}
push @EXPORT, qw(logLevelSet);
2014-02-03 03:03:05 +03:00
####################################################################################################################################
# logDebugParam
#
# Log parameters passed to functions.
2014-02-03 03:03:05 +03:00
####################################################################################################################################
use constant DEBUG_PARAM => '()';
sub logDebugParam
2014-02-03 03:03:05 +03:00
{
my $strFunction = shift;
my $oyParamRef = shift;
2014-06-04 05:02:56 +03:00
return logDebugProcess($strFunction, DEBUG_PARAM, undef, $oyParamRef, @_);
}
2014-06-04 05:02:56 +03:00
push @EXPORT, qw(logDebugParam);
####################################################################################################################################
# logDebugReturn
#
# Log values returned from functions.
####################################################################################################################################
use constant DEBUG_RETURN => '=>';
2014-02-03 03:03:05 +03:00
sub logDebugReturn
{
my $strFunction = shift;
return logDebugProcess($strFunction, DEBUG_RETURN, undef, undef, @_);
}
push @EXPORT, qw(logDebugReturn);
####################################################################################################################################
# logDebugMisc
#
# Log misc values and details during execution.
####################################################################################################################################
use constant DEBUG_MISC => '';
sub logDebugMisc
{
my $strFunction = shift;
my $strDetail = shift;
return logDebugProcess($strFunction, DEBUG_MISC, $strDetail, undef, @_);
2014-02-13 21:54:43 +03:00
}
push @EXPORT, qw(logDebugMisc);
2014-02-13 21:54:43 +03:00
####################################################################################################################################
# logDebugProcess
2014-02-13 21:54:43 +03:00
####################################################################################################################################
sub logDebugProcess
2014-02-13 21:54:43 +03:00
{
my $strFunction = shift;
my $strType = shift;
my $strDetail = shift;
my $oyParamRef = shift;
2014-02-14 01:11:53 +03:00
my $iIndex = 0;
my $oParamHash = {};
my @oyResult;
my $bLogTrace = true;
2014-02-14 01:11:53 +03:00
if ($strType eq DEBUG_PARAM)
2014-02-13 21:54:43 +03:00
{
push @oyResult, $strFunction;
2014-02-13 21:54:43 +03:00
}
2014-02-14 01:11:53 +03:00
# Process each parameter hash
my $oParam = shift;
2014-02-14 01:11:53 +03:00
# Strip the package name off strFunction if it's pgBackRest
$strFunction =~ s/^pgBackRest[^\:]*\:\://;
while (defined($oParam))
2014-02-13 21:54:43 +03:00
{
my $strParamName = $$oParam{name};
my $oValue;
2014-02-13 21:54:43 +03:00
# Push the return value into the return value array
if ($strType eq DEBUG_PARAM)
{
if (defined($$oyParamRef[$iIndex]))
{
push(@oyResult, $$oyParamRef[$iIndex]);
}
else
{
push(@oyResult, $${oParam}{default});
$$oParamHash{$strParamName}{default} = true;
}
2014-07-28 01:13:23 +03:00
$oValue = $oyResult[@oyResult - 1];
2014-07-28 01:13:23 +03:00
if (!defined($oValue) && (!defined($${oParam}{required}) || $${oParam}{required}))
{
confess &log(ASSERT, "${strParamName} is required in ${strFunction}");
}
}
else
{
if (ref($$oParam{value}) eq 'ARRAY')
{
if (defined($$oParam{ref}) && $$oParam{ref})
{
push(@oyResult, $$oParam{value});
}
else
{
push(@oyResult, @{$$oParam{value}});
}
}
else
{
push(@oyResult, $$oParam{value});
}
2014-09-18 22:18:52 +03:00
$oValue = $$oParam{value};
}
2014-07-28 01:13:23 +03:00
if (!defined($$oParam{log}) || $$oParam{log})
{
# If the parameter is a hash but not blessed then represent it as a string
# ??? This should go away once the inputs to logDebug can be changed
if (ref($oValue) eq 'HASH' && !blessed($oValue))
{
$$oParamHash{$strParamName}{value} = '[hash]';
}
# Else log the parameter value exactly
else
{
$$oParamHash{$strParamName}{value} = $oValue;
}
2014-02-14 01:11:53 +03:00
# There are certain return values that it's wasteful to generate debug logging for
if (!($strParamName eq 'self') &&
(!defined($$oParam{trace}) || !$$oParam{trace}))
{
$bLogTrace = false;
}
}
# Get the next parameter hash
$oParam = shift;
$iIndex++;
2014-02-14 01:11:53 +03:00
}
2014-02-03 03:03:05 +03:00
if (defined($strDetail) && $iIndex == 0)
2014-02-14 01:11:53 +03:00
{
$bLogTrace = false;
}
2014-02-14 01:11:53 +03:00
logDebugOut($strFunction, $strType, $strDetail, $oParamHash, $bLogTrace ? TRACE : DEBUG);
# If there are one or zero return values then just return a scalar (this will be undef if there are no return values)
if (@oyResult == 1)
{
return $oyResult[0];
}
# Else return an array containing return values
return @oyResult;
}
####################################################################################################################################
# logDebugOut
####################################################################################################################################
use constant DEBUG_STRING_MAX_LEN => 1024;
sub logDebugOut
{
my $strFunction = shift;
my $strType = shift;
my $strMessage = shift;
my $oParamHash = shift;
my $strLevel = shift;
$strLevel = defined($strLevel) ? $strLevel : DEBUG;
if ($oLogLevelRank{$strLevel}{rank} <= $oLogLevelRank{$strLogLevelConsole}{rank} ||
$oLogLevelRank{$strLevel}{rank} <= $oLogLevelRank{$strLogLevelFile}{rank} ||
$oLogLevelRank{$strLevel}{rank} <= $oLogLevelRank{$strLogLevelStdErr}{rank})
{
if (defined($oParamHash))
{
my $strParamSet;
foreach my $strParam (sort(keys(%$oParamHash)))
{
if (defined($strParamSet))
{
$strParamSet .= ', ';
}
my $strValueRef;
my $bDefault = false;
if (ref($$oParamHash{$strParam}) eq 'HASH')
{
if (blessed($$oParamHash{$strParam}{value}))
{
$strValueRef = \'[object]';
}
else
{
if (ref($$oParamHash{$strParam}{value}) eq 'ARRAY')
{
my $strValueArray;
for my $strValue (@{$$oParamHash{$strParam}{value}})
{
if (ref($strValue) eq 'ARRAY')
{
my $strSubValueArray;
for my $strSubValue (@{$strValue})
{
$strSubValueArray .=
(defined($strSubValueArray) ? ', ' : '(') .
(defined($strSubValue) ? $strSubValue : '[undef]');
}
$strValueArray .= (defined($strValueArray) ? ', ' : '(') .
(defined($strSubValueArray) ? $strSubValueArray . ')' : '()');
}
else
{
$strValueArray .=
(defined($strValueArray) ? ', ' : '(') . (defined($strValue) ? $strValue : '[undef]');
}
}
$strValueRef = \(defined($strValueArray) ? $strValueArray . ')' : '()');
}
else
{
$strValueRef = ref($$oParamHash{$strParam}{value}) ? $$oParamHash{$strParam}{value} :
\$$oParamHash{$strParam}{value};
$bDefault = defined($$strValueRef) &&
defined($$oParamHash{$strParam}{default}) ? $$oParamHash{$strParam}{default} : false;
}
}
}
# If this is an ARRAY ref then create a comma-separated list
elsif (ref($$oParamHash{$strParam}) eq 'ARRAY')
{
my $strValueArray;
for my $strValue (@{$$oParamHash{$strParam}{value}})
{
$strValueArray .=
(defined($strValueArray) ? ', ' : '(') . (defined($strValue) ? $strValue : '[undef]');
}
$strValueRef = \(defined($strValueArray) ? $strValueArray . ')' : '()');
}
# Else get a reference if a reference was not passed
else
{
$strValueRef = ref($$oParamHash{$strParam}) ? $$oParamHash{$strParam} : \$$oParamHash{$strParam};
}
$strParamSet .= "${strParam} = " .
($bDefault ? '<' : '') .
(defined($$strValueRef) ?
($strParam =~ /^(b|is)/ ? ($$strValueRef ? 'true' : 'false'):
(length($$strValueRef) > DEBUG_STRING_MAX_LEN ?
substr($$strValueRef, 0, DEBUG_STRING_MAX_LEN) . ' ... <truncated>':
$$strValueRef)) : '[undef]') .
($bDefault ? '>' : '');
}
if (defined($strMessage))
{
$strMessage = $strMessage . (defined($strParamSet) ? ": ${strParamSet}" : '');
}
else
{
$strMessage = $strParamSet;
}
}
&log($strLevel, "${strFunction}${strType}" . (defined($strMessage) ? ": $strMessage" : ''));
}
}
####################################################################################################################################
# logException
####################################################################################################################################
sub logException
{
my $oException = shift;
return &log($oException->level(), $oException->message(), $oException->code(), undef, undef, undef, $oException->extra());
}
push @EXPORT, qw(logException);
2014-02-14 01:11:53 +03:00
####################################################################################################################################
# LOG - log messages
####################################################################################################################################
2014-02-03 03:03:05 +03:00
sub log
{
my $strLevel = shift;
my $strMessage = shift;
2014-06-07 18:51:27 +03:00
my $iCode = shift;
my $bSuppressLog = shift;
my $iIndent = shift;
2016-09-06 15:35:02 +02:00
my $iProcessId = shift;
my $rExtra = shift;
2014-06-07 18:51:27 +03:00
# Set defaults
$bSuppressLog = defined($bSuppressLog) ? $bSuppressLog : false;
# Initialize rExtra
if (!defined($rExtra))
{
$rExtra =
{
bLogFile => false,
bLogConsole => false,
};
}
# Set operational variables
2014-06-07 18:51:27 +03:00
my $strMessageFormat = $strMessage;
2014-08-10 01:35:55 +03:00
my $iLogLevelRank = $oLogLevelRank{"${strLevel}"}{rank};
2014-02-03 03:03:05 +03:00
# If test message
2014-08-10 01:35:55 +03:00
if ($strLevel eq TEST)
2014-07-28 01:13:23 +03:00
{
if (!defined($oTestPoint) || !defined($$oTestPoint{lc($strMessage)}))
{
return;
}
2014-08-10 01:35:55 +03:00
$iLogLevelRank = $oLogLevelRank{TRACE}{rank} + 1;
2014-07-28 01:13:23 +03:00
$strMessageFormat = TEST_ENCLOSE . '-' . $strMessageFormat . '-' . TEST_ENCLOSE;
}
# Else level rank must be valid
2014-08-10 01:35:55 +03:00
elsif (!defined($iLogLevelRank))
2014-02-14 01:11:53 +03:00
{
confess &log(ASSERT, "log level ${strLevel} does not exist");
}
2014-06-04 05:02:56 +03:00
# If message was undefined then set default message
2014-06-07 18:51:27 +03:00
if (!defined($strMessageFormat))
2014-02-03 03:03:05 +03:00
{
$strMessageFormat = '(undefined)';
2014-02-03 03:03:05 +03:00
}
2016-09-04 15:25:20 +02:00
# Set the error code
if ($strLevel eq ASSERT)
{
$iCode = ERROR_ASSERT;
}
elsif ($strLevel eq ERROR && !defined($iCode))
{
$iCode = ERROR_UNKNOWN;
}
$strMessageFormat = (defined($iCode) ? "[${iCode}]: " : '') . $strMessageFormat;
# Indent subsequent lines of the message if it has more than one line - makes the log more readable
if (defined($iIndent))
{
my $strIndent = ' ' x $iIndent;
$strMessageFormat =~ s/\n/\n${strIndent}/g;
}
else
{
$strMessageFormat =~ s/\n/\n /g;
}
2014-08-10 01:35:55 +03:00
if ($strLevel eq TRACE || $strLevel eq TEST)
2014-02-13 21:54:43 +03:00
{
$strMessageFormat =~ s/\n/\n /g;
$strMessageFormat = ' ' . $strMessageFormat;
2014-02-13 21:54:43 +03:00
}
2014-08-10 01:35:55 +03:00
elsif ($strLevel eq DEBUG)
2014-02-13 21:54:43 +03:00
{
$strMessageFormat =~ s/\n/\n /g;
$strMessageFormat = ' ' . $strMessageFormat;
2014-02-13 21:54:43 +03:00
}
2016-09-04 15:25:20 +02:00
elsif ($strLevel eq ERROR || $strLevel eq ASSERT)
2014-06-07 22:30:13 +03:00
{
$strMessageFormat =~ s/\n/\n /g;
2014-06-07 22:30:13 +03:00
}
2014-02-13 21:54:43 +03:00
# Format the message text
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
2016-09-06 15:35:02 +02:00
$strMessageFormat =
timestampFormat() . sprintf('.%03d P%02d', (gettimeofday() - int(gettimeofday())) * 1000,
(defined($iProcessId) ? $iProcessId : 0)) .
2016-09-04 15:25:20 +02:00
(' ' x (7 - length($strLevel))) . "${strLevel}: ${strMessageFormat}\n";
2014-02-13 21:54:43 +03:00
# Output to stderr depending on log level
if (!$rExtra->{bLogConsole} && $iLogLevelRank <= $oLogLevelRank{$strLogLevelStdErr}{rank})
{
if ($strLogLevelStdErr ne PROTOCOL)
{
syswrite(*STDERR, $strLevel . (defined($iCode) ? " [${iCode}]" : '') . ': ');
}
syswrite(*STDERR, "${strMessage}\n");
$rExtra->{bLogConsole} = true;
}
# Else output to stdout depending on log level and test flag
elsif (!$rExtra->{bLogConsole} && $iLogLevelRank <= $oLogLevelRank{$strLogLevelConsole}{rank} || $bTest && $strLevel eq TEST)
2014-02-13 21:54:43 +03:00
{
if (!$bSuppressLog)
{
syswrite(*STDOUT, $strMessageFormat);
}
# If in test mode and this is a test messsage then delay so the calling process has time to read the message
if ($bTest && $strLevel eq TEST && $fTestDelay > 0)
{
usleep($fTestDelay * 1000000);
}
$rExtra->{bLogConsole} = true;
2014-02-14 01:11:53 +03:00
}
# Output to file depending on log level and test flag
if (!$rExtra->{bLogLogFile} && $iLogLevelRank <= $oLogLevelRank{$strLogLevelFile}{rank})
2014-02-14 01:11:53 +03:00
{
if (defined($hLogFile) || (defined($strLogLevelFile) && $strLogLevelFile ne OFF))
2014-02-14 01:11:53 +03:00
{
if (!$bSuppressLog)
{
if (defined($hLogFile))
{
syswrite($hLogFile, $strMessageFormat);
}
else
{
$strLogFileCache .= $strMessageFormat;
}
if ($strLevel eq ASSERT ||
($strLevel eq ERROR && ($strLogLevelFile eq DEBUG || $strLogLevelFile eq TRACE)))
{
my $strStackTrace = longmess() . "\n";
$strStackTrace =~ s/\n/\n /g;
if (defined($hLogFile))
{
syswrite($hLogFile, $strStackTrace);
}
else
{
$strLogFileCache .= $strStackTrace;
}
}
}
2014-02-14 01:11:53 +03:00
}
$rExtra->{bLogFile} = true;
2014-02-13 21:54:43 +03:00
}
2014-02-03 03:03:05 +03:00
# Throw a typed exception if code is defined
2014-06-07 18:51:27 +03:00
if (defined($iCode))
{
return new pgBackRest::Common::Exception($strLevel, $iCode, $strMessage, longmess(), $rExtra);
2014-06-07 18:51:27 +03:00
}
# Return the message test so it can be used in a confess
2014-02-03 03:03:05 +03:00
return $strMessage;
}
push @EXPORT, qw(log);
2015-04-24 02:52:41 +02:00
####################################################################################################################################
# testSet
#
# Set test parameters.
2015-04-24 02:52:41 +02:00
####################################################################################################################################
sub testSet
2015-04-24 02:52:41 +02:00
{
my $bTestParam = shift;
my $fTestDelayParam = shift;
my $oTestPointParam = shift;
2015-04-24 02:52:41 +02:00
# Set defaults
$bTest = defined($bTestParam) ? $bTestParam : false;
$fTestDelay = defined($bTestParam) ? $fTestDelayParam : $fTestDelay;
$oTestPoint = $oTestPointParam;
2015-04-24 02:52:41 +02:00
# Make sure that a delay is specified in test mode
if ($bTest && !defined($fTestDelay))
2015-04-24 02:52:41 +02:00
{
confess &log(ASSERT, 'iTestDelay must be provided when bTest is true');
2015-04-24 02:52:41 +02:00
}
# Test delay should be between 1 and 600 seconds
if (!($fTestDelay >= 0 && $fTestDelay <= 600))
{
confess &log(ERROR, 'test-delay must be between 1 and 600 seconds');
}
2015-04-24 02:52:41 +02:00
}
push @EXPORT, qw(testSet);
2015-04-24 02:52:41 +02:00
####################################################################################################################################
# testCheck - Check for a test message
2015-04-24 02:52:41 +02:00
####################################################################################################################################
sub testCheck
2015-04-24 02:52:41 +02:00
{
my $strLog = shift;
my $strTest = shift;
2015-04-24 02:52:41 +02:00
return index($strLog, TEST_ENCLOSE . '-' . $strTest . '-' . TEST_ENCLOSE) != -1;
2015-04-24 02:52:41 +02:00
}
push @EXPORT, qw(testCheck);
2014-06-04 18:58:30 +03:00
1;