This commit is contained in:
Mars 2024-06-02 06:03:21 -04:00
parent 6e5045f1f4
commit 693fa17d10
Signed by: pupbrained
GPG key ID: 0FF5B8826803F895
266 changed files with 60543 additions and 1000 deletions

View file

@ -0,0 +1,143 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("arithmetic_types_logging")
{
static constexpr char const* filename = "arithmetic_types_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
BackendOptions bo;
bo.error_notifier = [](std::string const&) {};
Backend::start(bo);
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
bool b = true;
LOG_INFO(logger, "v [{}]", b);
char c = 'a';
LOG_INFO(logger, "c [{}]", c);
short int si = -12;
LOG_INFO(logger, "si [{}]", si);
int i = -123;
LOG_INFO(logger, "i [{}]", i);
long int li = 9876;
LOG_INFO(logger, "li [{}]", li);
long long int lli = 321;
LOG_INFO(logger, "lli [{}]", lli);
unsigned short int usi = 15;
LOG_INFO(logger, "usi [{}]", usi);
unsigned int ui = 123;
LOG_INFO(logger, "ui [{}]", ui);
unsigned long int uli = 2876;
LOG_INFO(logger, "uli [{}]", uli);
unsigned long long int ulli = 1321;
LOG_INFO(logger, "ulli [{}]", ulli);
float f = 323.31f;
LOG_INFO(logger, "f [{}]", f);
double d = 3213213.123;
LOG_INFO(logger, "d [{}]", d);
int const& cri = i;
LOG_INFO(logger, "cri [{}]", cri);
int& ci = i;
LOG_INFO(logger, "ci [{}]", ci);
LOG_INFO(logger, "invalid format [{%f}]", 321.1);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
REQUIRE_FALSE(Backend::is_running());
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " v [true]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c [a]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli [2876]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [1321]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f [323.31]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d [3213213.123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123]"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" [Could not format log statement. message: \"invalid format [{%f}]\""}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,116 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
#if !defined(QUILL_NO_EXCEPTIONS)
/***/
TEST_CASE("backend_exception_notifier")
{
static constexpr char const* filename = "backend_exception_notifier.log";
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger("logger", std::move(file_sink));
// counter to check our error handler was invoked
// atomic because we check this value on this thread, but the backend worker thread updates it
std::atomic<size_t> error_notifier_invoked{0};
// Set invalid thread name
BackendOptions backend_options;
// Setting to an invalid CPU. When we call quill::start() our error handler will be invoked and an error will be logged
backend_options.backend_cpu_affinity = static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() - 1);
backend_options.thread_name =
"Lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt_ut_"
"labore_et_dolore_magna_aliqua";
backend_options.error_notifier = [logger, &error_notifier_invoked](std::string const& error_message)
{
// Log inside the function from the backend thread, for testing
// Note that this log is asynchronous here which means when error_notifier_invoked is
// incremented does not mean we have logged this yet
// flush_log() is not permitted inside this callback
LOG_WARNING(logger, "error handler invoked {}", error_message);
error_notifier_invoked.fetch_add(1);
};
Backend::start(backend_options);
// Log a message and wait for it to get processed, that way we know the backend thread has started
LOG_INFO(logger, "frontend");
logger->flush_log();
// Check our handler was invoked since either set_backend_thread_name or set_backend_thread_cpu_affinity should have failed
REQUIRE_GE(error_notifier_invoked.load(), 1);
// Now we can try to get another exception by calling LOG_BACKTRACE without calling init first
error_notifier_invoked.store(0);
LOG_BACKTRACE(logger, "Backtrace message");
logger->flush_log();
// Check our handler was invoked
REQUIRE_EQ(error_notifier_invoked.load(), 1);
// Pass an invalid fmt format and see if it throws
error_notifier_invoked.store(0);
LOG_INFO(logger, "Format {:>321.}", 321.3);
logger->flush_log();
// Check our handler was invoked
REQUIRE_EQ(error_notifier_invoked.load(), 1);
// Wait until the backend thread stops for test stability
Backend::stop();
// After the backend has stopped, all messages include the async ones from the notifier will
// be in the log file. At this point we can safely check it
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_GE(file_contents.size(), 5);
// Look for the async errors
std::string const expected_string_1 = "error handler invoked Failed to set cpu affinity ";
std::string const expected_string_2 = "error handler invoked Failed to set thread name ";
bool const has_any_error = quill::testing::file_contains(file_contents, expected_string_1) ||
quill::testing::file_contains(file_contents, expected_string_2);
REQUIRE(has_any_error);
std::string const expected_string_3 = "error handler invoked logger->init_backtrace(...)";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
std::string const expected_string_4 = "error handler invoked [Could not format log statement.";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
testing::remove_file(filename);
}
#endif

View file

@ -0,0 +1,90 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <thread>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backend_long_sleep_and_notify")
{
static constexpr size_t number_of_messages = 100u;
static constexpr size_t number_of_threads = 4;
static constexpr char const* filename = "log_backend_long_sleep_and_notify.log";
static std::string const logger_name_prefix = "logger_";
// Start the backend thread
BackendOptions backend_options;
backend_options.sleep_duration = std::chrono::hours{24};
Backend::start(backend_options);
std::vector<std::thread> threads;
for (size_t i = 0; i < number_of_threads; ++i)
{
threads.emplace_back(
[i]() mutable
{
// Also use preallocate
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger =
Frontend::create_or_get_logger(logger_name_prefix + std::to_string(i), std::move(file_sink));
for (size_t j = 0; j < number_of_messages; ++j)
{
LOG_INFO(logger, "Hello from thread {thread_index} this is message {message_num}", i, j);
}
});
}
for (auto& elem : threads)
{
elem.join();
}
// The backend worker is still sleeping here so no file should exist
REQUIRE_EQ(testing::file_contents(filename).size(), 0);
// Notify the backend to wake up and process
Backend::notify();
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads);
for (size_t i = 0; i < number_of_threads; ++i)
{
// for each thread
for (size_t j = 0; j < number_of_messages; ++j)
{
std::string expected_string = logger_name_prefix + std::to_string(i) +
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j);
REQUIRE(testing::file_contains(file_contents, expected_string));
}
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,91 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <thread>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backend_transit_buffer_hard_limit")
{
static constexpr size_t number_of_messages = 500u;
static constexpr size_t number_of_threads = 10;
static constexpr char const* filename = "backend_transit_buffer_hard_limit.log";
static std::string const logger_name_prefix = "logger_";
// Start the backend thread
BackendOptions backend_options;
backend_options.transit_events_hard_limit = 0;
backend_options.transit_event_buffer_initial_capacity = 0;
Backend::start(backend_options);
std::vector<std::thread> threads;
for (size_t i = 0; i < number_of_threads; ++i)
{
threads.emplace_back(
[i]() mutable
{
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger =
Frontend::create_or_get_logger(logger_name_prefix + std::to_string(i), std::move(file_sink));
for (size_t j = 0; j < number_of_messages; ++j)
{
LOG_INFO(logger, "Hello from thread {thread_index} this is message {message_num}", i, j);
}
});
}
for (auto& elem : threads)
{
elem.join();
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads);
for (size_t i = 0; i < number_of_threads; ++i)
{
// for each thread
for (size_t j = 0; j < number_of_messages; ++j)
{
std::string expected_string = logger_name_prefix + std::to_string(i) +
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j);
REQUIRE(testing::file_contains(file_contents, expected_string));
}
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,75 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <thread>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backend_transit_buffer_soft_limit")
{
static constexpr char const* filename = "backend_transit_buffer_soft_limit.log";
static std::string const logger_name = "logger";
size_t constexpr soft_limit = 100;
// First log some messages and then start the backend worker thread so that the soft limit is hit
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
for (size_t i = 0; i < soft_limit * 2; ++i)
{
// log all messages
LOG_INFO(logger, "Message num {}", i);
}
// Start the backend thread
BackendOptions backend_options;
backend_options.transit_events_soft_limit = soft_limit;
Backend::start(backend_options);
// log more messages after the backend started
for (size_t i = soft_limit * 2; i < soft_limit * 4; ++i)
{
// log all messages
LOG_INFO(logger, "Message num {}", i);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = testing::file_contents(filename);
size_t const total_messages = soft_limit * 4;
REQUIRE_EQ(file_contents.size(), total_messages);
for (size_t i = 0; i < total_messages; ++i)
{
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Message num "} + std::to_string(i)));
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,83 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backtrace_dynamic_log_level")
{
static constexpr char const* filename = "backtrace_dynamic_log_level.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
// Enable backtrace for 2 messages for error
logger->init_backtrace(2, LogLevel::Error);
// log using dynamic log level and flush on warning instead
LOG_DYNAMIC(logger, LogLevel::Info, "Before dynamic backtrace log");
for (size_t i = 100; i < 120; ++i)
{
#if defined(__aarch64__) || ((__ARM_ARCH >= 6) || defined(_M_ARM64))
// On ARM we add a small delay because log messages can get the same timestamp from rdtsc
// when in this loop and make the test unstable
std::this_thread::sleep_for(std::chrono::microseconds{200});
#endif
LOG_DYNAMIC(logger, LogLevel::Backtrace, "Dynamic backtrace log {}", i);
}
LOG_DYNAMIC(logger, LogLevel::Error, "After dynamic error");
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 4);
std::string expected_string_1 =
"LOG_INFO " + logger_name + " Before dynamic backtrace log";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
std::string expected_string_2 = "LOG_ERROR " + logger_name + " After dynamic error";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
std::string expected_string_3 =
"LOG_BACKTRACE " + logger_name + " Dynamic backtrace log 118";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
std::string expected_string_4 =
"LOG_BACKTRACE " + logger_name + " Dynamic backtrace log 119";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
testing::remove_file(filename);
}

View file

@ -0,0 +1,79 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backtrace_flush_on_error")
{
static constexpr char const* filename = "backtrace_flush_on_error.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
// Enable backtrace for 2 messages for error
logger->init_backtrace(2, LogLevel::Error);
// flush backtrace on error
LOG_INFO(logger, "Before backtrace log");
for (size_t i = 0; i < 12; ++i)
{
#if defined(__aarch64__) || ((__ARM_ARCH >= 6) || defined(_M_ARM64))
// On ARM we add a small delay because log messages can get the same timestamp from rdtsc
// when in this loop and make the test unstable
std::this_thread::sleep_for(std::chrono::microseconds{200});
#endif
LOG_BACKTRACE(logger, "Backtrace log {}", i);
}
LOG_ERROR(logger, "After error");
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 4);
std::string expected_string_1 = "LOG_INFO " + logger_name + " Before backtrace log";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
std::string expected_string_2 = "LOG_ERROR " + logger_name + " After error";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
std::string expected_string_3 = "LOG_BACKTRACE " + logger_name + " Backtrace log 10";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
std::string expected_string_4 = "LOG_BACKTRACE " + logger_name + " Backtrace log 11";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
testing::remove_file(filename);
}

View file

@ -0,0 +1,76 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backtrace_manual_flush")
{
static constexpr char const* filename = "backtrace_manual_flush.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
// Enable backtrace for 2 messages for error
logger->init_backtrace(2, LogLevel::Error);
// flush backtrace on error
LOG_INFO(logger, "Before backtrace log");
for (size_t i = 0; i < 12; ++i)
{
#if defined(__aarch64__) || ((__ARM_ARCH >= 6) || defined(_M_ARM64))
// On ARM we add a small delay because log messages can get the same timestamp from rdtsc
// when in this loop and make the test unstable
std::this_thread::sleep_for(std::chrono::microseconds{200});
#endif
LOG_BACKTRACE(logger, "Backtrace log {}", i);
}
logger->flush_backtrace();
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 3);
std::string expected_string_1 = "LOG_INFO " + logger_name + " Before backtrace log";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
std::string expected_string_3 = "LOG_BACKTRACE " + logger_name + " Backtrace log 10";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
std::string expected_string_4 = "LOG_BACKTRACE " + logger_name + " Backtrace log 11";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
testing::remove_file(filename);
}

View file

@ -0,0 +1,70 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backtrace_no_flush")
{
static constexpr char const* filename = "backtrace_no_flush.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
// Enable backtrace for 2 messages for warning
logger->init_backtrace(2, LogLevel::Error);
// try with LOG_WARNING and expect no flush
LOG_INFO(logger, "Before backtrace log retry");
for (size_t i = 0; i < 12; ++i)
{
LOG_BACKTRACE(logger, "Backtrace log {}", i);
}
LOG_WARNING(logger, "After backtrace log retry");
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 2);
std::string expected_string_1 =
"LOG_INFO " + logger_name + " Before backtrace log retry";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
std::string expected_string_2 =
"LOG_WARNING " + logger_name + " After backtrace log retry";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
testing::remove_file(filename);
}

View file

@ -0,0 +1,105 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("backtrace_terminated_thread_flush")
{
// In this test we store in backtrace from one thread that terminates
// then we log that backtrace from a different thread
static constexpr char const* filename = "backtrace_terminated_thread_flush.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
std::thread thread_a(
[]()
{
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
// Get a logger and enable backtrace
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
// Enable backtrace for 2 messages
logger->init_backtrace(2, LogLevel::Error);
LOG_INFO(logger, "Before backtrace log");
for (uint32_t i = 0; i < 12; ++i)
{
LOG_BACKTRACE(logger, "Backtrace message {}", i);
}
});
thread_a.join();
// thread_a logged something in backtrace and finished.
// Now we spawn a different thread and LOG_ERROR
// we expect to see the backtrace from the previous thread
std::thread thread_b(
[]()
{
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
// Get a logger and enable backtrace
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
LOG_ERROR(logger, "After error");
logger->flush_log();
Frontend::remove_logger(logger);
});
thread_b.join();
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 4);
std::string expected_string_1 = "LOG_INFO " + logger_name + " Before backtrace log";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
std::string expected_string_2 = "LOG_ERROR " + logger_name + " After error";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
std::string expected_string_3 = "LOG_BACKTRACE " + logger_name + " Backtrace message 10";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
std::string expected_string_4 = "LOG_BACKTRACE " + logger_name + " Backtrace message 11";
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
testing::remove_file(filename);
}

View file

