You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-05 00:28:52 +02:00
Add log module.
This commit is contained in:
@ -62,7 +62,7 @@
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<p>Add <code>time</code> module.</p>
|
||||
<p>Add <code>log</code> and <code>time</code> modules.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
|
@ -6,6 +6,7 @@ pgbackrest: \
|
||||
common/error.o \
|
||||
common/errorType.o \
|
||||
common/ini.o \
|
||||
common/log.o \
|
||||
common/memContext.o \
|
||||
common/regExp.o \
|
||||
common/time.o \
|
||||
@ -19,6 +20,7 @@ pgbackrest: \
|
||||
common/wait.o \
|
||||
config/config.o \
|
||||
config/define.o \
|
||||
config/load.o \
|
||||
config/parse.o \
|
||||
perl/exec.o \
|
||||
storage/helper.o \
|
||||
@ -28,6 +30,7 @@ pgbackrest: \
|
||||
common/error.o \
|
||||
common/errorType.o \
|
||||
common/ini.o \
|
||||
common/log.o \
|
||||
common/memContext.o \
|
||||
common/regExp.o \
|
||||
common/time.o \
|
||||
@ -41,6 +44,7 @@ pgbackrest: \
|
||||
common/wait.o \
|
||||
config/config.o \
|
||||
config/define.o \
|
||||
config/load.o \
|
||||
config/parse.o \
|
||||
perl/exec.o \
|
||||
storage/helper.o \
|
||||
|
176
src/common/log.c
Normal file
176
src/common/log.c
Normal file
@ -0,0 +1,176 @@
|
||||
/***********************************************************************************************************************************
|
||||
Log Handler
|
||||
***********************************************************************************************************************************/
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "common/time.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Module variables
|
||||
***********************************************************************************************************************************/
|
||||
// Log levels
|
||||
LogLevel logLevelStdOut = logLevelOff;
|
||||
LogLevel logLevelStdErr = logLevelWarn;
|
||||
|
||||
// Log file handles
|
||||
int logHandleStdOut = STDOUT_FILENO;
|
||||
int logHandleStdErr = STDERR_FILENO;
|
||||
|
||||
// Is the timestamp printed in the log?
|
||||
bool logTimestamp = false;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Log buffer
|
||||
***********************************************************************************************************************************/
|
||||
#define LOG_BUFFER_SIZE 32768
|
||||
|
||||
char logBuffer[LOG_BUFFER_SIZE];
|
||||
char logFormat[LOG_BUFFER_SIZE];
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Convert log level to string and vice versa
|
||||
***********************************************************************************************************************************/
|
||||
#define LOG_LEVEL_TOTAL 9
|
||||
|
||||
const char *logLevelList[LOG_LEVEL_TOTAL] =
|
||||
{
|
||||
"OFF",
|
||||
"ASSERT",
|
||||
"ERROR",
|
||||
"PROTOCOL",
|
||||
"WARN",
|
||||
"INFO",
|
||||
"DETAIL",
|
||||
"DEBUG",
|
||||
"TRACE",
|
||||
};
|
||||
|
||||
LogLevel
|
||||
logLevelEnum(const char *logLevel)
|
||||
{
|
||||
LogLevel result = logLevelOff;
|
||||
|
||||
// Search for the log level
|
||||
for (; result < LOG_LEVEL_TOTAL; result++)
|
||||
if (strcasecmp(logLevel, logLevelList[result]) == 0)
|
||||
break;
|
||||
|
||||
// If the log level was not found
|
||||
if (result == LOG_LEVEL_TOTAL)
|
||||
THROW(AssertError, "log level '%s' not found", logLevel);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *
|
||||
logLevelStr(LogLevel logLevel)
|
||||
{
|
||||
if (logLevel >= LOG_LEVEL_TOTAL)
|
||||
THROW(AssertError, "invalid log level '%d'", logLevel);
|
||||
|
||||
return logLevelList[logLevel];
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Initialize the log system
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
logInit(LogLevel logLevelStdOutParam, LogLevel logLevelStdErrParam, bool logTimestampParam)
|
||||
{
|
||||
logLevelStdOut = logLevelStdOutParam;
|
||||
logLevelStdErr = logLevelStdErrParam;
|
||||
logTimestamp = logTimestampParam;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
General log function
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
logInternal(LogLevel logLevel, const char *fileName, const char *functionName, int fileLine, int code, const char *format, ...)
|
||||
{
|
||||
// Should this entry be logged?
|
||||
if (logLevel <= logLevelStdOut || logLevel <= logLevelStdErr)
|
||||
{
|
||||
int bufferPos = 0;
|
||||
|
||||
// Add time
|
||||
if (logTimestamp && logLevel > logLevelStdErr)
|
||||
{
|
||||
TimeUSec logTimeUSec = timeUSec();
|
||||
time_t logTime = (time_t)(logTimeUSec / USEC_PER_SEC);
|
||||
|
||||
bufferPos += strftime(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%Y-%m-%d %H:%M:%S", localtime(&logTime));
|
||||
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, ".%03d ", (int)(logTimeUSec / 1000 % 1000));
|
||||
}
|
||||
|
||||
// Add process and aligned log level
|
||||
if (logLevel > logLevelStdErr)
|
||||
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "P00 %*s: ", 6, logLevelStr(logLevel));
|
||||
// Else just the log level with no alignment
|
||||
else
|
||||
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%s: ", logLevelStr(logLevel));
|
||||
|
||||
// Add error code
|
||||
if (code != 0)
|
||||
bufferPos += snprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "[%03d]: ", code);
|
||||
|
||||
// Add debug info
|
||||
if (logLevelStdOut >= logLevelDebug)
|
||||
{
|
||||
bufferPos += snprintf(
|
||||
logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, "%s:%s():%d: ", fileName, functionName, fileLine);
|
||||
}
|
||||
|
||||
// Format message
|
||||
va_list argumentList;
|
||||
va_start(argumentList, format);
|
||||
|
||||
if (logLevel <= logLevelStdErr || strchr(format, '\n') == NULL)
|
||||
bufferPos += vsnprintf(logBuffer + bufferPos, LOG_BUFFER_SIZE - bufferPos, format, argumentList);
|
||||
else
|
||||
{
|
||||
vsnprintf(logFormat, LOG_BUFFER_SIZE, format, argumentList);
|
||||
|
||||
// Indent all lines after the first
|
||||
const char *formatPtr = logFormat;
|
||||
const char *linefeedPtr = strchr(logFormat, '\n');
|
||||
int indentSize = 12;
|
||||
|
||||
while (linefeedPtr != NULL)
|
||||
{
|
||||
strncpy(logBuffer + bufferPos, formatPtr, linefeedPtr - formatPtr + 1);
|
||||
bufferPos += linefeedPtr - formatPtr + 1;
|
||||
|
||||
formatPtr = linefeedPtr + 1;
|
||||
linefeedPtr = strchr(formatPtr, '\n');
|
||||
|
||||
for (int indentIdx = 0; indentIdx < indentSize; indentIdx++)
|
||||
logBuffer[bufferPos++] = ' ';
|
||||
}
|
||||
|
||||
strcpy(logBuffer + bufferPos, formatPtr);
|
||||
bufferPos += strlen(formatPtr);
|
||||
}
|
||||
|
||||
va_end(argumentList);
|
||||
|
||||
// Add linefeed
|
||||
logBuffer[bufferPos++] = '\n';
|
||||
logBuffer[bufferPos] = 0;
|
||||
|
||||
// Determine where to log the message based on log-level-stderr
|
||||
int stream = logHandleStdOut;
|
||||
|
||||
if (logLevel <= logLevelStdErr)
|
||||
stream = logHandleStdErr;
|
||||
|
||||
THROW_ON_SYS_ERROR(
|
||||
write(stream, logBuffer, bufferPos) != bufferPos, FileWriteError, "unable to write log to stdout");
|
||||
}
|
||||
}
|
64
src/common/log.h
Normal file
64
src/common/log.h
Normal file
@ -0,0 +1,64 @@
|
||||
/***********************************************************************************************************************************
|
||||
Log Handler
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef COMMON_LOG_H
|
||||
#define COMMON_LOG_H
|
||||
|
||||
#include "common/type.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Log types
|
||||
***********************************************************************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
logLevelOff,
|
||||
logLevelAssert,
|
||||
logLevelError,
|
||||
logLevelProtocol,
|
||||
logLevelWarn,
|
||||
logLevelInfo,
|
||||
logLevelDetail,
|
||||
logLevelDebug,
|
||||
logLevelTrace,
|
||||
} LogLevel;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Expose internal data for debugging/testing
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef NDEBUG
|
||||
extern LogLevel logLevelStdOut;
|
||||
extern LogLevel logLevelStdErr;
|
||||
|
||||
extern int logHandleStdOut;
|
||||
extern int logHandleStdErr;
|
||||
|
||||
extern bool logTimestamp;
|
||||
#endif
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
void logInit(LogLevel logLevelStdOut, LogLevel logLevelStdErr, bool logTimestamp);
|
||||
|
||||
LogLevel logLevelEnum(const char *logLevel);
|
||||
const char *logLevelStr(LogLevel logLevel);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Macros
|
||||
***********************************************************************************************************************************/
|
||||
#define LOG_ANY(logLevel, code, ...) \
|
||||
logInternal(logLevel, __FILE__, __func__, __LINE__, code, __VA_ARGS__)
|
||||
#define LOG_ERROR(code, ...) \
|
||||
LOG_ANY(logLevelError, code, __VA_ARGS__)
|
||||
#define LOG_INFO(...) \
|
||||
LOG_ANY(logLevelInfo, 0, __VA_ARGS__)
|
||||
#define LOG_WARN(...) \
|
||||
LOG_ANY(logLevelWarn, 0, __VA_ARGS__)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Internal Functions
|
||||
***********************************************************************************************************************************/
|
||||
void logInternal(
|
||||
LogLevel logLevel, const char *fileName, const char *functionName, int fileLine, int code, const char *format, ...);
|
||||
|
||||
#endif
|
39
src/config/load.c
Normal file
39
src/config/load.c
Normal file
@ -0,0 +1,39 @@
|
||||
/***********************************************************************************************************************************
|
||||
Configuration Load
|
||||
***********************************************************************************************************************************/
|
||||
#include <string.h>
|
||||
|
||||
#include "common/memContext.h"
|
||||
#include "common/log.h"
|
||||
#include "config/config.h"
|
||||
#include "config/parse.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Load the configuration
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
cfgLoad(int argListSize, const char *argList[])
|
||||
{
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Parse config from command line and config file
|
||||
configParse(argListSize, argList);
|
||||
|
||||
// Initialize logging
|
||||
LogLevel logLevelConsole = logLevelOff;
|
||||
LogLevel logLevelStdErr = logLevelOff;
|
||||
bool logTimestamp = true;
|
||||
|
||||
if (cfgOptionValid(cfgOptLogLevelConsole))
|
||||
logLevelConsole = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelConsole)));
|
||||
|
||||
if (cfgOptionValid(cfgOptLogLevelStderr))
|
||||
logLevelStdErr = logLevelEnum(strPtr(cfgOptionStr(cfgOptLogLevelStderr)));
|
||||
|
||||
if (cfgOptionValid(cfgOptLogTimestamp))
|
||||
logTimestamp = cfgOptionBool(cfgOptLogTimestamp);
|
||||
|
||||
logInit(logLevelConsole, logLevelStdErr, logTimestamp);
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
}
|
12
src/config/load.h
Normal file
12
src/config/load.h
Normal file
@ -0,0 +1,12 @@
|
||||
/***********************************************************************************************************************************
|
||||
Configuration Load
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef CONFIG_LOAD_H
|
||||
#define CONFIG_LOAD_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
void cfgLoad(int argListSize, const char *argList[]);
|
||||
|
||||
#endif
|
12
src/main.c
12
src/main.c
@ -5,8 +5,9 @@ Main
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "config/config.h"
|
||||
#include "config/parse.h"
|
||||
#include "config/load.h"
|
||||
#include "perl/exec.h"
|
||||
#include "version.h"
|
||||
|
||||
@ -14,10 +15,12 @@ int main(int argListSize, const char *argList[])
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Parse command line
|
||||
configParse(argListSize, argList);
|
||||
// Load the configuration
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
cfgLoad(argListSize, argList);
|
||||
|
||||
// Display version
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
if (!cfgCommandHelp() && cfgCommand() == cfgCmdVersion)
|
||||
{
|
||||
printf(PGBACKREST_NAME " " PGBACKREST_VERSION "\n");
|
||||
@ -30,8 +33,7 @@ int main(int argListSize, const char *argList[])
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
fprintf(stderr, "ERROR [%03d]: %s\n", errorCode(), errorMessage());
|
||||
fflush(stderr);
|
||||
LOG_ERROR(errorCode(), errorMessage());
|
||||
exit(errorCode());
|
||||
}
|
||||
TRY_END();
|
||||
|
@ -442,7 +442,7 @@ full backup - invalid cmd line (db-master host)
|
||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --no-online --type=full --stanza=bogus backup
|
||||
------------------------------------------------------------------------------------------------------------------------------------
|
||||
STDERR:
|
||||
ERROR [037]: backup command requires option: db1-path
|
||||
ERROR: [037]: backup command requires option: db1-path
|
||||
HINT: does this stanza exist?
|
||||
|
||||
stop all stanzas (db-master host)
|
||||
|
@ -101,18 +101,28 @@ my $oTestDef =
|
||||
&TESTDEF_NAME => 'type',
|
||||
&TESTDEF_TOTAL => 2,
|
||||
&TESTDEF_C => true,
|
||||
&TESTDEF_CDEF => '-DNO_ERROR',
|
||||
&TESTDEF_CDEF => '-DNO_ERROR -DNO_LOG',
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
'common/type' => TESTDEF_COVERAGE_NOCODE,
|
||||
},
|
||||
},
|
||||
{
|
||||
&TESTDEF_NAME => 'time',
|
||||
&TESTDEF_TOTAL => 2,
|
||||
&TESTDEF_C => true,
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
'common/time' => TESTDEF_COVERAGE_FULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
&TESTDEF_NAME => 'error',
|
||||
&TESTDEF_TOTAL => 6,
|
||||
&TESTDEF_C => true,
|
||||
&TESTDEF_CDEF => '-DNO_ERROR',
|
||||
&TESTDEF_CDEF => '-DNO_ERROR -DNO_LOG',
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
@ -124,7 +134,7 @@ my $oTestDef =
|
||||
&TESTDEF_NAME => 'mem-context',
|
||||
&TESTDEF_TOTAL => 6,
|
||||
&TESTDEF_C => true,
|
||||
&TESTDEF_CDEF => '-DNO_MEM_CONTEXT',
|
||||
&TESTDEF_CDEF => '-DNO_MEM_CONTEXT -DNO_LOG',
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
@ -132,13 +142,14 @@ my $oTestDef =
|
||||
},
|
||||
},
|
||||
{
|
||||
&TESTDEF_NAME => 'time',
|
||||
&TESTDEF_TOTAL => 2,
|
||||
&TESTDEF_NAME => 'log',
|
||||
&TESTDEF_TOTAL => 3,
|
||||
&TESTDEF_C => true,
|
||||
&TESTDEF_CDEF => '-DNO_LOG',
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
'common/time' => TESTDEF_COVERAGE_FULL,
|
||||
'common/log' => TESTDEF_COVERAGE_FULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -433,6 +444,17 @@ my $oTestDef =
|
||||
'config/parse.auto' => TESTDEF_COVERAGE_NOCODE,
|
||||
},
|
||||
},
|
||||
{
|
||||
&TESTDEF_NAME => 'load',
|
||||
&TESTDEF_TOTAL => 1,
|
||||
&TESTDEF_C => true,
|
||||
&TESTDEF_CDEF => '-DNO_ERROR -DNO_LOG',
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
'config/load' => TESTDEF_COVERAGE_FULL,
|
||||
},
|
||||
},
|
||||
{
|
||||
&TESTDEF_NAME => 'unit',
|
||||
&TESTDEF_TOTAL => 1,
|
||||
|
@ -314,7 +314,8 @@ sub run
|
||||
($self->{oTest}->{&TEST_VM} ne VM_CO6 && $self->{oTest}->{&TEST_VM} ne VM_U12 ? ' -Wpedantic' : '') .
|
||||
" -I$self->{strBackRestBase}/src -I$self->{strBackRestBase}/test/src test.c" .
|
||||
" $self->{strBackRestBase}/test/src/common/harnessTest.c" .
|
||||
join(' ', @stryCFile) . " -l crypto -o test";
|
||||
" $self->{strBackRestBase}/test/src/common/logTest.c" .
|
||||
' ' . join(' ', @stryCFile) . " -l crypto -o test";
|
||||
|
||||
executeTest(
|
||||
'docker exec -i -u ' . TEST_USER . " ${strImage} bash -l -c '" .
|
||||
|
57
test/src/common/logTest.c
Normal file
57
test/src/common/logTest.c
Normal file
@ -0,0 +1,57 @@
|
||||
/***********************************************************************************************************************************
|
||||
Log Test Harness
|
||||
***********************************************************************************************************************************/
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/harnessTest.h"
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/type.h"
|
||||
#include "storage/helper.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Name of file where logs are stored for testing
|
||||
***********************************************************************************************************************************/
|
||||
String *stdoutFile = NULL;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Initialize log for testing
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
testLogInit()
|
||||
{
|
||||
logInit(logLevelInfo, logLevelOff, false);
|
||||
|
||||
stdoutFile = strNewFmt("%s/stdout.log", testPath());
|
||||
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Compare log to a static string
|
||||
|
||||
After the comparison the log is cleared so the next result can be compared.
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
testLogResult(const char *expected)
|
||||
{
|
||||
String *actual = strTrim(strNewBuf(storageGet(storageLocal(), stdoutFile, false)));
|
||||
|
||||
if (!strEqZ(actual, expected))
|
||||
THROW(AssertError, "\n\nexpected log:\n\n%s\n\nbut actual log was:\n\n%s\n\n", expected, strPtr(actual));
|
||||
|
||||
close(logHandleStdOut);
|
||||
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Make sure nothing is left in the log after all tests have completed
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
testLogFinal()
|
||||
{
|
||||
String *actual = strTrim(strNewBuf(storageGet(storageLocal(), stdoutFile, false)));
|
||||
|
||||
if (!strEqZ(actual, ""))
|
||||
THROW(AssertError, "\n\nexpected log to be empty but actual log was:\n\n%s\n\n", strPtr(actual));
|
||||
}
|
14
test/src/common/logTest.h
Normal file
14
test/src/common/logTest.h
Normal file
@ -0,0 +1,14 @@
|
||||
/***********************************************************************************************************************************
|
||||
Log Test Harness
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef TEST_COMMON_LOG_H
|
||||
#define TEST_COMMON_LOG_H
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
void testLogInit();
|
||||
void testLogResult(const char *expected);
|
||||
void testLogFinal();
|
||||
|
||||
#endif
|
95
test/src/module/common/logTest.c
Normal file
95
test/src/module/common/logTest.c
Normal file
@ -0,0 +1,95 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Log Handler
|
||||
***********************************************************************************************************************************/
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <common/regExp.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Test Run
|
||||
***********************************************************************************************************************************/
|
||||
void testRun()
|
||||
{
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("logLevelEnum() and logLevelStr()"))
|
||||
{
|
||||
TEST_ERROR(logLevelEnum(BOGUS_STR), AssertError, "log level 'BOGUS' not found");
|
||||
TEST_RESULT_INT(logLevelEnum("OFF"), logLevelOff, "log level 'OFF' found");
|
||||
TEST_RESULT_INT(logLevelEnum("info"), logLevelInfo, "log level 'info' found");
|
||||
TEST_RESULT_INT(logLevelEnum("TRACE"), logLevelTrace, "log level 'TRACE' found");
|
||||
|
||||
TEST_ERROR(logLevelStr(999), AssertError, "invalid log level '999'");
|
||||
TEST_RESULT_STR(logLevelStr(logLevelOff), "OFF", "log level 'OFF' found");
|
||||
TEST_RESULT_STR(logLevelStr(logLevelInfo), "INFO", "log level 'INFO' found");
|
||||
TEST_RESULT_STR(logLevelStr(logLevelTrace), "TRACE", "log level 'TRACE' found");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("logInit()"))
|
||||
{
|
||||
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
|
||||
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
|
||||
TEST_RESULT_VOID(logInit(logLevelInfo, logLevelError, true), "init logging");
|
||||
TEST_RESULT_INT(logLevelStdOut, logLevelInfo, "console logging is info");
|
||||
TEST_RESULT_INT(logLevelStdErr, logLevelError, "stderr logging is error");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("logInternal()"))
|
||||
{
|
||||
TEST_RESULT_VOID(logInit(logLevelWarn, logLevelOff, true), "init logging to warn (timestamp on)");
|
||||
TEST_RESULT_VOID(logInternal(logLevelWarn, NULL, NULL, 0, 0, "TEST"), "log timestamp");
|
||||
|
||||
String *logTime = strNewN(logBuffer, 23);
|
||||
TEST_RESULT_BOOL(
|
||||
regExpMatchOne(
|
||||
strNew("^20[0-9]{2}\\-[0-1][0-9]\\-[0-3][0-9] [0-2][0-9]\\:[0-5][0-9]\\:[0-5][0-9]\\.[0-9]{3}$"), logTime),
|
||||
true, "check timestamp format: %s", strPtr(logTime));
|
||||
|
||||
// Redirect output to files
|
||||
TEST_RESULT_VOID(logInit(logLevelWarn, logLevelOff, false), "init logging to warn (timestamp off)");
|
||||
|
||||
String *stdoutFile = strNewFmt("%s/stdout.log", testPath());
|
||||
String *stderrFile = strNewFmt("%s/stderr.log", testPath());
|
||||
|
||||
logHandleStdOut = open(strPtr(stdoutFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
|
||||
logHandleStdErr = open(strPtr(stderrFile), O_WRONLY | O_CREAT | O_TRUNC, 0640);
|
||||
|
||||
logBuffer[0] = 0;
|
||||
TEST_RESULT_VOID(logInternal(logLevelWarn, NULL, NULL, 0, 0, "format %d", 99), "log warn");
|
||||
TEST_RESULT_STR(logBuffer, "P00 WARN: format 99\n", " check log");
|
||||
|
||||
logBuffer[0] = 0;
|
||||
TEST_RESULT_VOID(logInternal(logLevelError, NULL, NULL, 0, 25, "message"), "log error");
|
||||
TEST_RESULT_STR(logBuffer, "P00 ERROR: [025]: message\n", " check log");
|
||||
|
||||
logBuffer[0] = 0;
|
||||
TEST_RESULT_VOID(logInternal(logLevelError, NULL, NULL, 0, 25, "message1\nmessage2"), "log error with multiple lines");
|
||||
TEST_RESULT_STR(logBuffer, "P00 ERROR: [025]: message1\n message2\n", " check log");
|
||||
|
||||
TEST_RESULT_VOID(logInit(logLevelDebug, logLevelDebug, false), "init logging to debug");
|
||||
|
||||
logBuffer[0] = 0;
|
||||
TEST_RESULT_VOID(logInternal(logLevelError, "test.c", "test_func", 33, 25, "message"), "log error");
|
||||
TEST_RESULT_STR(logBuffer, "ERROR: [025]: test.c:test_func():33: message\n", " check log");
|
||||
|
||||
// Check stdout
|
||||
Storage *storage = storageNew(strNew(testPath()), 0750, 65536, NULL);
|
||||
|
||||
TEST_RESULT_STR(
|
||||
strPtr(strNewBuf(storageGet(storage, stdoutFile, false))),
|
||||
"P00 WARN: format 99\n"
|
||||
"P00 ERROR: [025]: message\n"
|
||||
"P00 ERROR: [025]: message1\n"
|
||||
" message2\n",
|
||||
"checkout stdout output");
|
||||
|
||||
// Check stderr
|
||||
TEST_RESULT_STR(
|
||||
strPtr(strNewBuf(storageGet(storage, stderrFile, false))),
|
||||
"ERROR: [025]: test.c:test_func():33: message\n",
|
||||
"checkout stderr output");
|
||||
}
|
||||
}
|
53
test/src/module/config/loadTest.c
Normal file
53
test/src/module/config/loadTest.c
Normal file
@ -0,0 +1,53 @@
|
||||
/***********************************************************************************************************************************
|
||||
Test Configuration Load
|
||||
***********************************************************************************************************************************/
|
||||
#include "common/log.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Test run
|
||||
***********************************************************************************************************************************/
|
||||
void testRun()
|
||||
{
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("cfgLoad()"))
|
||||
{
|
||||
StringList *argList = strLstNew();
|
||||
strLstAdd(argList, strNew("pgbackrest"));
|
||||
strLstAdd(argList, strNew("archive-get"));
|
||||
|
||||
TEST_ERROR(
|
||||
cfgLoad(strLstSize(argList), strLstPtr(argList)), OptionRequiredError,
|
||||
"archive-get command requires option: stanza");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
|
||||
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
|
||||
|
||||
argList = strLstNew();
|
||||
strLstAdd(argList, strNew("pgbackrest"));
|
||||
strLstAdd(argList, strNew("--host-id=1"));
|
||||
strLstAdd(argList, strNew("--process=1"));
|
||||
strLstAdd(argList, strNew("--command=backup"));
|
||||
strLstAdd(argList, strNew("--stanza=db"));
|
||||
strLstAdd(argList, strNew("--type=backup"));
|
||||
strLstAdd(argList, strNew("local"));
|
||||
|
||||
TEST_RESULT_VOID(cfgLoad(strLstSize(argList), strLstPtr(argList)), "load local config");
|
||||
|
||||
TEST_RESULT_INT(logLevelStdOut, logLevelOff, "console logging is off");
|
||||
TEST_RESULT_INT(logLevelStdErr, logLevelWarn, "stderr logging is warn");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
argList = strLstNew();
|
||||
strLstAdd(argList, strNew("pgbackrest"));
|
||||
strLstAdd(argList, strNew("--stanza=db"));
|
||||
strLstAdd(argList, strNew("--db-path=/path/to/db"));
|
||||
strLstAdd(argList, strNew("--repo-path=/path/to/repo"));
|
||||
strLstAdd(argList, strNew("stanza-create"));
|
||||
|
||||
TEST_RESULT_VOID(cfgLoad(strLstSize(argList), strLstPtr(argList)), "load local config");
|
||||
|
||||
TEST_RESULT_INT(logLevelStdOut, logLevelWarn, "console logging is off");
|
||||
TEST_RESULT_INT(logLevelStdErr, logLevelOff, "stderr logging is off");
|
||||
}
|
||||
}
|
@ -301,6 +301,8 @@ void testRun()
|
||||
TEST_RESULT_INT(cfgOptionSource(cfgOptOnline), cfgSourceParam, " online is source default");
|
||||
TEST_RESULT_BOOL(cfgOptionBool(cfgOptCompress), true, " compress is set");
|
||||
TEST_RESULT_INT(cfgOptionSource(cfgOptCompress), cfgSourceDefault, " compress is source default");
|
||||
TEST_RESULT_INT(cfgOptionInt(cfgOptBufferSize), 4194304, " buffer-size is set");
|
||||
TEST_RESULT_INT(cfgOptionSource(cfgOptBufferSize), cfgSourceDefault, " buffer-size is source default");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
argList = strLstNew();
|
||||
|
@ -86,7 +86,7 @@ void testRun()
|
||||
TEST_RESULT_PTR(storageList(storage, strNew(BOGUS_STR), NULL, true), NULL, "ignore missing dir");
|
||||
|
||||
TEST_RESULT_VOID(storagePut(storage, strNew("aaa.txt"), bufNewStr(strNew("aaa"))), "write aaa.text");
|
||||
TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, NULL, false), ", ")), "aaa.txt", "dir list");
|
||||
TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, NULL, false), ", ")), "aaa.txt, stdout.log", "dir list");
|
||||
|
||||
TEST_RESULT_VOID(storagePut(storage, strNew("bbb.txt"), bufNewStr(strNew("bbb"))), "write bbb.text");
|
||||
TEST_RESULT_STR(strPtr(strLstJoin(storageList(storage, NULL, strNew("^bbb"), false), ", ")), "bbb.txt", "dir list");
|
||||
|
@ -5,7 +5,9 @@ This wrapper runs the the C unit tests.
|
||||
***********************************************************************************************************************************/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef NO_ERROR
|
||||
#include "common/error.h"
|
||||
@ -13,6 +15,10 @@ This wrapper runs the the C unit tests.
|
||||
|
||||
#include "common/harnessTest.h"
|
||||
|
||||
#ifndef NO_LOG
|
||||
#include "common/logTest.h"
|
||||
#endif
|
||||
|
||||
#ifndef NO_MEM_CONTEXT
|
||||
#include "common/memContext.h"
|
||||
#endif
|
||||
@ -36,9 +42,17 @@ main - run the tests
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
// Set neutral umask for testing
|
||||
umask(0000);
|
||||
|
||||
// Set globals
|
||||
testPathSet("{[C_TEST_PATH]}");
|
||||
|
||||
#ifndef NO_LOG
|
||||
// Initialize logging
|
||||
testLogInit();
|
||||
#endif
|
||||
|
||||
// Initialize tests
|
||||
// run, selected
|
||||
{[C_TEST_LIST]}
|
||||
@ -50,15 +64,23 @@ main(void)
|
||||
// Run the tests
|
||||
testRun();
|
||||
|
||||
#ifndef NO_LOG
|
||||
// Make sure there is nothing untested left in the log
|
||||
testLogFinal();
|
||||
#endif
|
||||
|
||||
// End test run and make sure all tests completed
|
||||
testComplete();
|
||||
|
||||
printf("\nTESTS COMPLETED SUCCESSFULLY\n");
|
||||
fflush(stdout);
|
||||
#ifndef NO_ERROR
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
fprintf(stderr, "TEST FAILED WITH %s, \"%s\" at %s:%d\n", errorName(), errorMessage(), errorFileName(), errorFileLine());
|
||||
fflush(stderr);
|
||||
exit(errorCode());
|
||||
}
|
||||
#ifndef NO_MEM_CONTEXT
|
||||
FINALLY()
|
||||
|
Reference in New Issue
Block a user