diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bacf62..1bc5660 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,8 +90,20 @@ set_target_properties(FairLogger PROPERTIES ) if(BUILD_TESTING) - add_executable(loggerTest test/loggerTest.cxx) - target_link_libraries(loggerTest FairLogger pthread) + add_executable(loggerTest test/logger.cxx) + target_link_libraries(loggerTest FairLogger) + add_executable(macrosTest test/macros.cxx) + target_link_libraries(macrosTest FairLogger) + add_executable(nologTest test/nolog.cxx) + target_link_libraries(nologTest FairLogger) + add_executable(severityTest test/severity.cxx) + target_link_libraries(severityTest FairLogger) + add_executable(sinksTest test/sinks.cxx) + target_link_libraries(sinksTest FairLogger) + add_executable(threadsTest test/threads.cxx) + target_link_libraries(threadsTest FairLogger pthread) + add_executable(verbosityTest test/verbosity.cxx) + target_link_libraries(verbosityTest FairLogger) endif() ################################################################################ @@ -131,7 +143,13 @@ install_cmake_package() # Testing ###################################################################### if(BUILD_TESTING) - add_test(NAME loggerTest COMMAND $) + add_test(NAME logger COMMAND $) + add_test(NAME macros COMMAND $) + add_test(NAME nolog COMMAND $) + add_test(NAME severity COMMAND $) + add_test(NAME sinks COMMAND $) + add_test(NAME threads COMMAND $) + add_test(NAME verbosity COMMAND $) endif() ################################################################################ diff --git a/test/Common.h b/test/Common.h new file mode 100644 index 0000000..629c7d6 --- /dev/null +++ b/test/Common.h @@ -0,0 +1,99 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ +#ifndef FAIR_LOGGER_TEST_COMMON_H +#define FAIR_LOGGER_TEST_COMMON_H + +#include +#include +#include +#include +#include +#include +#include + +#include // fflush +#include // dup, dup2, close + +namespace fair +{ +namespace logger +{ +namespace test +{ + +template +auto ToStr(T&&... t) -> std::string +{ + std::stringstream ss; + (void)std::initializer_list{(ss << t, 0)...}; + return ss.str(); +} + +template +class StreamCapturer +{ + public: + explicit StreamCapturer() + : mFd(S) + , mOriginalFd(dup(S)) // create a copy of the given file descriptor + { + char name[] = "/tmp/fairlogger_test_capture.XXXXXX"; + + const int capturedFd = mkstemp(name); // create a unique temporary file + if (capturedFd == -1) { + std::cout << "Could not create tmp file " << name << " for test; does the test have access to the /tmp directory?" << std::endl; + throw std::runtime_error("Could not create tmp file for test; does the test have access to the /tmp directory?"); + } + mTmpFile = name; + + fflush(nullptr); // flushes all open output streams + dup2(capturedFd, mFd); + close(capturedFd); + } + + std::string GetCapture() + { + fflush(nullptr); // flushes all open output streams + std::ifstream t(mTmpFile); + std::stringstream buffer; + buffer << t.rdbuf(); + return buffer.str(); + } + + ~StreamCapturer() + { + dup2(mOriginalFd, mFd); + close(mOriginalFd); + remove(mTmpFile.c_str()); + } + + private: + const int mFd; + int mOriginalFd; + std::string mTmpFile; +}; + +void CheckOutput(std::string const& expected, std::function f) +{ + std::string output; + { + StreamCapturer<1> c; + f(); + output = c.GetCapture(); + } + const std::regex e(expected); + if (!std::regex_match(output, e)) { + throw std::runtime_error(std::string("MISMATCH:\n##### expected (regex):\n" + expected + "\n##### found:\n" + output)); + } +} + +} // namespace test +} // namespace logger +} // namespace fair + +#endif // FAIR_LOGGER_TEST_COMMON_H diff --git a/test/logger.cxx b/test/logger.cxx new file mode 100644 index 0000000..f2ede5c --- /dev/null +++ b/test/logger.cxx @@ -0,0 +1,58 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include + +#include + +using namespace std; +using namespace fair; + +void printEverySeverity() +{ + static int i = 1; + + LOG(nolog) << "nolog message, counter: " << i++; + LOG(trace) << "trace message, counter: " << i++; + LOG(debug4) << "debug4 message, counter: " << i++; + LOG(debug3) << "debug3 message, counter: " << i++; + LOG(debug2) << "debug2 message, counter: " << i++; + LOG(debug1) << "debug1 message, counter: " << i++; + LOG(debug) << "debug message, counter: " << i++; + LOG(info) << "info message, counter: " << i++; + LOG(state) << "state message, counter: " << i++; + LOG(warn) << "warning message, counter: " << i++; + LOG(error) << "error message, counter: " << i++; + LOG(fatal) << "fatal message, counter: " << i++; +} + +void printAllVerbositiesWithSeverity(Severity sev) +{ + Logger::SetConsoleSeverity(sev); + + for (uint32_t i = 0; i < Logger::fVerbosityNames.size(); ++i) { + cout << "##### testing severity '" << Logger::fSeverityNames.at(static_cast(sev)) << "' with verbosity '" << Logger::fVerbosityNames.at(i) << "'" << endl; + Logger::SetVerbosity(static_cast(i)); + printEverySeverity(); + } +} + +int main() +{ + Logger::SetConsoleColor(true); + Logger::SetVerbosity(Verbosity::veryhigh); + cout << "##### GetConsoleSeverity = " << Logger::SeverityName(Logger::GetConsoleSeverity()) << endl; + + cout << "##### testing severities..." << endl; + + for (uint32_t i = 0; i < Logger::fSeverityNames.size(); ++i) { + printAllVerbositiesWithSeverity(static_cast(i)); + } + + return 0; +} diff --git a/test/loggerTest.cxx b/test/loggerTest.cxx deleted file mode 100644 index 265ff56..0000000 --- a/test/loggerTest.cxx +++ /dev/null @@ -1,208 +0,0 @@ -/******************************************************************************** - * Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * - * * - * This software is distributed under the terms of the * - * GNU Lesser General Public Licence (LGPL) version 3, * - * copied verbatim in the file "LICENSE" * - ********************************************************************************/ -#include - -#include -#include -#include - -using namespace std; -using namespace fair; - -void printEverySeverity() -{ - static int i = 1; - - LOG(nolog) << "nolog message " << i++; - LOG(error) << "error message " << i++; - LOG(warn) << "warning message " << i++; - LOG(state) << "state message " << i++; - LOG(info) << "info message " << i++; - LOG(debug) << "debug message " << i++; - LOG(debug1) << "debug1 message " << i++; - LOG(debug2) << "debug2 message " << i++; - LOG(debug3) << "debug3 message " << i++; - LOG(debug4) << "debug4 message " << i++; - LOG(trace) << "trace message " << i++; -} - -void printAllVerbositiesWithSeverity(Severity sev) -{ - Logger::SetConsoleSeverity(sev); - - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'verylow' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::verylow); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'low' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::low); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'medium' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::medium); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'high' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::high); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'veryhigh' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::veryhigh); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user1' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::user1); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user2' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::user2); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user3' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::user3); - printEverySeverity(); - cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'user4' verbosity..." << endl; - Logger::SetVerbosity(Verbosity::user4); - printEverySeverity(); -} - -void silentlyPrintAllVerbositiesWithSeverity(Severity sev) -{ - Logger::SetConsoleSeverity(sev); - - Logger::SetVerbosity(Verbosity::verylow); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::low); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::medium); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::high); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::veryhigh); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::user1); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::user2); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::user3); - printEverySeverity(); - Logger::SetVerbosity(Verbosity::user4); - printEverySeverity(); -} - -int main() -{ - Logger::SetConsoleColor(true); - - auto spec = VerbositySpec::Make(VerbositySpec::Info::file_line_function, - VerbositySpec::Info::process_name, - VerbositySpec::Info::process_name); - cout << "Defining custom verbosity \"user2\"" << endl; - Logger::DefineVerbosity(Verbosity::user2, spec); - - cout << "cout: testing severities..." << endl; - - printAllVerbositiesWithSeverity(Severity::trace); - printAllVerbositiesWithSeverity(Severity::debug4); - printAllVerbositiesWithSeverity(Severity::debug3); - printAllVerbositiesWithSeverity(Severity::debug2); - printAllVerbositiesWithSeverity(Severity::debug1); - printAllVerbositiesWithSeverity(Severity::debug); - printAllVerbositiesWithSeverity(Severity::info); - printAllVerbositiesWithSeverity(Severity::state); - printAllVerbositiesWithSeverity(Severity::warn); - printAllVerbositiesWithSeverity(Severity::error); - printAllVerbositiesWithSeverity(Severity::nolog); - - cout << endl; - cout << "cout: setting severity to 'info' and verbosity to 'medium'" << endl; - Logger::SetConsoleSeverity(Severity::info); - Logger::SetVerbosity(Verbosity::medium); - - cout << "cout: is logging trace: " << fair::Logger::Logging(Severity::trace) << endl; - cout << "cout: is logging debug4: " << fair::Logger::Logging(Severity::debug) << endl; - cout << "cout: is logging debug3: " << fair::Logger::Logging(Severity::debug) << endl; - cout << "cout: is logging debug2: " << fair::Logger::Logging(Severity::debug) << endl; - cout << "cout: is logging debug1: " << fair::Logger::Logging(Severity::debug) << endl; - cout << "cout: is logging debug: " << fair::Logger::Logging(Severity::debug) << endl; - cout << "cout: is logging info: " << fair::Logger::Logging(Severity::info) << endl; - cout << "cout: is logging state: " << fair::Logger::Logging(Severity::state) << endl; - cout << "cout: is logging warn: " << fair::Logger::Logging(Severity::warn) << endl; - cout << "cout: is logging error: " << fair::Logger::Logging(Severity::error) << endl; - cout << "cout: is logging fatal: " << fair::Logger::Logging(Severity::fatal) << endl; - cout << "cout: is logging nolog: " << fair::Logger::Logging(Severity::nolog) << endl; - - for (int i = 0; i < 1000000; ++i) { - silentlyPrintAllVerbositiesWithSeverity(Severity::nolog); - } - cout << endl; - cout << "cout: setting severity to 'trace' and verbosity to 'veryhigh'" << endl; - Logger::SetConsoleSeverity(Severity::trace); - Logger::SetVerbosity(Verbosity::veryhigh); - - cout << endl; - cout << "cout: testing conditional logging..." << endl; - int x = 0; - LOG(info) << "x = " << x << " (initial)"; - LOG_IF(info, (x == 0)) << "incrementing x to " << ++x; - LOG(info) << "x = " << x << " (after increment)"; - LOG_IF(info, (x == 0)) << "this should not be printed and x not incremented: " << ++x; - LOG(info) << "x = " << x << " (after conditional increment)"; - - cout << endl; - cout << "cout: setting severity to 'nolog'" << endl; - Logger::SetConsoleSeverity(Severity::nolog); - - cout << "cout: ----------------------------" << endl; - cout << "cout: open log file with severity 'error'" << endl; - Logger::InitFileSink(Severity::error, "test_log", true); - printEverySeverity(); - cout << "cout: closing log file" << endl; - Logger::RemoveFileSink(); - - - cout << "cout: setting severity to 'nolog'" << endl; - Logger::SetConsoleSeverity(Severity::nolog); - cout << "cout: ----------------------------" << endl; - cout << "cout: adding custom sink with error severity" << endl << endl; - - Logger::AddCustomSink("CustomSink", "error", [](const string& content, const LogMetaData& metadata) - { - cout << "CustomSink: content: " << content << endl; - - cout << "CustomSink: available metadata: " << endl; - cout << "CustomSink: \tstd::time_t timestamp: " << metadata.timestamp << endl; - cout << "CustomSink: \tstd::chrono::microseconds us: " << metadata.us.count() << endl; - cout << "CustomSink: \tstd::string process_name: " << metadata.process_name << endl; - cout << "CustomSink: \tstd::string file: " << metadata.file << endl; - cout << "CustomSink: \tstd::string line: " << metadata.line << endl; - cout << "CustomSink: \tstd::string func: " << metadata.func << endl; - cout << "CustomSink: \tstd::string severity_name: " << metadata.severity_name << endl; - cout << "CustomSink: \tfair::Severity severity: " << static_cast(metadata.severity) << endl; - }); - - printEverySeverity(); - - cout << endl << "cout: removing custom sink with info severity" << endl; - - Logger::AddCustomSink("CustomSink", Severity::error, [](const string& /*content*/, const LogMetaData& /*metadata*/){}); - Logger::RemoveCustomSink("CustomSink"); - Logger::RemoveCustomSink("bla"); - - cout << "cout: setting severity to 'trace'" << endl; - Logger::SetConsoleSeverity(Severity::trace); - - LOGP(info, "Hello {} {}!", "world", ":-)"); - LOGF(info, "Hello %s %s!", "world", ":-)"); - - cout << "cout: setting verbosity to 'high'" << endl; - Logger::SetVerbosity(Verbosity::high); - - LOGV(info, verylow) << "I should be printed with very low verbosity"; - - cout << "cout: pushing 4 new lines with LOGN() in info verbosity" << endl; - LOGN(info); - LOGN(info); - LOGN(info); - LOGN(info); - - return 0; -} diff --git a/test/macros.cxx b/test/macros.cxx new file mode 100644 index 0000000..2bc17e3 --- /dev/null +++ b/test/macros.cxx @@ -0,0 +1,60 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include "Common.h" +#include + +#include + +using namespace std; +using namespace fair; +using namespace fair::logger::test; + +int main() +{ + try { + Logger::SetConsoleColor(false); + Logger::SetConsoleSeverity(Severity::fatal); + Logger::SetVerbosity(Verbosity::verylow); + + int x = 0; + + CheckOutput("^incrementing x to 1\n$", [&]() { LOG_IF(fatal, true) << "incrementing x to " << ++x; }); + if (x != 1) { + throw runtime_error(ToStr("expected x to be 1, but it is: ", x)); + } + + CheckOutput("^$", [&]() { LOG_IF(fatal, false) << "incrementing x to " << ++x; }); + if (x != 1) { + throw runtime_error(ToStr("expected x to be 1, but it is: ", x)); + } + + CheckOutput("^Hello world :-\\)!\n$", []() { LOGP(fatal, "Hello {} {}!", "world", ":-)"); }); + CheckOutput("^Hello world :-\\)!\n$", []() { LOGF(fatal, "Hello %s %s!", "world", ":-)"); }); + + CheckOutput(ToStr(R"(^\[FATAL])", " content\n$"), []() { LOGV(fatal, low) << "content"; }); + + CheckOutput("^\n\n\n\n$", []() { + LOGN(fatal); + LOGN(fatal); + LOGN(fatal); + LOGN(fatal); + }); + + Logger::SetVerbosity(Verbosity::veryhigh); + + CheckOutput(ToStr(R"(^\[.*]\[\d{2}:\d{2}:\d{2}\.\d{6}]\[FATAL]\[a:4:b])", " c\n$"), []() { + LOGD(Severity::fatal, "a", "4", "b") << "c"; + }); + } catch (runtime_error& rte) { + cout << rte.what() << endl; + return 1; + } + + return 0; +} diff --git a/test/nolog.cxx b/test/nolog.cxx new file mode 100644 index 0000000..eaa80bd --- /dev/null +++ b/test/nolog.cxx @@ -0,0 +1,60 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include + +using namespace std; +using namespace fair; + +void printEverySeverity() +{ + LOG(nolog) << "nolog message, counter: "; + LOG(trace) << "trace message, counter: "; + LOG(debug4) << "debug4 message, counter: "; + LOG(debug3) << "debug3 message, counter: "; + LOG(debug2) << "debug2 message, counter: "; + LOG(debug1) << "debug1 message, counter: "; + LOG(debug) << "debug message, counter: "; + LOG(info) << "info message, counter: " ; + LOG(state) << "state message, counter: "; + LOG(warn) << "warning message, counter: "; + LOG(error) << "error message, counter: "; +} + +void silentlyPrintAllVerbositiesWithSeverity(Severity sev) +{ + Logger::SetConsoleSeverity(sev); + + Logger::SetVerbosity(Verbosity::verylow); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::low); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::medium); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::high); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::veryhigh); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::user1); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::user2); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::user3); + printEverySeverity(); + Logger::SetVerbosity(Verbosity::user4); + printEverySeverity(); +} + +int main() +{ + for (int i = 0; i < 1000000; ++i) { + silentlyPrintAllVerbositiesWithSeverity(Severity::nolog); + } + + return 0; +} diff --git a/test/severity.cxx b/test/severity.cxx new file mode 100644 index 0000000..ae03545 --- /dev/null +++ b/test/severity.cxx @@ -0,0 +1,99 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include "Common.h" + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace fair; +using namespace fair::logger::test; + +uint32_t printEverySeverity(uint32_t i) +{ + LOG(nolog) << "nolog message, counter: " << i++; + LOG(trace) << "trace message, counter: " << i++; + LOG(debug4) << "debug4 message, counter: " << i++; + LOG(debug3) << "debug3 message, counter: " << i++; + LOG(debug2) << "debug2 message, counter: " << i++; + LOG(debug1) << "debug1 message, counter: " << i++; + LOG(debug) << "debug message, counter: " << i++; + LOG(info) << "info message, counter: " << i++; + LOG(state) << "state message, counter: " << i++; + LOG(warn) << "warning message, counter: " << i++; + LOG(error) << "error message, counter: " << i++; + LOG(fatal) << "fatal message, counter: " << i++; + + return i; +} + +void CheckSeverity(Severity severity) +{ + Logger::SetConsoleSeverity(severity); + auto sev = Logger::GetConsoleSeverity(); + + cout << "##### testing severity '" << Logger::SeverityName(sev) << "' (" << static_cast(sev) << "), Logging(): " << std::boolalpha << Logger::Logging(sev) << endl; + + for (uint32_t i = 0; i < Logger::fSeverityNames.size(); ++i) { + if (sev == Severity::nolog) { + if (i == 11) { + if (!Logger::Logging(static_cast(i))) { + throw runtime_error(ToStr("expecting to be logging ", Logger::fSeverityNames.at(i), " during ", Logger::fSeverityNames.at(static_cast(sev)), ", but it is not.")); + } + } else { + if (Logger::Logging(static_cast(i))) { + throw runtime_error(ToStr("expecting to NOT be logging ", Logger::fSeverityNames.at(i), " during ", Logger::fSeverityNames.at(static_cast(sev)), ", but it is.")); + } + } + } else { + if (i >= static_cast(sev)) { + if (!Logger::Logging(static_cast(i))) { + throw runtime_error(ToStr("expecting to be logging ", Logger::fSeverityNames.at(i), " during ", Logger::fSeverityNames.at(static_cast(sev)), ", but it is not.")); + } + } else { + if (Logger::Logging(static_cast(i))) { + throw runtime_error(ToStr("expecting to NOT be logging ", Logger::fSeverityNames.at(i), " during ", Logger::fSeverityNames.at(static_cast(sev)), ", but it is.")); + } + } + } + } + + uint32_t i = 0; + i = printEverySeverity(i); + if (sev == Severity::nolog) { + if (i != 1) { + throw runtime_error(ToStr("expected: i==1, found: i==", i)); + } + } else { + if (i != Logger::fSeverityNames.size() - static_cast(sev)) { + throw runtime_error(ToStr("expected: i==", Logger::fSeverityNames.size() - static_cast(sev) - 1, ", found: i==", i)); + } + } +} + +int main() +{ + Logger::SetConsoleColor(true); + + try { + cout << "##### testing " << Logger::fSeverityNames.size() << " severities..." << endl; + for (uint32_t i = 0; i < Logger::fSeverityNames.size(); ++i) { + CheckSeverity(static_cast(i)); + } + } catch (runtime_error& rte) { + cout << rte.what() << endl; + return 1; + } + + return 0; +} diff --git a/test/sinks.cxx b/test/sinks.cxx new file mode 100644 index 0000000..0282a9f --- /dev/null +++ b/test/sinks.cxx @@ -0,0 +1,134 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include "Common.h" +#include + +#include +#include +#include +#include + +using namespace std; +using namespace fair; +using namespace fair::logger::test; + +int main() +{ + Logger::SetConsoleColor(false); + Logger::SetVerbosity(Verbosity::low); + + Logger::SetConsoleSeverity(Severity::nolog); + + try { +#ifdef FAIR_MIN_SEVERITY + if (static_cast(Severity::FAIR_MIN_SEVERITY) > static_cast(Severity::warn)) { + cout << "test requires at least FAIR_MIN_SEVERITY == warn to run, skipping" << endl; + return 0; + } +#endif + if (Logger::Logging(Severity::warn)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; } + if (Logger::Logging(Severity::error)) { cout << "Logger expected to NOT log error, but it reports to do so" << endl; return 1; } + if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; } + + cout << "##### adding file sink with warn severity" << endl; + random_device rd; + mt19937 gen(rd()); + uniform_int_distribution<> distrib(1, 65536); + string name = Logger::InitFileSink(Severity::warn, string("test_log_" + to_string(distrib(gen))), true); + + CheckOutput("^\\[FATAL] fatal\n$", [](){ + LOG(state) << "state"; + LOG(warn) << "warning"; + LOG(error) << "error"; + LOG(fatal) << "fatal"; + }); + + if (Logger::Logging(Severity::state)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; } + if (!Logger::Logging(Severity::warn)) { cout << "Logger expected to log warn, but it reports not to" << endl; return 1; } + if (!Logger::Logging(Severity::error)) { cout << "Logger expected to log error, but it reports not to" << endl; return 1; } + if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; } + + ifstream t(name); + stringstream buffer; + buffer << t.rdbuf(); + string fileContent = buffer.str(); + + if (fileContent != "[WARN] warning\n[ERROR] error\n[FATAL] fatal\n") { + throw runtime_error(ToStr("unexpected file sink output. expected:\n[WARN] warning\n[ERROR] error\n[FATAL] fatal\nfound:\n", fileContent)); + } + + cout << "##### removing file sink with warn severity" << endl; + Logger::RemoveFileSink(); + + if (Logger::Logging(Severity::warn)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; } + if (Logger::Logging(Severity::error)) { cout << "Logger expected to NOT log error, but it reports to do so" << endl; return 1; } + if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; } + + cout << "##### adding custom sink with warn severity" << endl; + + Logger::AddCustomSink("CustomSink", "warn", [](const string& content, const LogMetaData& metadata) + { + cout << "CustomSink " << content << endl; + + if (metadata.severity != Severity::warn && metadata.severity != Severity::error && metadata.severity != Severity::fatal) { + throw runtime_error(ToStr("unexpected severity message arrived at custom sink that accepts only warn,error,fatal: ", Logger::fSeverityNames.at(static_cast(metadata.severity)))); + } + + if (metadata.severity_name != "WARN" && metadata.severity_name != "ERROR" && metadata.severity_name != "FATAL") { + throw runtime_error(ToStr("unexpected severity name arrived at custom sink that accepts only warn,error,fatal: ", metadata.severity_name)); + } + }); + + CheckOutput("^CustomSink warning\nCustomSink error\nCustomSink fatal\n\\[FATAL] fatal\n$", [](){ + LOG(state) << "state"; + LOG(warn) << "warning"; + LOG(error) << "error"; + LOG(fatal) << "fatal"; + }); + + if (Logger::Logging(Severity::state)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; } + if (!Logger::Logging(Severity::warn)) { cout << "Logger expected to log warn, but it reports not to" << endl; return 1; } + if (!Logger::Logging(Severity::error)) { cout << "Logger expected to log error, but it reports not to" << endl; return 1; } + if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; } + + + cout << "##### removing custom sink with error severity" << endl; + + bool caught = false; + try { + Logger::AddCustomSink("CustomSink", Severity::error, [](const string& /*content*/, const LogMetaData& /*metadata*/){}); + } catch (runtime_error& rte) { + caught = true; + } + if (!caught) { + throw runtime_error("expected to throw a runtime_error upon adding sink with same key, but none was thrown"); + } + + Logger::RemoveCustomSink("CustomSink"); + + if (Logger::Logging(Severity::warn)) { cout << "Logger expected to NOT log warn, but it reports to do so" << endl; return 1; } + if (Logger::Logging(Severity::error)) { cout << "Logger expected to NOT log error, but it reports to do so" << endl; return 1; } + if (!Logger::Logging(Severity::fatal)) { cout << "Logger expected to log fatal, but it reports not to" << endl; return 1; } + + caught = false; + try { + Logger::RemoveCustomSink("bla"); + } catch (runtime_error& rte) { + caught = true; + } + if (!caught) { + throw runtime_error("expected to throw a runtime_error upon removing non-existent sink, but none was thrown"); + } + } catch (runtime_error& rte) { + cout << rte.what() << endl; + return 1; + } + + return 0; +} diff --git a/test/threads.cxx b/test/threads.cxx new file mode 100644 index 0000000..c2c3e72 --- /dev/null +++ b/test/threads.cxx @@ -0,0 +1,67 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include "Common.h" +#include + +#include +#include +#include + +using namespace std; +using namespace fair; +using namespace fair::logger::test; + +void f() +{ + LOG(fatal) << "a" << "b" << "c" << "d" << "e" << "f" << "g" << "h" << "i" << "j" << "k" << "l" << "m" << "n" << "o" << "p" << "q" << "r" << "s" << "t" << "u" << "v" << "w" << "x" << "y" << "z"; +} + +int main() +{ + try { + Logger::SetConsoleColor(false); + Logger::SetConsoleSeverity(Severity::fatal); + Logger::SetVerbosity(Verbosity::veryhigh); + + CheckOutput( +R"(^\[.*]\[\d{2}:\d{2}:\d{2}\.\d{6}]\[FATAL]\[.*:\d+:.*] abcdefghijklmnopqrstuvwxyz +\[.*]\[\d{2}:\d{2}:\d{2}\.\d{6}]\[FATAL]\[.*:\d+:.*] abcdefghijklmnopqrstuvwxyz +\[.*]\[\d{2}:\d{2}:\d{2}\.\d{6}]\[FATAL]\[.*:\d+:.*] abcdefghijklmnopqrstuvwxyz +\[.*]\[\d{2}:\d{2}:\d{2}\.\d{6}]\[FATAL]\[.*:\d+:.*] abcdefghijklmnopqrstuvwxyz +\[.*]\[\d{2}:\d{2}:\d{2}\.\d{6}]\[FATAL]\[.*:\d+:.*] abcdefghijklmnopqrstuvwxyz +$)", []() { + thread t1(f); + thread t2(f); + thread t3(f); + thread t4(f); + thread t5(f); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + t5.join(); + }); + + thread t1(f); + thread t2(f); + thread t3(f); + thread t4(f); + thread t5(f); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + t5.join(); + } catch (runtime_error& rte) { + cout << rte.what() << endl; + return 1; + } + + return 0; +} diff --git a/test/verbosity.cxx b/test/verbosity.cxx new file mode 100644 index 0000000..adc462d --- /dev/null +++ b/test/verbosity.cxx @@ -0,0 +1,78 @@ +/******************************************************************************** + * Copyright (C) 2014-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include "Common.h" + +#include + +#include +#include + +using namespace std; +using namespace fair; +using namespace fair::logger::test; + +int main() +{ + Logger::SetConsoleColor(false); + Logger::SetConsoleSeverity(Severity::fatal); + + try { + auto spec1 = VerbositySpec::Make(VerbositySpec::Info::file_line_function, VerbositySpec::Info::process_name); + auto spec2 = VerbositySpec::Make(VerbositySpec::Info::process_name, VerbositySpec::Info::file_line_function); + + Logger::DefineVerbosity(Verbosity::user1, spec1); + Logger::SetVerbosity(Verbosity::user1); // spec1 on user1 + CheckOutput(ToStr(R"(^\[.*:\d{2}:.*]\[.*])", " content\n$"), []() { LOG(fatal) << "content"; }); + + Logger::DefineVerbosity(Verbosity::user1, spec2); + Logger::SetVerbosity(Verbosity::user1); // spec2 on user1 + CheckOutput(ToStr(R"(^\[.*]\[.*:\d{2}:.*])", " content\n$"), []() { LOG(fatal) << "content"; }); + + Logger::DefineVerbosity(Verbosity::user2, spec1); + Logger::SetVerbosity(Verbosity::user2); // spec1 on user2 + CheckOutput(ToStr(R"(^\[.*:\d{2}:.*]\[.*])", " content\n$"), []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::verylow); // content + CheckOutput("^content\n$", []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::low); // [severity] content + CheckOutput(ToStr(R"(^\[FATAL])", " content\n$"), []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::medium); // [HH:MM:SS][severity] content + CheckOutput(ToStr(R"(^\[\d{2}:\d{2}:\d{2}]\[FATAL])", " content\n$"), []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::high); // [process_name][HH:MM:SS][severity] content + CheckOutput(ToStr(R"(^\[.*]\[\d{2}:\d{2}:\d{2}]\[FATAL])", " content\n$"), []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::veryhigh); // [process_name][HH:MM:SS:µS][severity][file:line:function] content + CheckOutput(ToStr(R"(^\[.*]\[\d{2}:\d{2}:\d{2}\.\d{6}]\[FATAL]\[.*:\d+:.*])", " content\n$"), []() { LOG(fatal) << "content"; }); + + Logger::SetConsoleColor(true); + + Logger::SetVerbosity(Verbosity::verylow); // content + CheckOutput("^content\n$", []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::low); // [severity] content + CheckOutput("^\\[\033\\[01;31mFATAL\033\\[0m] content\n$", []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::medium); // [HH:MM:SS][severity] content + CheckOutput("^\\[\033\\[01;36m\\d{2}:\\d{2}:\\d{2}\033\\[0m]\\[\033\\[01;31mFATAL\033\\[0m] content\n$", []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::high); // [process_name][HH:MM:SS][severity] content + CheckOutput("^\\[\033\\[01;34m.*\033\\[0m]\\[\033\\[01;36m\\d{2}:\\d{2}:\\d{2}\033\\[0m]\\[\033\\[01;31mFATAL\033\\[0m] content\n$", []() { LOG(fatal) << "content"; }); + + Logger::SetVerbosity(Verbosity::veryhigh); // [process_name][HH:MM:SS:µS][severity][file:line:function] content + CheckOutput("^\\[\033\\[01;34m.*\033\\[0m]\\[\033\\[01;36m\\d{2}:\\d{2}:\\d{2}\\.\\d{6}\033\\[0m]\\[\033\\[01;31mFATAL\033\\[0m]\\[\033\\[01;34m.*\033\\[0m:\033\\[01;33m\\d+\033\\[0m:\033\\[01;34m.*\033\\[0m] content\n$", []() { LOG(fatal) << "content"; }); + } catch (runtime_error& rte) { + cout << rte.what() << endl; + return 1; + } + + return 0; +}