@ -0,0 +1,78 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <string>
#include <vector>
using namespace quill;
// Define custom Frontend Options
struct CustomFrontendOptions
{
static constexpr quill::QueueType queue_type = quill::QueueType::BoundedBlocking;
static constexpr uint32_t initial_queue_capacity = 131'072;
static constexpr uint32_t blocking_queue_retry_interval_ns = 800;
static constexpr bool huge_pages_enabled = false;
};
using CustomFrontend = FrontendImpl<CustomFrontendOptions>;
using CustomLogger = LoggerImpl<CustomFrontendOptions>;
TEST_CASE("bounded_blocking_queue")
{
static constexpr char const* filename = "bounded_blocking_queue.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
auto file_sink = CustomFrontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
CustomLogger* logger = CustomFrontend::create_or_get_logger(logger_name, std::move(file_sink));
for (int i = 0; i < 5000; ++i)
{
LOG_INFO(logger, "Log something to fulfill the bound queue {}", i);
LOG_WARNING(logger, "Log something to fulfill the bound queue {}", i);
LOG_ERROR(logger, "Log something to fulfill the bound queue {}", i);
}
logger->flush_log();
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check the first messages as we can't if some were dropped
std::vector<std::string> const file_contents = testing::file_contents(filename);
for (int i = 0; i < 5000; ++i)
{
std::string expected_string_1 = "LOG_INFO " + logger_name +
" Log something to fulfill the bound queue " + std::to_string(i);
std::string expected_string_2 = "LOG_WARNING " + logger_name +
" Log something to fulfill the bound queue " + std::to_string(i);
std::string expected_string_3 = "LOG_ERROR " + logger_name +
" Log something to fulfill the bound queue " + std::to_string(i);
REQUIRE(testing::file_contains(file_contents, expected_string_1));
REQUIRE(testing::file_contains(file_contents, expected_string_2));
REQUIRE(testing::file_contains(file_contents, expected_string_3));
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,78 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <string>
#include <vector>
using namespace quill;
// Define custom Frontend Options
struct CustomFrontendOptions
{
static constexpr quill::QueueType queue_type = quill::QueueType::BoundedDropping;
static constexpr uint32_t initial_queue_capacity = 131'072;
static constexpr uint32_t blocking_queue_retry_interval_ns = 800;
static constexpr bool huge_pages_enabled = false;
};
using CustomFrontend = FrontendImpl<CustomFrontendOptions>;
using CustomLogger = LoggerImpl<CustomFrontendOptions>;
TEST_CASE("bounded_dropping_queue")
{
static constexpr char const* filename = "bounded_dropping_queue.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
auto file_sink = CustomFrontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
CustomLogger* logger = CustomFrontend::create_or_get_logger(logger_name, std::move(file_sink));
for (int i = 0; i < 5000; ++i)
{
LOG_INFO(logger, "Log something to fulfill the bound queue {}", i);
LOG_WARNING(logger, "Log something to fulfill the bound queue {}", i);
LOG_ERROR(logger, "Log something to fulfill the bound queue {}", i);
}
logger->flush_log();
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check the first messages as we can't if some were dropped
std::vector<std::string> const file_contents = testing::file_contents(filename);
for (int i = 0; i < 100; ++i)
{
std::string expected_string_1 = "LOG_INFO " + logger_name +
" Log something to fulfill the bound queue " + std::to_string(i);
std::string expected_string_2 = "LOG_WARNING " + logger_name +
" Log something to fulfill the bound queue " + std::to_string(i);
std::string expected_string_3 = "LOG_ERROR " + logger_name +
" Log something to fulfill the bound queue " + std::to_string(i);
REQUIRE(testing::file_contains(file_contents, expected_string_1));
REQUIRE(testing::file_contains(file_contents, expected_string_2));
REQUIRE(testing::file_contains(file_contents, expected_string_3));
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,109 @@
function(quill_add_test TEST_NAME SOURCES)
set(HEADER_FILES
${PROJECT_SOURCE_DIR}/quill/test/bundled/doctest/doctest.h
${PROJECT_SOURCE_DIR}/quill/test/misc/TestUtilities.h
)
set(ADD_SOURCE_FILES
${PROJECT_SOURCE_DIR}/quill/test/misc/TestMain.cpp
${PROJECT_SOURCE_DIR}/quill/test/misc/TestUtilities.cpp
${PROJECT_SOURCE_DIR}/quill/test/misc/DocTestExtensions.cpp)
list(APPEND SOURCES ${ADD_SOURCE_FILES})
# Create a test executable
add_executable(${TEST_NAME} "")
set_common_compile_options(${TEST_NAME})
# Add sources
target_sources(${TEST_NAME} PRIVATE ${SOURCES} ${HEADER_FILES})
# include dirs
target_include_directories(${TEST_NAME}
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/quill/test/misc>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/quill/test/bundled>
$<INSTALL_INTERFACE:include>
PRIVATE
${PROJECT_SOURCE_DIR}/quill/test)
# Link dependencies
target_link_libraries(${TEST_NAME} quill)
# Do not decay cxx standard if not specified
set_property(TARGET ${TEST_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
# Set output test directory
set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/test)
# Add this target to the post build unit tests
doctest_discover_tests(${TEST_NAME})
endfunction()
include(${PROJECT_SOURCE_DIR}/cmake/doctest.cmake)
quill_add_test(TEST_ArithmeticTypesLogging ArithmeticTypesLoggingTest.cpp)
quill_add_test(TEST_BackendExceptionNotifier BackendExceptionNotifierTest.cpp)
quill_add_test(TEST_BackendLongSleepAndNotify BackendLongSleepAndNotifyTest.cpp)
quill_add_test(TEST_BackendTransitBufferHardLimit BackendTransitBufferHardLimitTest.cpp)
quill_add_test(TEST_BackendTransitBufferSoftLimit BackendTransitBufferSoftLimitTest.cpp)
quill_add_test(TEST_BacktraceDynamicLogLevel BacktraceDynamicLogLevelTest.cpp)
quill_add_test(TEST_BacktraceFlushOnError BacktraceFlushOnErrorTest.cpp)
quill_add_test(TEST_BacktraceManualFlush BacktraceManualFlushTest.cpp)
quill_add_test(TEST_BacktraceNoFlush BacktraceNoFlushTest.cpp)
quill_add_test(TEST_BacktraceTerminatedThreadFlush BacktraceTerminatedThreadFlushTest.cpp)
quill_add_test(TEST_BoundedBlockingQueue BoundedBlockingQueueTest.cpp)
quill_add_test(TEST_BoundedDroppingQueue BoundedDroppingQueueTest.cpp)
quill_add_test(TEST_ConsoleSinkStderrMultipleFormats ConsoleSinkStderrMultipleFormatsTest.cpp)
quill_add_test(TEST_ConsoleSinkStdoutMultipleFormats ConsoleSinkStdoutMultipleFormatsTest.cpp)
quill_add_test(TEST_LoggerAddRemoveGet LoggerAddRemoveGetTest.cpp)
quill_add_test(TEST_EnumLogging EnumLoggingTest.cpp)
quill_add_test(TEST_FlushWithoutAnyLog FlushWithoutAnyLog.cpp)
quill_add_test(TEST_JsonConsoleLoggingTest JsonConsoleLoggingTest.cpp)
quill_add_test(TEST_JsonFileLogging JsonFileLoggingTest.cpp)
quill_add_test(TEST_LogArgumentsEvaluation LogArgumentsEvaluationTest.cpp)
quill_add_test(TEST_LogFlushWithSoftLimit LogFlushWithSoftLimitTest.cpp)
quill_add_test(TEST_MultiFrontendThreads MultiFrontendThreadsTest.cpp)
quill_add_test(TEST_MultipleSinksSameLogger MultipleSinksSameLoggerTest.cpp)
quill_add_test(TEST_RotatingSinkDailyRotation RotatingSinkDailyRotationTest.cpp)
quill_add_test(TEST_RotatingSinkKeepOldest RotatingSinkKeepOldestTest.cpp)
quill_add_test(TEST_RotatingSinkOverwriteOldest RotatingSinkOverwriteOldestTest.cpp)
quill_add_test(TEST_SignalHandler SignalHandlerTest.cpp)
quill_add_test(TEST_SingleFrontendThread SingleFrontendThreadTest.cpp)
quill_add_test(TEST_SinkFilter SinkFilterTest.cpp)
quill_add_test(TEST_StdArrayLogging StdArrayLoggingTest.cpp)
quill_add_test(TEST_StdDequeLogging StdDequeLoggingTest.cpp)
quill_add_test(TEST_StdFilesystemPathLogging StdFilesystemPathLoggingTest.cpp)
quill_add_test(TEST_StdForwardListLogging StdForwardListLoggingTest.cpp)
quill_add_test(TEST_StdListLogging StdListLoggingTest.cpp)
quill_add_test(TEST_StdMapLogging StdMapLoggingTest.cpp)
quill_add_test(TEST_StdMultiMapLogging StdMultiMapLoggingTest.cpp)
quill_add_test(TEST_StdMultiSetLogging StdMultiSetLoggingTest.cpp)
quill_add_test(TEST_StdOptionalLogging StdOptionalLoggingTest.cpp)
quill_add_test(TEST_StdPairLogging StdPairLoggingTest.cpp)
quill_add_test(TEST_StdSetLogging StdSetLoggingTest.cpp)
quill_add_test(TEST_StdTupleLogging StdTupleLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedMapLogging StdUnorderedMapLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedMultiMapLogging StdUnorderedMultiMapLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedMultiSetLogging StdUnorderedMultiSetLoggingTest.cpp)
quill_add_test(TEST_StdUnorderedSetLogging StdUnorderedSetLoggingTest.cpp)
quill_add_test(TEST_StdVectorLogging StdVectorLoggingTest.cpp)
quill_add_test(TEST_SinkLogLevelFilter SinkLogLevelFilterTest.cpp)
quill_add_test(TEST_StringLargeLogging StringLargeLoggingTest.cpp)
quill_add_test(TEST_StringLoggingDynamicLogLevel StringLoggingDynamicLogLevelTest.cpp)
quill_add_test(TEST_StringLogging StringLoggingTest.cpp)
quill_add_test(TEST_StringRandomLargeLogging StringRandomLargeLoggingTest.cpp)
quill_add_test(TEST_StringRandomLogging StringRandomLoggingTest.cpp)
quill_add_test(TEST_StringRandomSmallLogging StringRandomSmallLoggingTest.cpp)
quill_add_test(TEST_TagsLogging TagsLoggingTest.cpp)
quill_add_test(TEST_UserClockSource UserClockSourceTest.cpp)
quill_add_test(TEST_UserDefinedTypeLogging UserDefinedTypeLoggingTest.cpp)
quill_add_test(TEST_CompileActiveLogLevel CompileActiveLogLevelTest.cpp)
target_compile_definitions(TEST_CompileActiveLogLevel PRIVATE -DQUILL_COMPILE_ACTIVE_LOG_LEVEL=QUILL_COMPILE_ACTIVE_LOG_LEVEL_WARNING)
if (WIN32)
quill_add_test(TEST_WideStdTypesLogging WideStdTypesLoggingTest.cpp)
quill_add_test(TEST_WideStringLogging WideStringLoggingTest.cpp)
endif ()

View file

@ -0,0 +1,67 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("compile_active_log_level")
{
// we build this target with
// add_compile_definitions(-DQUILL_COMPILE_ACTIVE_LOG_LEVEL=QUILL_COMPILE_ACTIVE_LOG_LEVEL_WARNING)
static constexpr char const* filename = "compile_active_log_level.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
logger->set_log_level(quill::LogLevel::TraceL3);
REQUIRE_EQ(logger->get_log_level(), quill::LogLevel::TraceL3);
LOG_TRACE_L3(logger, "This is a log trace l3 example {}", 1);
LOG_TRACE_L2(logger, "This is a log trace l2 example {} {}", 2, 2.3);
LOG_TRACE_L1(logger, "This is a log trace l1 {} example", "string");
LOG_DEBUG(logger, "This is a log debug example {}", 4);
LOG_INFO(logger, "This is a log info example {}", 21);
LOG_WARNING(logger, "This is a log warning example {}", 11);
LOG_ERROR(logger, "This is a log error example {}", 3212);
LOG_CRITICAL(logger, "This is a log critical example {}", 321);
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check, we only except statements above warning
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 3);
REQUIRE(quill::testing::file_contains(file_contents, std::string{"This is a log warning example 11"}));
REQUIRE(quill::testing::file_contains(file_contents, std::string{"This is a log error example 3212"}));
REQUIRE(quill::testing::file_contains(file_contents, std::string{"This is a log critical example 321"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,97 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/bundled/fmt/format.h"
#include "quill/bundled/fmt/ranges.h"
#include "quill/sinks/ConsoleSink.h"
#include <cstdio>
#include <sstream>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("console_sink_stderr_multiple_formats")
{
static std::string const logger_name_a = "logger_a";
static std::string const logger_name_b = "logger_b";
// Start the logging backend thread
Backend::start();
quill::testing::CaptureStderr();
// Set writing logging to a file
bool const using_colours = false;
std::string const stream = "stderr";
auto console_sink = Frontend::create_or_get_sink<ConsoleSink>("console_sink", using_colours, stream);
Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink);
Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink,
"%(logger) - %(message) (%(caller_function))");
console_sink.reset();
// log a few messages so we rotate files
for (size_t i = 0; i < 20; ++i)
{
if (i % 2 == 0)
{
LOG_INFO(logger_a, "Hello log num {}", i);
}
else
{
LOG_INFO(logger_b, "Hello log num {}", i);
}
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// convert result to vector
std::string results = quill::testing::GetCapturedStderr();
std::stringstream data(results);
std::string line;
std::vector<std::string> result_arr;
while (std::getline(data, line, '\n'))
{
result_arr.push_back(line);
}
for (uint32_t i = 0; i < 20; ++i)
{
if (i % 2 == 0)
{
std::string expected_string =
"LOG_INFO " + logger_name_a + " Hello log num " + std::to_string(i);
if (!quill::testing::file_contains(result_arr, expected_string))
{
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
}
}
else
{
std::string expected_string =
logger_name_b + " - Hello log num " + std::to_string(i) + " (DOCTEST_ANON_FUNC_2)";
if (!quill::testing::file_contains(result_arr, expected_string))
{
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
}
}
}
}

View file

@ -0,0 +1,97 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/bundled/fmt/format.h"
#include "quill/bundled/fmt/ranges.h"
#include "quill/sinks/ConsoleSink.h"
#include <cstdio>
#include <sstream>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("console_sink_stdout_multiple_formats")
{
static std::string const logger_name_a = "logger_a";
static std::string const logger_name_b = "logger_b";
// Start the logging backend thread
Backend::start();
quill::testing::CaptureStdout();
// Set writing logging to a file
bool const using_colours = false;
std::string const stream = "stdout";
auto console_sink = Frontend::create_or_get_sink<ConsoleSink>("console_sink", using_colours, stream);
Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink);
Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink,
"%(logger) - %(message) (%(caller_function))");
console_sink.reset();
// log a few messages so we rotate files
for (size_t i = 0; i < 20; ++i)
{
if (i % 2 == 0)
{
LOG_INFO(logger_a, "Hello log num {}", i);
}
else
{
LOG_INFO(logger_b, "Hello log num {}", i);
}
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// convert result to vector
std::string results = quill::testing::GetCapturedStdout();
std::stringstream data(results);
std::string line;
std::vector<std::string> result_arr;
while (std::getline(data, line, '\n'))
{
result_arr.push_back(line);
}
for (uint32_t i = 0; i < 20; ++i)
{
if (i % 2 == 0)
{
std::string expected_string =
"LOG_INFO " + logger_name_a + " Hello log num " + std::to_string(i);
if (!quill::testing::file_contains(result_arr, expected_string))
{
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
}
}
else
{
std::string expected_string =
logger_name_b + " - Hello log num " + std::to_string(i) + " (DOCTEST_ANON_FUNC_2)";
if (!quill::testing::file_contains(result_arr, expected_string))
{
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
}
}
}
}

View file

@ -0,0 +1,121 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/bundled/fmt/format.h"
#include "quill/bundled/fmt/ostream.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
enum TestEnum : int
{
Test1 = 1,
Test2 = 2,
Test3 = 3
};
std::ostream& operator<<(std::ostream& os, TestEnum const& test_enum)
{
switch (test_enum)
{
case TestEnum::Test1:
os << "Test1";
break;
case TestEnum::Test2:
os << "Test2";
break;
case TestEnum::Test3:
os << "Test3";
break;
default:
os << "Unknown";
break;
}
return os;
}
template <>
struct fmtquill::formatter<TestEnum> : fmtquill::ostream_formatter
{
};
enum class TestEnumClass : uint64_t
{
Test4 = 4,
Test5 = 5,
Test6 = 6
};
std::ostream& operator<<(std::ostream& os, const TestEnumClass& test_enum_class)
{
switch (test_enum_class)
{
case TestEnumClass::Test4:
os << "Test4";
break;
case TestEnumClass::Test5:
os << "Test5";
break;
case TestEnumClass::Test6:
os << "Test6";
break;
default:
os << "Unknown";
break;
}
return os;
}
template <>
struct fmtquill::formatter<TestEnumClass> : fmtquill::ostream_formatter
{
};
/***/
TEST_CASE("enum_logging")
{
static constexpr char const* filename = "enum_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
LOG_INFO(logger, "{} -> {}, {} -> {}", TestEnum::Test1, static_cast<int>(TestEnum::Test1),
TestEnumClass::Test4, static_cast<uint64_t>(TestEnumClass::Test4));
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
std::string expected_string = "LOG_INFO " + logger_name + " Test1 -> 1, Test4 -> 4";
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
testing::remove_file(filename);
}

View file

@ -0,0 +1,56 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("flush_without_any_log")
{
static constexpr char const* filename = "flush_without_any_log.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
std::atomic<bool> is_flush_done = false;
std::thread watcher(
[&is_flush_done]()
{
uint32_t try_count = 2000;
while (!is_flush_done.load() && try_count--)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
REQUIRE_EQ(is_flush_done.load(), true);
});
logger->flush_log();
is_flush_done = true;
watcher.join();
Backend::stop();
testing::remove_file(filename);
}

View file

@ -0,0 +1,71 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/JsonConsoleSink.h"
#include "quill/bundled/fmt/format.h"
#include <cstdio>
#include <sstream>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("json_console_logging")
{
static constexpr size_t number_of_messages = 50;
static std::string const logger_name_a = "logger_a";
// Start the logging backend thread
Backend::start();
quill::testing::CaptureStdout();
// Set writing logging to a file
auto console_sink = Frontend::create_or_get_sink<JsonConsoleSink>("json_console");
Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink);
// log a few messages
for (size_t i = 0; i < number_of_messages; ++i)
{
LOG_INFO(logger_a, "Hello log num [{num}, {multiply}, {add}]", i, i * i, i + i);
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// convert result to vector
std::string results = quill::testing::GetCapturedStdout();
std::stringstream data(results);
std::string line;
std::vector<std::string> file_contents;
while (std::getline(data, line, '\n'))
{
file_contents.push_back(line);
}
REQUIRE_EQ(file_contents.size(), number_of_messages);
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string const expected_format =
R"("logger_a","log_level":"INFO","message":"Hello log num [{{num}}, {{multiply}}, {{add}}]","num":"{}","multiply":"{}","add":"{}")";
std::string const expected_string =
fmtquill::format(fmtquill::runtime(expected_format), i, i * i, i + i);
REQUIRE(testing::file_contains(file_contents, expected_string));
}
}

View file

@ -0,0 +1,180 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/bundled/fmt/format.h"
#include "quill/bundled/fmt/ostream.h"
#include "quill/sinks/JsonFileSink.h"
#include <cstdio>
#include <optional>
#include <string>
#include <thread>
#include <vector>
using namespace quill;
class UserDefinedType
{
public:
UserDefinedType() = default;
UserDefinedType(size_t i, std::string const& s) : _i(i), _s(s) {}
virtual ~UserDefinedType() = default;
friend std::ostream& operator<<(std::ostream& os, UserDefinedType const& obj)
{
if (obj._i && obj._s)
{
os << "i: " << *obj._i << ", s: " << *obj._s;
}
return os;
}
private:
std::optional<size_t> _i;
std::optional<std::string> _s;
};
template <>
struct fmtquill::formatter<UserDefinedType> : fmtquill::ostream_formatter
{
};
/***/
TEST_CASE("json_file_logging")
{
static constexpr size_t number_of_messages = 500u;
static constexpr size_t number_of_threads = 6;
static constexpr char const* json_filename = "json_file_logging.json";
static constexpr char const* filename = "json_file_logging_file.log";
static std::string const logger_name_prefix = "logger_";
// Start the logging backend thread
BackendOptions bo;
bo.error_notifier = [](std::string const&) {};
Backend::start(bo);
std::vector<std::thread> threads;
for (size_t i = 0; i < number_of_threads; ++i)
{
threads.emplace_back(
[i]() mutable
{
// log to json
auto json_file_sink = Frontend::create_or_get_sink<JsonFileSink>(
json_filename,
[]()
{
JsonFileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(
logger_name_prefix + std::to_string(i),
std::initializer_list<std::shared_ptr<Sink>>{std::move(json_file_sink), std::move(file_sink)},
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) "
"%(message) [%(named_args)]");
if (i == 0)
{
// log a message without any args, only from the first thread
LOG_INFO(logger, "Hello from thread");
}
for (size_t j = 0; j < number_of_messages; ++j)
{
LOG_INFO(logger,
"Hello from thread {thread_index} this is message {message_num} [{custom}]", i,
j, fmtquill::format("{}", UserDefinedType{j, std::to_string(j)}));
}
if (i == 0)
{
// log an invalid format for testing, only from the first thread
LOG_INFO(logger, "invalid format [{%f}]", 321.1);
}
});
}
for (auto& elem : threads)
{
elem.join();
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(json_filename);
std::vector<std::string> const file_contents_s = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads + 2);
REQUIRE_EQ(file_contents_s.size(), number_of_messages * number_of_threads + 2);
for (size_t i = 0; i < number_of_threads; ++i)
{
// for each thread
for (size_t j = 0; j < number_of_messages; ++j)
{
// check json log
std::string expected_json_string = std::string{"\"logger\":\""} + logger_name_prefix +
std::to_string(i) +
std::string{
"\",\"log_level\":\"INFO\",\"message\":\"Hello from thread {thread_index} this is "
"message {message_num} [{custom}]\","} +
std::string{"\"thread_index\":\""} + std::to_string(i) +
std::string{"\",\"message_num\":\""} + std::to_string(j) +
std::string{"\",\"custom\":\"i: "} + std::to_string(j) + ", s: " + std::to_string(j) +
std::string{"\""};
REQUIRE(quill::testing::file_contains(file_contents, expected_json_string));
// check standard log
// for each thread [i: 0, s: 0]
std::string expected_string = logger_name_prefix + std::to_string(i) +
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j) +
+" [i: " + std::to_string(j) + ", s: " + std::to_string(j) +
"] [thread_index: " + std::to_string(i) + ", message_num: " + std::to_string(j) + ", ";
REQUIRE(quill::testing::file_contains(file_contents_s, expected_string));
}
std::string expected_no_args_json = "\"log_level\":\"INFO\",\"message\":\"Hello from thread\"";
std::string expected_no_args_fmt = "Hello from thread";
REQUIRE(quill::testing::file_contains(file_contents, expected_no_args_json));
REQUIRE(quill::testing::file_contains(file_contents_s, expected_no_args_fmt));
std::string expected_invalid_fmt_json =
"\"log_level\":\"INFO\",\"message\":\"invalid format [{%f}]\"";
std::string expected_invalid_fmt = "invalid format [{%f}]\", location: \"";
REQUIRE(quill::testing::file_contains(file_contents, expected_invalid_fmt_json));
REQUIRE(quill::testing::file_contains(file_contents_s, expected_invalid_fmt));
}
testing::remove_file(json_filename);
testing::remove_file(filename);
}

View file

@ -0,0 +1,67 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("log_arguments_evaluation")
{
static constexpr char const* filename = "log_arguments_evaluation.log";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
std::string const logger_name = "logger";
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
size_t cnt{0};
auto arg_str = [&cnt]()
{
++cnt;
return "expensive_calculation";
};
// 1. checks that log arguments are not evaluated when we don't log
logger->set_log_level(quill::LogLevel::Info);
LOG_DEBUG(logger, "Test log arguments {}", arg_str());
LOG_TRACE_L1(logger, "Test log arguments {}", arg_str());
REQUIRE_EQ(cnt, 0);
// 2. checks that log arguments are evaluated only once per log statement
LOG_INFO(logger, "Test log arguments {}", arg_str());
REQUIRE_EQ(cnt, 1);
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 1);
testing::remove_file(filename);
}

View file

@ -0,0 +1,86 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <thread>
#include <vector>
using namespace quill;
/***/
TEST_CASE("log_flush_with_soft_limit_test")
{
static constexpr char const* filename = "log_flush_with_soft_limit_test.log";
static std::string const logger_name = "logger";
static size_t constexpr soft_limit = 100;
// make sure we at least x 100 the soft limit to make sure we are testing what we want
// to not reduce this number. Increasing is fine
static size_t constexpr number_of_messages = soft_limit * 100;
static constexpr size_t number_of_threads = 4;
// When hitting the transit_events_soft_limit several events are processed in the backend at the
// same time If all of them are processed there is a chance to miss messages that where in the
// queues but never buffered result in example issuing the flush_log() earlier than it should
// Start the backend thread
BackendOptions backend_options;
backend_options.transit_events_soft_limit = soft_limit;
Backend::start(backend_options);
std::vector<std::thread> threads;
for (size_t i = 0; i < number_of_threads; ++i)
{
threads.emplace_back(
[i]() mutable
{
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
cfg.set_do_fsync(true);
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
for (size_t j = 0; j < number_of_messages; ++j)
{
LOG_INFO(logger, "Hello from thread {} this is message {}", i, j);
}
});
}
for (auto& elem : threads)
{
elem.join();
}
Frontend::get_valid_logger()->flush_log();
// Now check we have all messages in the file after the flush statement
size_t const total_messages = number_of_messages * number_of_threads;
// Read file and check
REQUIRE_EQ(testing::file_contents(filename).size(), total_messages);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check again, nothing else was logged
REQUIRE_EQ(testing::file_contents(filename).size(), total_messages);
testing::remove_file(filename);
}

View file

@ -0,0 +1,107 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/**
* A test class example that is using the logger
*/
class LoggingTestClass
{
public:
LoggingTestClass(std::string const& filename, std::string const& logger_name)
{
// create a new logger in the ctor
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
cfg.set_do_fsync(true);
return cfg;
}(),
FileEventNotifier{});
quill::Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
_logger = logger;
}
~LoggingTestClass()
{
_logger->flush_log();
Frontend::remove_logger(_logger);
}
/**
* Use logger in const function
*/
void use_logger_const() const noexcept { LOG_INFO(_logger, "Test message for test class const"); }
/**
* Use logger in normal function
*/
void use_logger() const { LOG_INFO(_logger, "Test message for test class non const"); }
private:
quill::Logger* _logger{nullptr};
};
/***/
TEST_CASE("logger_add_remove_get")
{
// Verifies logging behavior adding, removing and getting loggers
// and logging from const member functions while dynamically creating and
// removing loggers and reusing the same file after removal.
static constexpr size_t iterations = 100;
static constexpr char const* filename = "logger_add_remove_get.log";
// Start the logging backend thread
Backend::start();
for (size_t i = 0; i < iterations; ++i)
{
std::string const logger_a_name = "logger_a" + std::to_string(i);
std::string const logger_b_name = "logger_b" + std::to_string(i);
{
// log for class a
LoggingTestClass logging_test_class_a{filename, logger_a_name};
logging_test_class_a.use_logger_const();
logging_test_class_a.use_logger();
// log again for class b
LoggingTestClass const logging_test_class_b{filename, logger_b_name};
logging_test_class_b.use_logger_const();
}
// Test that get_all_loggers() works and also it should be empty after removing the loggers
REQUIRE(Frontend::get_all_loggers().empty());
REQUIRE(!Frontend::get_logger(logger_a_name));
REQUIRE(!Frontend::get_logger(logger_b_name));
// The only safe way to know that the loggers are really removed is currently this
while (Frontend::get_number_of_loggers())
{
// wait for all the to be removed first by the backend thread first then repeat the test
std::this_thread::sleep_for(std::chrono::milliseconds{1});
}
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 3);
testing::remove_file(filename);
}
Backend::stop();
}

View file

@ -0,0 +1,95 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdint>
#include <string>
#include <thread>
#include <vector>
using namespace quill;
/***/
TEST_CASE("multi_frontend_threads")
{
static constexpr size_t number_of_messages = 1000;
static constexpr size_t number_of_threads = 10;
static constexpr char const* filename = "multi_frontend_threads.log";
static std::string const logger_name_prefix = "logger_";
// Start the logging backend thread
Backend::start();
std::vector<std::thread> threads;
for (size_t i = 0; i < number_of_threads; ++i)
{
threads.emplace_back(
[i]() mutable
{
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(
logger_name_prefix + std::to_string(i), std::move(file_sink),
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) "
"%(message)",
"%Y-%m-%d %H:%M:%S.%Qns", Timezone::GmtTime, ClockSourceType::System);
for (size_t j = 0; j < number_of_messages; ++j)
{
LOG_INFO(logger, "Hello from thread {} this is message {}", i, j);
}
});
}
for (auto& elem : threads)
{
elem.join();
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads);
for (size_t i = 0; i < number_of_threads; ++i)
{
// for each thread
for (size_t j = 0; j < number_of_messages; ++j)
{
std::string expected_string = logger_name_prefix + std::to_string(i) +
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j);
REQUIRE(testing::file_contains(file_contents, expected_string));
}
}
// Check log file is timestamp ordered
REQUIRE(quill::testing::is_timestamp_ordered(file_contents));
testing::remove_file(filename);
}

View file

@ -0,0 +1,93 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/ConsoleSink.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <sstream>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("multiple_sinks_same_logger")
{
static constexpr size_t number_of_messages = 10000;
static constexpr char const* filename = "multiple_sinks_same_logger.log";
// Start the logging backend thread
Backend::start();
quill::testing::CaptureStdout();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
bool const using_colours = false;
std::string const stream = "stdout";
auto console_sink = Frontend::create_or_get_sink<ConsoleSink>("console_sink", using_colours, stream);
std::string const logger_name = "logger";
Logger* logger =
Frontend::create_or_get_logger(logger_name, {std::move(file_sink), std::move(console_sink)});
for (size_t i = 0; i < number_of_messages; ++i)
{
LOG_INFO(logger, "This is message {}", i);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
{
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages);
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string expected_string = logger_name + " This is message " + std::to_string(i);
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
}
}
{
// convert stdout result to vector
std::string results = quill::testing::GetCapturedStdout();
std::stringstream data(results);
std::string line;
std::vector<std::string> file_contents;
while (std::getline(data, line, '\n'))
{
file_contents.push_back(line);
}
REQUIRE_EQ(file_contents.size(), number_of_messages);
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string expected_string = "logger This is message " + std::to_string(i);
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
}
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,56 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/RotatingFileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("rotating_sink_daily_rotation")
{
// This test has 2 loggers that they logged to different rotating file handlers
static char const* base_filename = "rotating_sink_daily_rotation.log";
// Start the logging backend thread
Backend::start();
// Create a rotating file handler
std::shared_ptr<quill::Sink> rotating_file_sink_a =
Frontend::create_or_get_sink<RotatingFileSink>(base_filename,
[]()
{
RotatingFileSinkConfig rfh_cfg;
rfh_cfg.set_rotation_time_daily("00:00");
rfh_cfg.set_open_mode('w');
return rfh_cfg;
}());
// Get the same instance back - we search it again (for testing only)
quill::Logger* logger = Frontend::create_or_get_logger("logger", std::move(rotating_file_sink_a));
// log a few messages so we rotate files
for (uint32_t i = 0; i < 20; ++i)
{
LOG_INFO(logger, "Hello daily file log num {}", i);
}
// flush all log and remove all loggers
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(base_filename);
REQUIRE_EQ(file_contents.size(), 20);
testing::remove_file(base_filename);
}

View file

@ -0,0 +1,102 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/RotatingFileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("rotating_sink_keep_oldest")
{
// This test has 2 loggers that they logged to different rotating file handlers
static char const* base_filename_a = "rotating_sink_keep_oldest_a.log";
static constexpr char const* base_filename_a_1 = "rotating_sink_keep_oldest_a.1.log";
static constexpr char const* base_filename_a_2 = "rotating_sink_keep_oldest_a.2.log";
static char const* base_filename_b = "rotating_sink_keep_oldest_b.log";
static constexpr char const* base_filename_b_1 = "rotating_sink_keep_oldest_b.1.log";
static constexpr size_t max_file_size = 900;
// Start the logging backend thread
Backend::start();
// Create a rotating file handler
std::shared_ptr<quill::Sink> rotating_file_sink_a =
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_a,
[]()
{
RotatingFileSinkConfig rfh_cfg;
rfh_cfg.set_rotation_max_file_size(max_file_size);
rfh_cfg.set_max_backup_files(2);
rfh_cfg.set_overwrite_rolled_files(false);
rfh_cfg.set_open_mode('w');
return rfh_cfg;
}());
// Get the same instance back - we search it again (for testing only)
quill::Logger* logger_a = Frontend::create_or_get_logger("logger_a", std::move(rotating_file_sink_a));
// Another rotating logger to another file with max backup count 1 this time. Here we rotate only once
std::shared_ptr<quill::Sink> rotating_file_sink_b =
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_b,
[]()
{
RotatingFileSinkConfig rfh_cfg;
rfh_cfg.set_rotation_max_file_size(max_file_size);
rfh_cfg.set_max_backup_files(1);
rfh_cfg.set_overwrite_rolled_files(false);
rfh_cfg.set_open_mode('w');
return rfh_cfg;
}());
quill::Logger* logger_b = Frontend::create_or_get_logger("logger_b", std::move(rotating_file_sink_b));
// log a few messages so we rotate files
for (uint32_t i = 0; i < 20; ++i)
{
LOG_INFO(logger_a, "Hello rotating file log num {}", i);
LOG_INFO(logger_b, "Hello rotating file log num {}", i);
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(base_filename_a);
REQUIRE_GE(file_contents.size(), 3);
std::vector<std::string> const file_contents_1 = quill::testing::file_contents(base_filename_a_1);
REQUIRE_GE(file_contents_1.size(), 7);
std::vector<std::string> const file_contents_2 = quill::testing::file_contents(base_filename_a_2);
REQUIRE_GE(file_contents_2.size(), 7);
// File from 2nd logger
std::vector<std::string> const file_contents_3 = quill::testing::file_contents(base_filename_b);
REQUIRE_GE(file_contents_3.size(), 11);
std::vector<std::string> const file_contents_4 = quill::testing::file_contents(base_filename_b_1);
REQUIRE_GE(file_contents_4.size(), 7);
// Remove filenames
testing::remove_file(base_filename_a);
testing::remove_file(base_filename_a_1);
testing::remove_file(base_filename_a_2);
testing::remove_file(base_filename_b);
testing::remove_file(base_filename_b_1);
}

View file

@ -0,0 +1,102 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/RotatingFileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("rotating_sink_overwrite_oldest")
{
// This test has 2 loggers that they logged to different rotating file handlers
static char const* base_filename_a = "rotating_sink_overwrite_oldest_a.log";
static constexpr char const* base_filename_a_1 = "rotating_sink_overwrite_oldest_a.1.log";
static constexpr char const* base_filename_a_2 = "rotating_sink_overwrite_oldest_a.2.log";
static char const* base_filename_b = "rotating_sink_overwrite_oldest_b.log";
static constexpr char const* base_filename_b_1 = "rotating_sink_overwrite_oldest_b.1.log";
static constexpr size_t max_file_size = 900;
// Start the logging backend thread
Backend::start();
// Create a rotating file handler
std::shared_ptr<quill::Sink> rotating_file_sink_a =
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_a,
[]()
{
RotatingFileSinkConfig rfh_cfg;
rfh_cfg.set_rotation_max_file_size(max_file_size);
rfh_cfg.set_max_backup_files(2);
rfh_cfg.set_overwrite_rolled_files(true);
rfh_cfg.set_open_mode('w');
return rfh_cfg;
}());
// Get the same instance back - we search it again (for testing only)
quill::Logger* logger_a = Frontend::create_or_get_logger("logger_a", std::move(rotating_file_sink_a));
// Another rotating logger to another file with max backup count 1 this time. Here we rotate only once
std::shared_ptr<quill::Sink> rotating_file_sink_b =
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_b,
[]()
{
RotatingFileSinkConfig rfh_cfg;
rfh_cfg.set_rotation_max_file_size(max_file_size);
rfh_cfg.set_max_backup_files(1);
rfh_cfg.set_overwrite_rolled_files(true);
rfh_cfg.set_open_mode('w');
return rfh_cfg;
}());
quill::Logger* logger_b = Frontend::create_or_get_logger("logger_b", std::move(rotating_file_sink_b));
// log a few messages so we rotate files
for (uint32_t i = 0; i < 20; ++i)
{
LOG_INFO(logger_a, "Hello rotating file log num {}", i);
LOG_INFO(logger_b, "Hello rotating file log num {}", i);
}
// flush all log and remove all loggers
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(base_filename_a);
REQUIRE_GE(file_contents.size(), 3);
std::vector<std::string> const file_contents_1 = quill::testing::file_contents(base_filename_a_1);
REQUIRE_GE(file_contents_1.size(), 7);
std::vector<std::string> const file_contents_2 = quill::testing::file_contents(base_filename_a_2);
REQUIRE_GE(file_contents_2.size(), 7);
// File from 2nd logger
std::vector<std::string> const file_contents_3 = quill::testing::file_contents(base_filename_b);
REQUIRE_GE(file_contents_3.size(), 4);
std::vector<std::string> const file_contents_4 = quill::testing::file_contents(base_filename_b_1);
REQUIRE_GE(file_contents_4.size(), 7);
// Remove filenames
testing::remove_file(base_filename_a);
testing::remove_file(base_filename_a_1);
testing::remove_file(base_filename_a_2);
testing::remove_file(base_filename_b);
testing::remove_file(base_filename_b_1);
}

View file

@ -0,0 +1,117 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("signal_handler")
{
static constexpr char const* filename = "signal_handler.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_messages = 10;
static constexpr size_t number_of_threads = 10;
static std::string const logger_name_prefix = "logger_";
// Start the logging backend thread, we expect the signal handler to catch the signal,
// flush the log and raise the signal back
Backend::start_with_signal_handler<FrontendOptions>(BackendOptions{},
std::initializer_list<int>{SIGABRT}, 40);
// For testing purposes we want to keep the application running, we do not reraise the signal
detail::SignalHandlerContext::instance().should_reraise_signal.store(false);
quill::Frontend::preallocate();
std::vector<std::thread> threads;
for (size_t i = 0; i < number_of_threads; ++i)
{
threads.emplace_back(
[i]() mutable
{
#if defined(_WIN32)
// NOTE: On windows the signal handler must be installed on each new thread
quill::init_signal_handler<quill::FrontendOptions>();
#endif
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
cfg.set_do_fsync(true);
return cfg;
}(),
FileEventNotifier{});
Logger* logger =
Frontend::create_or_get_logger(logger_name_prefix + std::to_string(i), std::move(file_sink));
for (size_t j = 0; j < number_of_messages; ++j)
{
LOG_INFO(logger, "{} {} {}", i, j,
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "
"incididunt ut labore et dolore magna aliqua.");
}
});
}
for (auto& elem : threads)
{
elem.join();
}
// Now raise a signal
std::raise(SIGABRT);
{
// Except the log and the signal handler in the logs
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
for (size_t i = 0; i < number_of_threads; ++i)
{
// for each thread
for (size_t j = 0; j < number_of_messages; ++j)
{
std::string expected_string = logger_name_prefix + std::to_string(i) + " " +
std::to_string(i) + " " + std::to_string(j) +
" Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "
"incididunt ut labore et dolore magna aliqua.";
REQUIRE(testing::file_contains(file_contents, expected_string));
}
}
#if defined(_WIN32)
REQUIRE(quill::testing::file_contains(file_contents, std::string{"Received signal: 22 (signum: 22)"}));
#elif defined(__apple_build_version__)
REQUIRE(quill::testing::file_contains(file_contents, std::string{"Received signal: Abort trap: 6 (signum: 6)"}));
#else
REQUIRE(quill::testing::file_contains(file_contents, std::string{"Received signal: Aborted (signum: 6)"}));
#endif
}
// Wait until the backend thread stops for test stability
for (Logger* logger : Frontend::get_all_loggers())
{
logger->flush_log();
Frontend::remove_logger(logger);
}
Backend::stop();
REQUIRE_FALSE(Backend::is_running());
testing::remove_file(filename);
}

View file

@ -0,0 +1,62 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("single_frontend_thread")
{
static constexpr size_t number_of_messages = 10000;
static constexpr char const* filename = "single_frontend_thread.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
for (size_t i = 0; i < number_of_messages; ++i)
{
LOG_INFO(logger, "This is message {}", i);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages);
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string expected_string = logger_name + " This is message " + std::to_string(i);
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,132 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/**
* Filter class for our file handler
*/
class FileFilterA : public Filter
{
public:
FileFilterA() : Filter("FileFilterA") {}
QUILL_NODISCARD bool filter(MacroMetadata const* log_metadata, uint64_t log_timestamp, std::string_view thread_id,
std::string_view thread_name, std::string_view logger_name,
LogLevel log_level, std::string_view log_message) noexcept override
{
if (log_metadata->log_level() < LogLevel::Warning)
{
return true;
}
return false;
}
};
/**
* Filter for the stdout handler
*/
class FileFilterB : public Filter
{
public:
FileFilterB() : Filter("FileFilterB") {}
QUILL_NODISCARD bool filter(MacroMetadata const* log_metadata, uint64_t log_timestamp, std::string_view thread_id,
std::string_view thread_name, std::string_view logger_name,
LogLevel log_level, std::string_view log_message) noexcept override
{
if (log_metadata->log_level() >= LogLevel::Warning)
{
return true;
}
return false;
}
};
/***/
TEST_CASE("sink_filter")
{
static constexpr char const* filename_a = "sink_filter_a.log";
static constexpr char const* filename_b = "sink_filter_b.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
// Set writing logging to a file
auto file_sink_a = Frontend::create_or_get_sink<FileSink>(
filename_a,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
// log to filename_a anything below warning
std::unique_ptr<Filter> filter_a = std::make_unique<FileFilterA>();
// Also test get_filter_name()
REQUIRE_EQ(filter_a->get_filter_name(), std::string_view{"FileFilterA"});
// Add the filter
file_sink_a->add_filter(std::move(filter_a));
// Try to add the same again (same name)
std::unique_ptr<Filter> filter_a_2 = std::make_unique<FileFilterA>();
REQUIRE_EQ(filter_a_2->get_filter_name(), std::string_view{"FileFilterA"});
REQUIRE_THROWS_AS(file_sink_a->add_filter(std::move(filter_a_2)), QuillError);
auto file_sink_b = Frontend::create_or_get_sink<FileSink>(
filename_b,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
// log to filename_b warning, error, critical
file_sink_b->add_filter(std::make_unique<FileFilterB>());
Logger* logger =
Frontend::create_or_get_logger(logger_name, {std::move(file_sink_a), std::move(file_sink_b)});
LOG_INFO(logger, "Lorem ipsum dolor sit amet, consectetur adipiscing elit");
LOG_ERROR(logger, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante");
// Let all log get flushed to the file
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents_a = quill::testing::file_contents(filename_a);
REQUIRE_EQ(file_contents_a.size(), 1);
REQUIRE(quill::testing::file_contains(
file_contents_a,
std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur adipiscing elit"}));
std::vector<std::string> const file_contents_b = quill::testing::file_contents(filename_b);
REQUIRE_EQ(file_contents_b.size(), 1);
REQUIRE(quill::testing::file_contains(
file_contents_b,
std::string{"LOG_ERROR " + logger_name +
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante"}));
testing::remove_file(filename_a);
testing::remove_file(filename_b);
}

View file

@ -0,0 +1,89 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/***/
TEST_CASE("sink_log_level_filter")
{
static constexpr char const* filename_a = "sink_log_level_filter_a.log";
static constexpr char const* filename_b = "sink_log_level_filter_b.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
// Set writing logging to a file
auto file_sink_a = Frontend::create_or_get_sink<FileSink>(
filename_a,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
// Set filters to our handlers
REQUIRE_EQ(file_sink_a->get_log_level_filter(), LogLevel::TraceL3);
file_sink_a->set_log_level_filter(LogLevel::Info);
REQUIRE_EQ(file_sink_a->get_log_level_filter(), LogLevel::Info);
auto file_sink_b = Frontend::create_or_get_sink<FileSink>(
filename_b,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
// log to filename_b warning, error, critical
REQUIRE_EQ(file_sink_b->get_log_level_filter(), LogLevel::TraceL3);
file_sink_b->set_log_level_filter(LogLevel::Error);
REQUIRE_EQ(file_sink_b->get_log_level_filter(), LogLevel::Error);
Logger* logger =
Frontend::create_or_get_logger(logger_name, {std::move(file_sink_a), std::move(file_sink_b)});
LOG_INFO(logger, "Lorem ipsum dolor sit amet, consectetur adipiscing elit");
LOG_ERROR(logger, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante");
// Let all log get flushed to the file
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents_a = quill::testing::file_contents(filename_a);
REQUIRE_EQ(file_contents_a.size(), 2);
REQUIRE(quill::testing::file_contains(
file_contents_a,
std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur adipiscing elit"}));
REQUIRE(quill::testing::file_contains(
file_contents_a,
std::string{"LOG_ERROR " + logger_name +
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante"}));
std::vector<std::string> const file_contents_b = quill::testing::file_contents(filename_b);
REQUIRE_EQ(file_contents_b.size(), 1);
REQUIRE(quill::testing::file_contains(
file_contents_b,
std::string{"LOG_ERROR " + logger_name +
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante"}));
testing::remove_file(filename_a);
testing::remove_file(filename_b);
}

View file

@ -0,0 +1,209 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Array.h"
#include <array>
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_array_logging")
{
static constexpr char const* filename = "std_array_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::array<bool, 2> b = {true, false};
LOG_INFO(logger, "v {}", b);
std::array<char, 2> c = {'a', 'c'};
LOG_INFO(logger, "c {}", c);
std::array<short, 2> si = {-12, 10};
LOG_INFO(logger, "si {}", si);
std::array<int, 2> i = {-123, 1};
LOG_INFO(logger, "i {}", i);
std::array<long, 2> li = {9876, 1232};
LOG_INFO(logger, "li {}", li);
std::array<long long, 2> lli = {321, 231};
LOG_INFO(logger, "lli {}", lli);
std::array<unsigned short, 2> usi = {15, 2};
LOG_INFO(logger, "usi {}", usi);
std::array<unsigned int, 2> ui = {123, 2};
LOG_INFO(logger, "ui {}", ui);
std::array<unsigned long, 2> uli = {3213, 2876};
LOG_INFO(logger, "uli {}", uli);
std::array<unsigned long long, 2> ulli = {321, 1321};
LOG_INFO(logger, "ulli {}", ulli);
std::array<float, 2> f = {111.1f, 323.31f};
LOG_INFO(logger, "f {}", f);
std::array<double, 2> d = {12.1, 3213213.123};
LOG_INFO(logger, "d {}", d);
std::array<int, 2> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::array<int, 2>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::array<std::string, 2> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::array<std::string_view, 2> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::array<char const*, 4> scva = {"c style", "string test", "test", "log"};
LOG_INFO(logger, "scva {}", scva);
std::array<std::array<int, 2>, 3> aai = {{{321, 123}, {444, 333}, {111, 222}}};
LOG_INFO(logger, "aai {}", aai);
std::array<std::array<char const*, 2>, 3> aacs = {
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
LOG_INFO(logger, "aacs {}", aacs);
std::array<std::array<std::array<char const*, 2>, 2>, 3> aaacs = {
{{{{"one", "two"}, {"three", "four"}}},
{{{"five", "six"}, {"seven", "eight"}}},
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
LOG_INFO(logger, "aaacs {}", aaacs);
std::array<std::array<std::array<std::string, 2>, 2>, 3> aaabcs = {
{{{{"std_one", "two"}, {"three", "four"}}},
{{{"five", "six"}, {"seven", "eight"}}},
{{{"std_nine", "ten"}, {"eleven", "twelve"}}}}};
LOG_INFO(logger, "aaabcs {}", aaabcs);
std::array<std::array<std::array<std::string_view, 2>, 2>, 3> aaaccs = {
{{{{"std_one", "two"}, {"three_std", "four"}}},
{{{"five", "six"}, {"seven_std", "eight"}}},
{{{"std_nine", "ten"}, {"eleven", "twelve"}}}}};
LOG_INFO(logger, "aaaccs {}", aaaccs);
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aaacs {} aai {}", scva, sa, ulli, scva, sa, aaacs, aai);
std::array<int, 4> empt{};
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " v [true, false]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aai [[321, 123], [444, 333], [111, 222]]"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" aacs [[\"one\", \"two\"], [\"three\", \"four\"], [\"five\", \"six\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaabcs [[[\"std_one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaaccs [[[\"std_one\", \"two\"], [\"three_std\", \"four\"]], [[\"five\", \"six\"], [\"seven_std\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]] aai [[321, 123], [444, 333], [111, 222]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt [0, 0, 0, 0]"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,250 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Deque.h"
#include <cstdio>
#include <deque>
#include <string>
#include <string_view>
using namespace quill;
/***/
TEST_CASE("std_deque_logging")
{
static constexpr char const* filename = "std_deque_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::deque<char> c = {'a', 'c'};
LOG_INFO(logger, "c {}", c);
std::deque<short> si = {-12, 10};
LOG_INFO(logger, "si {}", si);
std::deque<int> i = {-123, 1};
LOG_INFO(logger, "i {}", i);
std::deque<long> li = {9876, 1232};
LOG_INFO(logger, "li {}", li);
std::deque<long long> lli = {321, 231};
LOG_INFO(logger, "lli {}", lli);
std::deque<unsigned short> usi = {15, 2};
LOG_INFO(logger, "usi {}", usi);
std::deque<unsigned int> ui = {123, 2};
LOG_INFO(logger, "ui {}", ui);
std::deque<unsigned long> uli = {3213, 2876};
LOG_INFO(logger, "uli {}", uli);
std::deque<unsigned long long> ulli = {321, 1321};
LOG_INFO(logger, "ulli {}", ulli);
std::deque<float> f = {111.1f, 323.31f};
LOG_INFO(logger, "f {}", f);
std::deque<double> d = {12.1, 3213213.123};
LOG_INFO(logger, "d {}", d);
std::deque<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::deque<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::deque<std::string> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::deque<std::string_view> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::deque<char const*> scva = {"c style", "string test", "test", "log"};
LOG_INFO(logger, "scva {}", scva);
std::deque<std::deque<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
LOG_INFO(logger, "aai {}", aai);
std::deque<std::deque<char const*>> aacs = {
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
LOG_INFO(logger, "aacs {}", aacs);
std::deque<std::deque<std::deque<char const*>>> aaacs = {
{{{{"one", "two"}, {"three", "four"}}},
{{{"five", "six"}, {"seven", "eight"}}},
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
LOG_INFO(logger, "aaacs {}", aaacs);
{
std::deque<std::deque<std::deque<std::string>>> aaabcs;
// First outer deque
std::deque<std::deque<std::string>> first_outer = {{"std_one", "two"}, {"three", "four"}};
// Second outer deque
std::deque<std::deque<std::string>> second_outer = {{"five", "six"}, {"seven", "eight"}};
// Third outer deque
std::deque<std::deque<std::string>> third_outer = {{"std_nine", "ten"}, {"eleven", "twelve"}};
aaabcs.push_back(first_outer);
aaabcs.push_back(second_outer);
aaabcs.push_back(third_outer);
LOG_INFO(logger, "aaabcs {}", aaabcs);
}
{
std::deque<std::deque<std::deque<std::string>>> aaaccs;
// First outer deque
std::deque<std::deque<std::string>> first_outer = {{"std_one", "two"}, {"three_std", "four"}};
// Second outer deque
std::deque<std::deque<std::string>> second_outer = {{"five", "six"}, {"seven_std", "eight"}};
// Third outer deque
std::deque<std::deque<std::string>> third_outer = {{"std_nine", "ten"}, {"eleven", "twelve"}};
aaaccs.push_back(first_outer);
aaaccs.push_back(second_outer);
aaaccs.push_back(third_outer);
LOG_INFO(logger, "aaaccs {}", aaaccs);
}
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aaacs {} aai {}", scva, sa, ulli, scva, sa, aaacs, aai);
std::deque<int> loopv;
for (int iter = 0; iter < 100; ++iter)
{
loopv.push_back(iter);
}
LOG_INFO(logger, "loopv {}", loopv);
std::deque<std::string> loopsv;
for (int iter = 0; iter < 100; ++iter)
{
loopsv.push_back(std::to_string(iter));
}
LOG_INFO(logger, "loopsv {}", loopsv);
std::deque<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aai [[321, 123], [444, 333], [111, 222]]"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" aacs [[\"one\", \"two\"], [\"three\", \"four\"], [\"five\", \"six\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaabcs [[[\"std_one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaaccs [[[\"std_one\", \"two\"], [\"three_std\", \"four\"]], [[\"five\", \"six\"], [\"seven_std\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]] aai [[321, 123], [444, 333], [111, 222]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,67 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/core/Filesystem.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/FilesystemPath.h"
#include <array>
#include <cstdio>
#include <filesystem>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_filesystem_path_logging")
{
static constexpr char const* filename = "std_filesystem_path_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
fs::path sp{"/usr/local/bin"};
LOG_INFO(logger, "sp {} {} {}", sp, sp, sp);
LOG_INFO(logger, "sp_2 {} {} {}", sp, sp, sp);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sp /usr/local/bin /usr/local/bin /usr/local/bin"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sp_2 /usr/local/bin /usr/local/bin /usr/local/bin"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,161 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/ForwardList.h"
#include <cstdio>
#include <forward_list>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_forward_list_logging")
{
static constexpr char const* filename = "std_forward_list_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::forward_list<char> c = {'a', 'c'};
LOG_INFO(logger, "c {}", c);
std::forward_list<short> si = {-12, 10};
LOG_INFO(logger, "si {}", si);
std::forward_list<int> i = {-123, 1};
LOG_INFO(logger, "i {}", i);
std::forward_list<long> li = {9876, 1232};
LOG_INFO(logger, "li {}", li);
std::forward_list<long long> lli = {321, 231};
LOG_INFO(logger, "lli {}", lli);
std::forward_list<unsigned short> usi = {15, 2};
LOG_INFO(logger, "usi {}", usi);
std::forward_list<unsigned int> ui = {123, 2};
LOG_INFO(logger, "ui {}", ui);
std::forward_list<unsigned long> uli = {3213, 2876};
LOG_INFO(logger, "uli {}", uli);
std::forward_list<unsigned long long> ulli = {321, 1321};
LOG_INFO(logger, "ulli {}", ulli);
std::forward_list<float> f = {111.1f, 323.31f};
LOG_INFO(logger, "f {}", f);
std::forward_list<double> d = {12.1, 3213213.123};
LOG_INFO(logger, "d {}", d);
std::forward_list<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::forward_list<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::forward_list<std::string> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::forward_list<std::string_view> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::forward_list<char const*> scva = {"c style", "string test", "test", "log"};
LOG_INFO(logger, "scva {}", scva);
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
std::forward_list<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,161 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/List.h"
#include <cstdio>
#include <list>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_list_logging")
{
static constexpr char const* filename = "std_list_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::list<char> c = {'a', 'c'};
LOG_INFO(logger, "c {}", c);
std::list<short> si = {-12, 10};
LOG_INFO(logger, "si {}", si);
std::list<int> i = {-123, 1};
LOG_INFO(logger, "i {}", i);
std::list<long> li = {9876, 1232};
LOG_INFO(logger, "li {}", li);
std::list<long long> lli = {321, 231};
LOG_INFO(logger, "lli {}", lli);
std::list<unsigned short> usi = {15, 2};
LOG_INFO(logger, "usi {}", usi);
std::list<unsigned int> ui = {123, 2};
LOG_INFO(logger, "ui {}", ui);
std::list<unsigned long> uli = {3213, 2876};
LOG_INFO(logger, "uli {}", uli);
std::list<unsigned long long> ulli = {321, 1321};
LOG_INFO(logger, "ulli {}", ulli);
std::list<float> f = {111.1f, 323.31f};
LOG_INFO(logger, "f {}", f);
std::list<double> d = {12.1, 3213213.123};
LOG_INFO(logger, "d {}", d);
std::list<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::list<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::list<std::string> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::list<std::string_view> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::list<char const*> scva = {"c style", "string test", "test", "log"};
LOG_INFO(logger, "scva {}", scva);
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
std::list<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,101 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Map.h"
#include <cstdio>
#include <cstring>
#include <map>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
struct CStringComparator
{
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
};
/***/
TEST_CASE("std_map_logging")
{
static constexpr char const* filename = "std_map_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::map<int, double> idm = {{111, 3213.21}, {222, 321.19}, {333, 5555.99}};
LOG_INFO(logger, "idm {}", idm);
std::map<int, std::string> loopv;
for (int iter = 0; iter < 25; ++iter)
{
loopv.emplace(iter, std::to_string(iter));
}
LOG_INFO(logger, "loopv {}", loopv);
std::map<std::string, std::string> loopsv;
for (int iter = 0; iter < 25; ++iter)
{
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
}
LOG_INFO(logger, "loopsv {}", loopv);
std::map<char const*, char const*, CStringComparator> ccm = {
{"4", "400"}, {"3", "300"}, {"1", "100"}, {"2", "200"}};
LOG_INFO(logger, "ccm {}", ccm);
std::map<char const*, int, CStringComparator> cim = {{"4", 4}, {"3", 3}, {"1", 1}, {"2", 2}};
LOG_INFO(logger, "cim {}", cim);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21, 222: 321.19, 333: 5555.99}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\""}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" ccm {\"1\": \"100\", \"2\": \"200\", \"3\": \"300\", \"4\": \"400\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"1\": 1, \"2\": 2, \"3\": 3, \"4\": 4}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,101 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Map.h"
#include <cstdio>
#include <cstring>
#include <map>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
struct CStringComparator
{
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
};
/***/
TEST_CASE("std_multimap_logging")
{
static constexpr char const* filename = "std_multimap_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::multimap<int, double> idm = {{111, 3213.21}, {222, 321.19}, {333, 5555.99}};
LOG_INFO(logger, "idm {}", idm);
std::multimap<int, std::string> loopv;
for (int iter = 0; iter < 25; ++iter)
{
loopv.emplace(iter, std::to_string(iter));
}
LOG_INFO(logger, "loopv {}", loopv);
std::multimap<std::string, std::string> loopsv;
for (int iter = 0; iter < 25; ++iter)
{
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
}
LOG_INFO(logger, "loopsv {}", loopv);
std::multimap<char const*, char const*, CStringComparator> ccm = {
{"4", "400"}, {"3", "300"}, {"1", "100"}, {"2", "200"}};
LOG_INFO(logger, "ccm {}", ccm);
std::multimap<char const*, int, CStringComparator> cim = {{"4", 4}, {"3", 3}, {"1", 1}, {"2", 2}};
LOG_INFO(logger, "cim {}", cim);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21, 222: 321.19, 333: 5555.99}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\""}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" ccm {\"1\": \"100\", \"2\": \"200\", \"3\": \"300\", \"4\": \"400\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"1\": 1, \"2\": 2, \"3\": 3, \"4\": 4}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,218 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Set.h"
#include <cstdio>
#include <cstring>
#include <set>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
struct CStringComparator
{
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
};
/***/
TEST_CASE("std_multiset_logging")
{
static constexpr char const* filename = "std_multiset_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::multiset<char> c = {'a', 'c'};
LOG_INFO(logger, "c {}", c);
std::multiset<short> si = {-12, 10};
LOG_INFO(logger, "si {}", si);
std::multiset<int> i = {-123, 1};
LOG_INFO(logger, "i {}", i);
std::multiset<long> li = {9876, 1232};
LOG_INFO(logger, "li {}", li);
std::multiset<long long> lli = {321, 231};
LOG_INFO(logger, "lli {}", lli);
std::multiset<unsigned short> usi = {15, 2};
LOG_INFO(logger, "usi {}", usi);
std::multiset<unsigned int> ui = {123, 2};
LOG_INFO(logger, "ui {}", ui);
std::multiset<unsigned long> uli = {3213, 2876};
LOG_INFO(logger, "uli {}", uli);
std::multiset<unsigned long long> ulli = {321, 1321};
LOG_INFO(logger, "ulli {}", ulli);
std::multiset<float> f = {111.1f, 323.31f};
LOG_INFO(logger, "f {}", f);
std::multiset<double> d = {12.1, 3213213.123};
LOG_INFO(logger, "d {}", d);
std::multiset<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::multiset<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::multiset<std::string> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::multiset<std::string_view> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::multiset<char const*, CStringComparator> scva = {"c_style", "aa", "string_test", "test",
"log"};
LOG_INFO(logger, "scva {}", scva);
std::multiset<std::multiset<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
LOG_INFO(logger, "aai {}", aai);
{
std::multiset<std::multiset<char const*, CStringComparator>> aacs = {
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
LOG_INFO(logger, "aacs {}", aacs);
}
{
std::multiset<std::multiset<std::multiset<char const*, CStringComparator>>> aaacs = {
{{{{"one", "two"}, {"three", "four"}}},
{{{"five", "six"}, {"seven", "eight"}}},
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
LOG_INFO(logger, "aaacs {}", aaacs);
}
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aai {}", scva, sa, ulli, scva, sa, aai);
std::multiset<int> loopv;
for (int iter = 0; iter < 100; ++iter)
{
loopv.insert(iter);
}
LOG_INFO(logger, "loopv {}", loopv);
std::multiset<std::string> loopsv;
for (int iter = 0; iter < 100; ++iter)
{
loopsv.insert(std::to_string(iter));
}
LOG_INFO(logger, "loopsv {}", loopsv);
std::multiset<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a', 'c'}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12, 10}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123, 1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li {1232, 9876}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli {231, 321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi {2, 15}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui {2, 123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli {2876, 3213}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321, 1321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1, 323.31}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1, 3213213.123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123, 1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123, 1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"string\", \"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\", \"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aai {{111, 222}, {123, 321}, {333, 444}}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aacs {{"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs {{{"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} ulli {321, 1321} scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} aai {{111, 222}, {123, 321}, {333, 444}}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {\"0\", \"1\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"2\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"3\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"4\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"5\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"6\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"7\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"8\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"9\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,109 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Optional.h"
#include <array>
#include <cstdio>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_optional_logging")
{
static constexpr char const* filename = "std_optional_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::optional<int> ei{std::nullopt};
LOG_INFO(logger, "ei [{}]", ei);
std::optional<double> ed{std::nullopt};
LOG_INFO(logger, "ed [{}]", ed);
std::optional<char const*> ccp{"testing"};
LOG_INFO(logger, "ccp [{}]", ccp);
std::optional<std::string> sp{"sp_testing"};
LOG_INFO(logger, "sp [{}]", sp);
std::optional<std::string> esp{std::nullopt};
LOG_INFO(logger, "esp [{}]", esp);
std::optional<std::string_view> svp{"svp_testing"};
LOG_INFO(logger, "svp [{}]", svp);
std::optional<int> i{123321};
LOG_INFO(logger, "i [{}]", i);
std::optional<double> d{333.221};
LOG_INFO(logger, "d [{}]", d);
LOG_INFO(logger, "zzzz [{}] [{}] [{}] [{}] [{}]", d, "test", *svp, *sp, ccp);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ei [none]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ed [none]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ccp [optional(\"testing\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sp [optional(\"sp_testing\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " esp [none]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " svp [optional(\"svp_testing\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i [optional(123321)]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d [optional(333.221)]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " zzzz [optional(333.221)] [test] [svp_testing] [sp_testing] [optional(\"testing\")]"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,92 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Pair.h"
#include <array>
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_pair_logging")
{
static constexpr char const* filename = "std_pair_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::pair<bool, int> b = {true, 312};
LOG_INFO(logger, "v {}", b);
std::pair<std::string, std::string> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::pair<std::string_view, std::string> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::pair<char const*, std::string> scva = {"c style", "string test"};
LOG_INFO(logger, "scva {}", scva);
std::pair<std::pair<std::string, std::string_view>, std::pair<const char*, uint32_t>> cp = {
{"pair", "testing"}, {"first", 2}};
LOG_INFO(logger, "cp {}", cp);
std::pair<int, double> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " v (true, 312)"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa (\"test\", \"string\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva (\"test\", \"string_view\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva (\"c style\", \"string test\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cp ((\"pair\", \"testing\"), (\"first\", 2))"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt (0, 0)"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,217 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Set.h"
#include <cstdio>
#include <cstring>
#include <set>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
struct CStringComparator
{
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
};
/***/
TEST_CASE("std_set_logging")
{
static constexpr char const* filename = "std_set_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::set<char> c = {'a', 'c'};
LOG_INFO(logger, "c {}", c);
std::set<short> si = {-12, 10};
LOG_INFO(logger, "si {}", si);
std::set<int> i = {-123, 1};
LOG_INFO(logger, "i {}", i);
std::set<long> li = {9876, 1232};
LOG_INFO(logger, "li {}", li);
std::set<long long> lli = {321, 231};
LOG_INFO(logger, "lli {}", lli);
std::set<unsigned short> usi = {15, 2};
LOG_INFO(logger, "usi {}", usi);
std::set<unsigned int> ui = {123, 2};
LOG_INFO(logger, "ui {}", ui);
std::set<unsigned long> uli = {3213, 2876};
LOG_INFO(logger, "uli {}", uli);
std::set<unsigned long long> ulli = {321, 1321};
LOG_INFO(logger, "ulli {}", ulli);
std::set<float> f = {111.1f, 323.31f};
LOG_INFO(logger, "f {}", f);
std::set<double> d = {12.1, 3213213.123};
LOG_INFO(logger, "d {}", d);
std::set<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::set<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::set<std::string> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::set<std::string_view> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::set<char const*, CStringComparator> scva = {"c_style", "aa", "string_test", "test", "log"};
LOG_INFO(logger, "scva {}", scva);
std::set<std::set<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
LOG_INFO(logger, "aai {}", aai);
{
std::set<std::set<char const*, CStringComparator>> aacs = {
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
LOG_INFO(logger, "aacs {}", aacs);
}
{
std::set<std::set<std::set<char const*, CStringComparator>>> aaacs = {
{{{{"one", "two"}, {"three", "four"}}},
{{{"five", "six"}, {"seven", "eight"}}},
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
LOG_INFO(logger, "aaacs {}", aaacs);
}
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aai {}", scva, sa, ulli, scva, sa, aai);
std::set<int> loopv;
for (int iter = 0; iter < 100; ++iter)
{
loopv.insert(iter);
}
LOG_INFO(logger, "loopv {}", loopv);
std::set<std::string> loopsv;
for (int iter = 0; iter < 100; ++iter)
{
loopsv.insert(std::to_string(iter));
}
LOG_INFO(logger, "loopsv {}", loopsv);
std::set<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a', 'c'}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12, 10}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123, 1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li {1232, 9876}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli {231, 321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi {2, 15}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui {2, 123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli {2876, 3213}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321, 1321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1, 323.31}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1, 3213213.123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123, 1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123, 1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"string\", \"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\", \"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aai {{111, 222}, {123, 321}, {333, 444}}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aacs {{"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs {{{"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} ulli {321, 1321} scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} aai {{111, 222}, {123, 321}, {333, 444}}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {\"0\", \"1\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"2\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"3\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"4\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"5\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"6\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"7\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"8\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"9\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,80 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Tuple.h"
#include <array>
#include <cstdio>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_tuple_logging")
{
static constexpr char const* filename = "std_tuple_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::tuple<std::string> st{"123456789"};
LOG_INFO(logger, "st {}", st);
std::tuple<std::string, int> et;
LOG_INFO(logger, "et {}", et);
std::tuple<std::string, std::string_view, int, double, char const*, std::string, int> ct{
"string", "string_view", 213, 33.12, "c_style", "another_string", 123};
LOG_INFO(logger, "ct {}", ct);
LOG_INFO(logger, "ct {} et {} st {}", ct, et, st);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " st (\"123456789\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " et (\"\", 0)"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ct (\"string\", \"string_view\", 213, 33.12, \"c_style\", \"another_string\", 123)"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ct (\"string\", \"string_view\", 213, 33.12, \"c_style\", \"another_string\", 123) et (\"\", 0) st (\"123456789\")"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,93 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/UnorderedMap.h"
#include <cstdio>
#include <cstring>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_unordered_map_logging")
{
static constexpr char const* filename = "std_unordered_map_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::unordered_map<int, double> idm = {{111, 3213.21}};
LOG_INFO(logger, "idm {}", idm);
std::unordered_map<int, std::string> loopv;
for (int iter = 0; iter < 25; ++iter)
{
loopv.emplace(iter, std::to_string(iter));
}
LOG_INFO(logger, "loopv {}", loopv);
std::unordered_map<std::string, std::string> loopsv;
for (int iter = 0; iter < 25; ++iter)
{
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
}
LOG_INFO(logger, "loopsv {}", loopv);
std::unordered_map<char const*, char const*> ccm = {{"4", "400"}};
LOG_INFO(logger, "ccm {}", ccm);
std::unordered_map<char const*, int> cim = {{"4", 4}};
LOG_INFO(logger, "cim {}", cim);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ccm {\"4\": \"400\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"4\": 4}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,93 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/UnorderedMap.h"
#include <cstdio>
#include <cstring>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_unordered_multimap_logging")
{
static constexpr char const* filename = "std_unordered_multimap_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::unordered_multimap<int, double> idm = {{111, 3213.21}};
LOG_INFO(logger, "idm {}", idm);
std::unordered_multimap<int, std::string> loopv;
for (int iter = 0; iter < 25; ++iter)
{
loopv.emplace(iter, std::to_string(iter));
}
LOG_INFO(logger, "loopv {}", loopv);
std::unordered_multimap<std::string, std::string> loopsv;
for (int iter = 0; iter < 25; ++iter)
{
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
}
LOG_INFO(logger, "loopsv {}", loopv);
std::unordered_multimap<char const*, char const*> ccm = {{"4", "400"}};
LOG_INFO(logger, "ccm {}", ccm);
std::unordered_multimap<char const*, int> cim = {{"4", 4}};
LOG_INFO(logger, "cim {}", cim);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ccm {\"4\": \"400\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"4\": 4}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,184 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/UnorderedSet.h"
#include <cstdio>
#include <cstring>
#include <string>
#include <string_view>
#include <unordered_set>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_unordered_multi_set_logging")
{
static constexpr char const* filename = "std_unordered_multi_set_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::unordered_multiset<char> c = {'a'};
LOG_INFO(logger, "c {}", c);
std::unordered_multiset<short> si = {-12};
LOG_INFO(logger, "si {}", si);
std::unordered_multiset<int> i = {-123};
LOG_INFO(logger, "i {}", i);
std::unordered_multiset<long> li = {9876};
LOG_INFO(logger, "li {}", li);
std::unordered_multiset<long long> lli = {321};
LOG_INFO(logger, "lli {}", lli);
std::unordered_multiset<unsigned short> usi = {15};
LOG_INFO(logger, "usi {}", usi);
std::unordered_multiset<unsigned int> ui = {123};
LOG_INFO(logger, "ui {}", ui);
std::unordered_multiset<unsigned long> uli = {3213};
LOG_INFO(logger, "uli {}", uli);
std::unordered_multiset<unsigned long long> ulli = {321};
LOG_INFO(logger, "ulli {}", ulli);
std::unordered_multiset<float> f = {111.1f};
LOG_INFO(logger, "f {}", f);
std::unordered_multiset<double> d = {12.1};
LOG_INFO(logger, "d {}", d);
std::unordered_multiset<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::unordered_multiset<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::unordered_multiset<std::string> sa = {"test"};
LOG_INFO(logger, "sa {}", sa);
std::unordered_multiset<std::string_view> sva = {"string_view"};
LOG_INFO(logger, "sva {}", sva);
std::unordered_multiset<char const*> scva = {"c_style"};
LOG_INFO(logger, "scva {}", scva);
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
std::unordered_multiset<int> loopv;
for (int iter = 0; iter < 100; ++iter)
{
loopv.insert(iter);
}
LOG_INFO(logger, "loopv {}", loopv);
std::unordered_multiset<std::string> loopsv;
for (int iter = 0; iter < 100; ++iter)
{
loopsv.insert(std::to_string(iter));
}
LOG_INFO(logger, "loopsv {}", loopsv);
std::unordered_multiset<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a'}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li {9876}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli {321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi {15}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui {123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli {3213}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"} sa {\"test\"} ulli {321} scva {\"c_style\"} sa {\"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,184 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/UnorderedSet.h"
#include <cstdio>
#include <cstring>
#include <string>
#include <string_view>
#include <unordered_set>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_unordered_set_logging")
{
static constexpr char const* filename = "std_unordered_set_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::unordered_set<char> c = {'a'};
LOG_INFO(logger, "c {}", c);
std::unordered_set<short> si = {-12};
LOG_INFO(logger, "si {}", si);
std::unordered_set<int> i = {-123};
LOG_INFO(logger, "i {}", i);
std::unordered_set<long> li = {9876};
LOG_INFO(logger, "li {}", li);
std::unordered_set<long long> lli = {321};
LOG_INFO(logger, "lli {}", lli);
std::unordered_set<unsigned short> usi = {15};
LOG_INFO(logger, "usi {}", usi);
std::unordered_set<unsigned int> ui = {123};
LOG_INFO(logger, "ui {}", ui);
std::unordered_set<unsigned long> uli = {3213};
LOG_INFO(logger, "uli {}", uli);
std::unordered_set<unsigned long long> ulli = {321};
LOG_INFO(logger, "ulli {}", ulli);
std::unordered_set<float> f = {111.1f};
LOG_INFO(logger, "f {}", f);
std::unordered_set<double> d = {12.1};
LOG_INFO(logger, "d {}", d);
std::unordered_set<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::unordered_set<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::unordered_set<std::string> sa = {"test"};
LOG_INFO(logger, "sa {}", sa);
std::unordered_set<std::string_view> sva = {"string_view"};
LOG_INFO(logger, "sva {}", sva);
std::unordered_set<char const*> scva = {"c_style"};
LOG_INFO(logger, "scva {}", scva);
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
std::unordered_set<int> loopv;
for (int iter = 0; iter < 100; ++iter)
{
loopv.insert(iter);
}
LOG_INFO(logger, "loopv {}", loopv);
std::unordered_set<std::string> loopsv;
for (int iter = 0; iter < 100; ++iter)
{
loopsv.insert(std::to_string(iter));
}
LOG_INFO(logger, "loopsv {}", loopsv);
std::unordered_set<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a'}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li {9876}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli {321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi {15}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui {123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli {3213}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"} sa {\"test\"} ulli {321} scva {\"c_style\"} sa {\"test\"}"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,255 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Vector.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("std_vector_logging")
{
static constexpr char const* filename = "std_vector_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::vector<char> c = {'a', 'c'};
LOG_INFO(logger, "c {}", c);
std::vector<short> si = {-12, 10};
LOG_INFO(logger, "si {}", si);
std::vector<int> i = {-123, 1};
LOG_INFO(logger, "i {}", i);
std::vector<long> li = {9876, 1232};
LOG_INFO(logger, "li {}", li);
std::vector<long long> lli = {321, 231};
LOG_INFO(logger, "lli {}", lli);
std::vector<unsigned short> usi = {15, 2};
LOG_INFO(logger, "usi {}", usi);
std::vector<unsigned int> ui = {123, 2};
LOG_INFO(logger, "ui {}", ui);
std::vector<unsigned long> uli = {3213, 2876};
LOG_INFO(logger, "uli {}", uli);
std::vector<unsigned long long> ulli = {321, 1321};
LOG_INFO(logger, "ulli {}", ulli);
std::vector<float> f = {111.1f, 323.31f};
LOG_INFO(logger, "f {}", f);
std::vector<double> d = {12.1, 3213213.123};
LOG_INFO(logger, "d {}", d);
std::vector<int> const& cri = i;
LOG_INFO(logger, "cri {}", cri);
std::vector<int>& ci = i;
LOG_INFO(logger, "ci {}", ci);
std::vector<std::string> sa = {"test", "string"};
LOG_INFO(logger, "sa {}", sa);
std::vector<std::string_view> sva = {"test", "string_view"};
LOG_INFO(logger, "sva {}", sva);
std::vector<char const*> scva = {"c style", "string test", "test", "log"};
LOG_INFO(logger, "scva {}", scva);
std::vector<std::vector<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
LOG_INFO(logger, "aai {}", aai);
std::vector<std::vector<char const*>> aacs = {
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
LOG_INFO(logger, "aacs {}", aacs);
std::vector<std::vector<std::vector<char const*>>> aaacs = {
{{{{"one", "two"}, {"three", "four"}}},
{{{"five", "six"}, {"seven", "eight"}}},
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
LOG_INFO(logger, "aaacs {}", aaacs);
{
std::vector<std::vector<std::vector<std::string>>> aaabcs;
// First outer vector
std::vector<std::vector<std::string>> first_outer = {{"std_one", "two"}, {"three", "four"}};
// Second outer vector
std::vector<std::vector<std::string>> second_outer = {{"five", "six"}, {"seven", "eight"}};
// Third outer vector
std::vector<std::vector<std::string>> third_outer = {{"std_nine", "ten"},
{"eleven", "twelve"}};
aaabcs.push_back(first_outer);
aaabcs.push_back(second_outer);
aaabcs.push_back(third_outer);
LOG_INFO(logger, "aaabcs {}", aaabcs);
}
{
std::vector<std::vector<std::vector<std::string>>> aaaccs;
// First outer vector
std::vector<std::vector<std::string>> first_outer = {{"std_one", "two"},
{"three_std", "four"}};
// Second outer vector
std::vector<std::vector<std::string>> second_outer = {{"five", "six"}, {"seven_std", "eight"}};
// Third outer vector
std::vector<std::vector<std::string>> third_outer = {{"std_nine", "ten"},
{"eleven", "twelve"}};
aaaccs.push_back(first_outer);
aaaccs.push_back(second_outer);
aaaccs.push_back(third_outer);
LOG_INFO(logger, "aaaccs {}", aaaccs);
}
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aaacs {} aai {}", scva, sa, ulli, scva, sa, aaacs, aai);
std::vector<int> loopv;
loopv.reserve(100);
for (int iter = 0; iter < 100; ++iter)
{
loopv.push_back(iter);
}
LOG_INFO(logger, "loopv {}", loopv);
std::vector<std::string> loopsv;
loopsv.reserve(100);
for (int iter = 0; iter < 100; ++iter)
{
loopsv.push_back(std::to_string(iter));
}
LOG_INFO(logger, "loopsv {}", loopsv);
std::vector<int> empt;
LOG_INFO(logger, "empt {}", empt);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aai [[321, 123], [444, 333], [111, 222]]"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" aacs [[\"one\", \"two\"], [\"three\", \"four\"], [\"five\", \"six\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaabcs [[[\"std_one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaaccs [[[\"std_one\", \"two\"], [\"three_std\", \"four\"]], [[\"five\", \"six\"], [\"seven_std\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]] aai [[321, 123], [444, 333], [111, 222]]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopv [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,73 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("string_large_logging")
{
static constexpr char const* filename = "string_large_logging.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_messages = 100;
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string v{
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "
"incididunt ut labore et dolore magna aliqua. Dui accumsan sit amet nulla facilisi "
"morbi tempus. Diam ut venenatis tellus in metus vulputate eu scelerisque felis. Lorem "
"mollis aliquam ut porttitor leo a. Posuere urna nec tincidunt praesent semper feugiat "
"nibh sed. Auctor urna nunc id cursus metus aliquam eleifend mi. Et ultrices neque ornare "
"aenean euismod elementum nisi quis. Phasellus vestibulum lorem sed risus ultricies "
"tristique nulla. Porta nibh venenatis cras sed felis eget velit aliquet sagittis. "
"Eget arcu dictum varius duis at consectetur lorem. Diam quam nulla porttitor massa id "
"neque aliquam vestibulum morbi. Sed euismod nisi porta lorem mollis aliquam. Arcu "
"felis bibendum ut tristique. Lorem ipsum dolor sit amet consectetur adipiscing elit "
"pellentesque habitant. Mauris augue neque gravida in. Dictum fusce ut placerat orci "
"nulla pellentesque dignissim "};
v += std::to_string(i);
LOG_INFO(logger, "Logging int: {}, int: {}, string: {}, string: {}", i, i * 10, v, v);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages);
testing::remove_file(filename);
}

View file

@ -0,0 +1,154 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("string_logging_dynamic_log_level")
{
static constexpr char const* filename = "string_logging_dynamic_log_level.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_messages = 10000;
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
logger->set_log_level(LogLevel::TraceL3);
{
std::string s = "adipiscing";
std::string const empty_s{};
std::string_view begin_s{"begin_s"};
std::string_view const end_s{"end_s"};
std::string_view empty_sv{};
char const* c_style_string_empty = "";
const char* c_style_string = "Lorem ipsum";
char c_style_char_array_empty[] = "";
char const c_style_char_array[] = "dolor";
char c_style_string_array_non_terminated[3];
c_style_string_array_non_terminated[0] = 'A';
c_style_string_array_non_terminated[1] = 'B';
c_style_string_array_non_terminated[2] = 'C';
LOG_DYNAMIC(logger, LogLevel::TraceL3, "s [{}]", s);
LOG_DYNAMIC(logger, LogLevel::TraceL2, "empty_s [{}]", empty_s);
LOG_DYNAMIC(logger, LogLevel::TraceL1, "begin_s [{}]", begin_s);
LOG_DYNAMIC(logger, LogLevel::Debug, "end_s [{}]", end_s);
LOG_DYNAMIC(logger, LogLevel::Info, "empty_sv [{}]", empty_sv);
LOG_DYNAMIC(logger, LogLevel::Warning, "c_style_string_empty [{}]", c_style_string_empty);
LOG_DYNAMIC(logger, LogLevel::Error, "c_style_string [{}]", c_style_string);
LOG_DYNAMIC(logger, LogLevel::Critical, "c_style_char_array_empty [{}]", c_style_char_array_empty);
LOG_DYNAMIC(logger, LogLevel::Info, "c_style_char_array [{}]", c_style_char_array);
LOG_DYNAMIC(logger, LogLevel::Info, "c_style_string_array_non_terminated [{}]",
c_style_string_array_non_terminated);
LOG_DYNAMIC(
logger, LogLevel::Info,
"Lorem ipsum dolor sit amet, consectetur [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
s, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated, s, "elit",
1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated);
LOG_DYNAMIC(logger, LogLevel::Error,
"Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [{}] [{}] "
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
"[{}] [{}] [{}] [{}]",
2, true, begin_s, empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
c_style_string, end_s, c_style_char_array_empty, c_style_char_array, 2, true,
begin_s, empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
c_style_string, end_s, c_style_char_array_empty, c_style_char_array);
}
// Log a big string
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string v{"Lorem ipsum dolor sit amet, consectetur "};
v += std::to_string(i);
LOG_DYNAMIC(logger, LogLevel::Info, "Logging int: {}, int: {}, string: {}, char: {}", i, i * 10,
v, v.c_str());
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages + 12);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_TRACE_L3 " + logger_name + " s [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_TRACE_L2 " + logger_name + " empty_s []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_TRACE_L1 " + logger_name + " begin_s [begin_s]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_DEBUG " + logger_name + " end_s [end_s]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empty_sv []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_WARNING " + logger_name + " c_style_string_empty []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_ERROR " + logger_name + " c_style_string [Lorem ipsum]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_CRITICAL " + logger_name + " c_style_char_array_empty []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_char_array [dolor]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_array_non_terminated [ABC]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC] [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_ERROR " + logger_name + " Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor] [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 0, int: 0, string: Lorem ipsum dolor sit amet, consectetur 0, char: Lorem ipsum dolor sit amet, consectetur 0"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 1999, int: 19990, string: Lorem ipsum dolor sit amet, consectetur 1999, char: Lorem ipsum dolor sit amet, consectetur 1999"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,161 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("string_logging")
{
static constexpr char const* filename = "string_logging.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_messages = 10000;
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::string s = "adipiscing";
std::string const& scr = s;
std::string& sr = s;
std::string const empty_s{};
std::string_view begin_s{"begin_s"};
std::string_view const end_s{"end_s"};
std::string_view empty_sv{};
char const* c_style_string_empty = "";
const char* c_style_string = "Lorem ipsum";
char c_style_char_array_empty[] = "";
char const c_style_char_array[] = "dolor";
char c_style_string_array_non_terminated[3];
c_style_string_array_non_terminated[0] = 'A';
c_style_string_array_non_terminated[1] = 'B';
c_style_string_array_non_terminated[2] = 'C';
LOG_INFO(logger, "s [{}]", s);
LOG_INFO(logger, "scr [{}]", scr);
LOG_INFO(logger, "sr [{}]", sr);
LOG_INFO(logger, "empty_s [{}]", empty_s);
LOG_INFO(logger, "begin_s [{}]", begin_s);
LOG_INFO(logger, "end_s [{}]", end_s);
LOG_INFO(logger, "empty_sv [{}]", empty_sv);
LOG_INFO(logger, "c_style_string_empty [{}]", c_style_string_empty);
LOG_INFO(logger, "c_style_string [{}]", c_style_string);
LOG_INFO(logger, "c_style_char_array_empty [{}]", c_style_char_array_empty);
LOG_INFO(logger, "c_style_char_array [{}]", c_style_char_array);
LOG_INFO(logger, "c_style_string_array_non_terminated [{}]", c_style_string_array_non_terminated);
LOG_INFO(logger,
"Lorem ipsum dolor sit amet, consectetur [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
s, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated, s,
"elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated);
LOG_ERROR(logger,
"Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [{}] [{}] "
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
"[{}] [{}] [{}] [{}]",
2, true, begin_s, empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
c_style_string, end_s, c_style_char_array_empty, c_style_char_array, 2, true, begin_s,
empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
c_style_string, end_s, c_style_char_array_empty, c_style_char_array);
}
// Log a big string
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string v{"Lorem ipsum dolor sit amet, consectetur "};
v += std::to_string(i);
LOG_INFO(logger, "Logging int: {}, int: {}, string: {}, char: {}", i, i * 10, v, v.c_str());
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages + 14);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " s [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scr [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sr [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empty_s []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " begin_s [begin_s]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " end_s [end_s]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empty_sv []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_empty []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string [Lorem ipsum]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_char_array_empty []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_char_array [dolor]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_array_non_terminated [ABC]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC] [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_ERROR " + logger_name + " Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor] [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 0, int: 0, string: Lorem ipsum dolor sit amet, consectetur 0, char: Lorem ipsum dolor sit amet, consectetur 0"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 1999, int: 19990, string: Lorem ipsum dolor sit amet, consectetur 1999, char: Lorem ipsum dolor sit amet, consectetur 1999"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,108 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("string_random_large_logging")
{
static constexpr char const* filename = "string_random_large_logging.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_strings = 500;
static constexpr int min_string_len = 10000;
static constexpr int max_string_len = 20000;
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
std::vector<std::string> random_strings_vec =
quill::testing::gen_random_strings(number_of_strings, min_string_len, max_string_len);
// First push in sequence
int32_t i = 0;
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
LOG_INFO(logger, "{}", elem.c_str());
LOG_INFO(logger, "{}", std::string_view{elem});
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
++i;
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
++i;
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem.c_str());
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
++i;
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", std::string_view{elem});
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
++i;
logger->flush_log();
}
// Then also try to push all
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
LOG_INFO(logger, "{}", elem.c_str());
LOG_INFO(logger, "{}", std::string_view{elem});
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
++i;
}
// clear the vector for the strings to go out of scope for additional testing
size_t const total_log_messages = random_strings_vec.size() * 14;
random_strings_vec.clear();
// Let all log get flushed to the file
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check we logged everything
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), total_log_messages);
testing::remove_file(filename);
}

View file

@ -0,0 +1,97 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("string_random_logging")
{
static constexpr char const* filename = "string_random_logging.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_strings = 2000;
static constexpr int min_string_len = 1;
static constexpr int max_string_len = 1500;
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
std::vector<std::string> random_strings_vec =
quill::testing::gen_random_strings(number_of_strings, min_string_len, max_string_len);
// First push in sequence
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
LOG_INFO(logger, "{}", elem.c_str());
LOG_INFO(logger, "{}", std::string_view{elem});
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem.c_str());
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", std::string_view{elem});
logger->flush_log();
}
// Then also try to push all
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
LOG_INFO(logger, "{}", elem.c_str());
LOG_INFO(logger, "{}", std::string_view{elem});
}
// clear the vector for the strings to go out of scope for additional testing
size_t const total_log_messages = random_strings_vec.size() * 9;
random_strings_vec.clear();
// Let all log get flushed to the file
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check we logged everything
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), total_log_messages);
testing::remove_file(filename);
}

View file

@ -0,0 +1,97 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("string_random_small_logging")
{
static constexpr char const* filename = "string_random_small_logging.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_strings = 500;
static constexpr int min_string_len = 1;
static constexpr int max_string_len = 50;
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
std::vector<std::string> random_strings_vec =
quill::testing::gen_random_strings(number_of_strings, min_string_len, max_string_len);
// First push in sequence
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
LOG_INFO(logger, "{}", elem.c_str());
LOG_INFO(logger, "{}", std::string_view{elem});
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem.c_str());
logger->flush_log();
}
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", std::string_view{elem});
logger->flush_log();
}
// Then also try to push all
for (auto const& elem : random_strings_vec)
{
LOG_INFO(logger, "{}", elem);
LOG_INFO(logger, "{}", elem.c_str());
LOG_INFO(logger, "{}", std::string_view{elem});
}
// clear the vector for the strings to go out of scope for additional testing
size_t const total_log_messages = random_strings_vec.size() * 9;
random_strings_vec.clear();
// Let all log get flushed to the file
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check we logged everything
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), total_log_messages);
testing::remove_file(filename);
}

View file

@ -0,0 +1,120 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Utility.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
class TestTags : public quill::Tags
{
public:
explicit constexpr TestTags(char const* tag_a) : _tag_a(tag_a) {}
void format(std::string& out) const override { out.append(fmtquill::format("{}", _tag_a)); }
private:
char const* _tag_a;
};
static constexpr TestTags tags_a{"TAG_A"};
static constexpr TestTags tags_b{"TAG_B"};
static constexpr quill::utility::CombinedTags<TestTags, TestTags> tags_ab{tags_a, tags_b, " -- "};
/***/
TEST_CASE("tags_logging")
{
static constexpr char const* filename = "tags_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(
logger_name, std::move(file_sink),
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) "
"%(logger:<12) [%(tags)] %(message)\"");
logger->set_log_level(quill::LogLevel::TraceL3);
LOG_TRACE_L3_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_TRACE_L2_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_TRACE_L1_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_DEBUG_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_INFO_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_WARNING_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_ERROR_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_CRITICAL_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
LOG_ERROR_WITH_TAGS(
logger, tags_ab, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante {} {}", 2, true);
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 9);
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_TRACE_L3 " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_TRACE_L2 " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_TRACE_L1 " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_DEBUG " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_WARNING " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_ERROR " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_CRITICAL " + logger_name +
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_ERROR " + logger_name + " [TAG_A -- TAG_B] Nulla tempus, libero at dignissim viverra, lectus libero finibus ante 2 true"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,117 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <vector>
using namespace quill;
/**
* Custom timestamp class
*/
class UserClockSourceTest : public UserClockSource
{
public:
UserClockSourceTest() = default;
/**
* Required by TimestampClock
* @return current time now, in nanoseconds since epoch
*/
uint64_t now() const override { return _ts.load(); }
/**
* set custom timestamp
* @param time_since_epoch timestamp
*/
void set_timestamp(std::chrono::seconds time_since_epoch)
{
// always convert to nanos
_ts.store(static_cast<uint64_t>(std::chrono::nanoseconds{time_since_epoch}.count()));
}
private:
/**
* time since epoch - must always be in nanoseconds
* This class needs to be thread-safe, unless only a single thread in the application calling LOG macros
* **/
std::atomic<uint64_t> _ts;
};
/***/
TEST_CASE("user_clock_source")
{
static constexpr size_t number_of_messages = 10;
static constexpr char const* filename = "user_clock_source.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
UserClockSourceTest uct;
uct.set_timestamp(std::chrono::seconds{1655007309});
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink),
"%(time) %(log_level) %(logger:<16) %(message)", // format
"%Y-%m-%d %H:%M:%S.%Qms", // timestamp format
quill::Timezone::GmtTime, ClockSourceType::User, &uct);
for (size_t i = 0; i < number_of_messages; ++i)
{
// log an array so the log message is pushed to the queue
LOG_INFO(logger, "Lorem ipsum dolor sit amet, consectetur adipiscing elit {}", i);
}
uct.set_timestamp(std::chrono::seconds{1656007309});
for (size_t i = 0; i < number_of_messages; ++i)
{
LOG_ERROR(logger, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante {}", i);
}
// Let all log get flushed to the file
uct.set_timestamp(std::chrono::seconds{1658007309});
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages * 2);
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string expected_string = "2022-06-12 04:15:09.000 INFO " + logger_name +
" Lorem ipsum dolor sit amet, consectetur adipiscing elit " + std::to_string(i);
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
}
for (size_t i = 0; i < number_of_messages; ++i)
{
std::string expected_string = "2022-06-23 18:01:49.000 ERROR " + logger_name +
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante " +
std::to_string(i);
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
}
testing::remove_file(filename);
}

View file

@ -0,0 +1,152 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Utility.h"
#include "quill/sinks/FileSink.h"
#include "quill/core/Codec.h"
#include "quill/core/DynamicFormatArgStore.h"
#include "quill/std/Array.h"
#include "quill/std/Vector.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/**
* CustomType defined type
*/
struct CustomType
{
std::string name;
std::string surname;
uint32_t age;
std::array<std::string, 3> favorite_colors;
};
/***/
template <>
struct fmtquill::formatter<CustomType>
{
template <typename FormatContext>
constexpr auto parse(FormatContext& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(::CustomType const& custom_type, FormatContext& ctx) const
{
return fmtquill::format_to(ctx.out(), "Name: {}, Surname: {}, Age: {}, Favorite Colors: {}",
custom_type.name, custom_type.surname, custom_type.age,
custom_type.favorite_colors);
}
};
/***/
template <>
struct quill::detail::ArgSizeCalculator<CustomType>
{
static size_t calculate(std::vector<size_t>& conditional_arg_size_cache, ::CustomType const& custom_type) noexcept
{
// pass as arguments the class members you want to serialize
return calculate_total_size(conditional_arg_size_cache, custom_type.name, custom_type.surname,
custom_type.age, custom_type.favorite_colors);
}
};
/***/
template <>
struct quill::detail::Encoder<CustomType>
{
static void encode(std::byte*& buffer, std::vector<size_t> const& conditional_arg_size_cache,
uint32_t& conditional_arg_size_cache_index, ::CustomType const& custom_type) noexcept
{
// You must encode the same members and in the same order as in the ArgSizeCalculator::calculate
encode_members(buffer, conditional_arg_size_cache, conditional_arg_size_cache_index,
custom_type.name, custom_type.surname, custom_type.age, custom_type.favorite_colors);
}
};
/***/
template <>
struct quill::detail::Decoder<CustomType>
{
static ::CustomType decode(std::byte*& buffer, DynamicFormatArgStore* args_store)
{
// You must decode the same members and in the same order as in the Encoder::encode
::CustomType custom_type;
decode_and_assign_members(buffer, args_store, custom_type, custom_type.name,
custom_type.surname, custom_type.age, custom_type.favorite_colors);
return custom_type;
}
};
/***/
TEST_CASE("custom_type_defined_type_logging")
{
static constexpr char const* filename = "custom_type_defined_type_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(
logger_name, std::move(file_sink),
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) "
"%(logger:<12) %(message)");
logger->set_log_level(quill::LogLevel::TraceL3);
CustomType custom_type;
custom_type.name = "Quill";
custom_type.surname = "Library";
custom_type.age = 4;
custom_type.favorite_colors[0] = "red";
custom_type.favorite_colors[1] = "green";
custom_type.favorite_colors[2] = "blue";
LOG_INFO(logger, "The answer is {}", custom_type);
std::vector<CustomType> const custom_types = {{"Alice", "Doe", 25, {"red", "green"}},
{"Bob", "Smith", 30, {"blue", "yellow"}},
{"Charlie", "Johnson", 35, {"green", "orange"}},
{"David", "Brown", 40, {"red", "blue", "yellow"}}};
LOG_INFO(logger, "The answers are {}", custom_types);
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), 2);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " The answer is Name: Quill, Surname: Library, Age: 4, Favorite Colors: [\"red\", \"green\", \"blue\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " The answers are [Name: Alice, Surname: Doe, Age: 25, Favorite Colors: [\"red\", \"green\", \"\"], Name: Bob, Surname: Smith, Age: 30, Favorite Colors: [\"blue\", \"yellow\", \"\"], Name: Charlie, Surname: Johnson, Age: 35, Favorite Colors: [\"green\", \"orange\", \"\"], Name: David, Surname: Brown, Age: 40, Favorite Colors: [\"red\", \"blue\", \"yellow\"]]"}));
testing::remove_file(filename);
}

View file

@ -0,0 +1,330 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/core/Filesystem.h"
#include "quill/sinks/FileSink.h"
#include "quill/std/Array.h"
#include "quill/std/Deque.h"
#include "quill/std/FilesystemPath.h"
#include "quill/std/ForwardList.h"
#include "quill/std/List.h"
#include "quill/std/Map.h"
#include "quill/std/Optional.h"
#include "quill/std/Pair.h"
#include "quill/std/Set.h"
#include "quill/std/UnorderedMap.h"
#include "quill/std/UnorderedSet.h"
#include "quill/std/Vector.h"
#include <array>
#include <cstdio>
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace quill;
struct CWideStringComparator
{
bool operator()(wchar_t const* a, wchar_t const* b) const { return std::wcscmp(a, b) < 0; }
};
/***/
TEST_CASE("wide_std_types_logging")
{
#if defined(_WIN32)
static constexpr char const* filename = "wide_std_types_logging.log";
static std::string const logger_name = "logger";
// Start the logging backend thread
Backend::start();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
fs::path wp{L"C:\\some\\path"};
LOG_INFO(logger, "wp {}", wp);
fs::path p{"C:\\another\\path"};
LOG_INFO(logger, "p {}", p);
LOG_INFO(logger, "wp {} p {}", wp, p);
std::array<std::wstring, 2> wsa = {L"test", L"string"};
LOG_INFO(logger, "wsa {}", wsa);
std::array<std::wstring_view, 2> wsva = {L"test", L"string_view"};
LOG_INFO(logger, "wsva {}", wsva);
std::array<wchar_t const*, 4> wscva = {L"c style", L"string test", L"test", L"log"};
LOG_INFO(logger, "wscva {}", wscva);
std::deque<std::wstring> wds = {L"test", L"string"};
LOG_INFO(logger, "wds {}", wds);
std::deque<std::wstring_view> wdsv = {L"test", L"string_view"};
LOG_INFO(logger, "wdsv {}", wdsv);
std::deque<wchar_t const*> wdcs = {L"c style", L"string test", L"test", L"log"};
LOG_INFO(logger, "wdcs {}", wdcs);
std::forward_list<std::wstring> wfs = {L"test", L"string"};
LOG_INFO(logger, "wfs {}", wfs);
std::forward_list<std::wstring_view> wfsv = {L"test", L"string_view"};
LOG_INFO(logger, "wfsv {}", wfsv);
std::forward_list<wchar_t const*> wfcs = {L"c style", L"string test", L"test", L"log"};
LOG_INFO(logger, "wfcs {}", wfcs);
std::list<std::wstring> sl = {L"test", L"string"};
LOG_INFO(logger, "sl {}", sl);
std::list<std::wstring_view> svl = {L"test", L"string_view"};
LOG_INFO(logger, "svl {}", svl);
std::list<wchar_t const*> scl = {L"c style", L"string test", L"test", L"log"};
LOG_INFO(logger, "scl {}", scl);
std::vector<std::wstring> wsv = {L"test", L"string"};
LOG_INFO(logger, "wsv {}", wsv);
std::vector<std::wstring_view> wsvv = {L"test", L"string_view"};
LOG_INFO(logger, "wsvv {}", wsvv);
std::vector<wchar_t const*> wscv = {L"c style", L"string test", L"test", L"log"};
LOG_INFO(logger, "wscv {}", wscv);
std::pair<std::wstring, std::wstring> wpss = {L"test", L"string"};
LOG_INFO(logger, "wpss {}", wpss);
std::pair<std::wstring_view, std::wstring> wpsv = {L"test", L"string_view"};
LOG_INFO(logger, "wpsv {}", wpsv);
std::pair<wchar_t const*, std::wstring> wscs = {L"c style", L"string test"};
LOG_INFO(logger, "wscs {}", wscs);
std::pair<int, std::wstring> wscsi = {1231, L"string test"};
LOG_INFO(logger, "wscsi {}", wscsi);
std::pair<std::wstring, double> wscsd = {L"string test", 443.2};
LOG_INFO(logger, "wscsd {}", wscsd);
std::optional<std::wstring> weo{std::nullopt};
LOG_INFO(logger, "eo {}", weo);
std::optional<std::wstring> wos{L"test"};
LOG_INFO(logger, "wos {}", wos);
std::optional<std::wstring_view> wosv{L"test"};
LOG_INFO(logger, "wosv {}", wosv);
std::optional<wchar_t const*> woc{L"test"};
LOG_INFO(logger, "woc {}", woc);
std::set<std::wstring> sa = {L"test", L"string"};
LOG_INFO(logger, "sa {}", sa);
std::set<std::wstring> sva = {L"test", L"string_view"};
LOG_INFO(logger, "sva {}", sva);
std::set<wchar_t const*, CWideStringComparator> scva = {L"c_style", L"aa", L"string_test",
L"test", L"log"};
LOG_INFO(logger, "scva {}", scva);
std::map<std::wstring, std::wstring> ccm = {{L"4", L"400"}, {L"3", L"300"}, {L"1", L"100"}};
LOG_INFO(logger, "ccm {}", ccm);
std::map<std::wstring, int> ccmx = {{L"4", 400}, {L"3", 300}, {L"1", 100}};
LOG_INFO(logger, "ccmx {}", ccmx);
std::map<wchar_t const*, std::wstring, CWideStringComparator> ccmc = {
{L"4", L"400"}, {L"3", L"300"}, {L"1", L"100"}};
LOG_INFO(logger, "ccmc {}", ccmc);
std::map<int, std::wstring> ccmi = {{4, L"400"}, {3, L"300"}, {1, L"100"}};
LOG_INFO(logger, "ccmi {}", ccmi);
std::unordered_set<std::wstring> uss = {L"test"};
LOG_INFO(logger, "uss {}", uss);
std::unordered_set<std::wstring_view> usvs = {L"string_view"};
LOG_INFO(logger, "usvs {}", usvs);
std::unordered_set<wchar_t const*> uscs = {L"c_style"};
LOG_INFO(logger, "uscs {}", uscs);
std::unordered_map<std::wstring, std::wstring> uccm = {{L"4", L"400"}};
LOG_INFO(logger, "uccm {}", uccm);
std::unordered_map<std::wstring, int> uccmx = {{L"5", 500}};
LOG_INFO(logger, "uccmx {}", uccmx);
std::unordered_map<wchar_t const*, std::wstring> uccmc = {{L"6", L"600"}};
LOG_INFO(logger, "uccmc {}", uccmc);
std::unordered_map<int, std::wstring> uccmi = {{7, L"700"}};
LOG_INFO(logger, "uccmi {}", uccmi);
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wp C:\\some\\path"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " p C:\\another\\path"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wp C:\\some\\path p C:\\another\\path"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wsa [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wsva [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wscva [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wds [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wdsv [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wdcs [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wfs [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wfsv [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wfcs [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sl [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " svl [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " scl [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wsv [\"test\", \"string\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wsvv [\"test\", \"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wscv [\"c style\", \"string test\", \"test\", \"log\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wpss (\"test\", \"string\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wpsv (\"test\", \"string_view\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wscs (\"c style\", \"string test\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wscsi (1231, \"string test\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wscsd (\"string test\", 443.2)"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " eo none"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wos optional(\"test\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " wosv optional(\"test\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " woc optional(\"test\")"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"string\", \"test\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"string_view\", \"test\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents,
std::string{"LOG_INFO " + logger_name +
" scva [\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ccm [(\"1\", \"100\"), (\"3\", \"300\"), (\"4\", \"400\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ccmx [(\"1\", 100), (\"3\", 300), (\"4\", 400)]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ccmc [(\"1\", \"100\"), (\"3\", \"300\"), (\"4\", \"400\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ccmi [(1, \"100\"), (3, \"300\"), (4, \"400\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uss [\"test\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " usvs [\"string_view\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uscs [\"c_style\"]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uccm [(\"4\", \"400\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uccmx [(\"5\", 500)]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uccmc [(\"6\", \"600\")]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " uccmi [(7, \"700\")]"}));
testing::remove_file(filename);
#endif
}

View file

@ -0,0 +1,136 @@
#include "doctest/doctest.h"
#include "misc/TestUtilities.h"
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/sinks/FileSink.h"
#include <cstdio>
#include <string>
#include <string_view>
#include <vector>
using namespace quill;
/***/
TEST_CASE("wide_string_logging")
{
#if defined(_WIN32)
static constexpr char const* filename = "wide_string_logging.log";
static std::string const logger_name = "logger";
static constexpr size_t number_of_messages = 10000;
// Start the logging backend thread
Backend::start();
Frontend::preallocate();
// Set writing logging to a file
auto file_sink = Frontend::create_or_get_sink<FileSink>(
filename,
[]()
{
FileSinkConfig cfg;
cfg.set_open_mode('w');
return cfg;
}(),
FileEventNotifier{});
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
{
std::string s = "adipiscing";
std::wstring ws = L"adipiscing";
std::wstring const empty_s{};
std::wstring_view begin_s{L"begin_s"};
std::wstring_view const end_s{L"end_s"};
std::wstring_view empty_sv{};
wchar_t const* c_style_string_empty = L"";
wchar_t const* c_style_string = L"Lorem ipsum";
LOG_INFO(logger, "s [{}]", s);
LOG_INFO(logger, "ws [{}]", ws);
LOG_INFO(logger, "empty_s [{}]", empty_s);
LOG_INFO(logger, "begin_s [{}]", begin_s);
LOG_INFO(logger, "end_s [{}]", end_s);
LOG_INFO(logger, "empty_sv [{}]", empty_sv);
LOG_INFO(logger, "c_style_string_empty [{}]", c_style_string_empty);
LOG_INFO(logger, "c_style_string [{}]", c_style_string);
LOG_INFO(logger,
"Lorem ipsum dolor sit amet, consectetur [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
ws, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty,
c_style_string, ws, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv,
c_style_string_empty, c_style_string, s);
LOG_ERROR(logger,
"Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [{}] [{}] "
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
2, true, begin_s, empty_sv, empty_s, c_style_string_empty, c_style_string, end_s, 2,
true, begin_s, empty_sv, empty_s, c_style_string_empty, c_style_string, end_s, s);
}
// Log a big string
for (size_t i = 0; i < number_of_messages; ++i)
{
std::wstring v{
L"Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem "
L"ipsum dolor sit amet, consectetur "};
v += std::to_wstring(i);
LOG_INFO(logger, "Logging int: {}, int: {}, string: {}, char: {}", i, i * 10, v, v.c_str());
}
logger->flush_log();
Frontend::remove_logger(logger);
// Wait until the backend thread stops for test stability
Backend::stop();
// Read file and check
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
REQUIRE_EQ(file_contents.size(), number_of_messages + 10);
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " s [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " ws [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empty_s []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " begin_s [begin_s]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " end_s [end_s]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " empty_sv []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_empty []"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string [Lorem ipsum]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_ERROR " + logger_name + " Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [2] [true] [begin_s] [] [] [] [Lorem ipsum] [end_s] [2] [true] [begin_s] [] [] [] [Lorem ipsum] [end_s] [adipiscing]"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 0, int: 0, string: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 0, char: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 0"}));
REQUIRE(quill::testing::file_contains(
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 1999, int: 19990, string: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 1999, char: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 1999"}));
testing::remove_file(filename);
#endif
}