mirror of https://github.com/djcb/mu.git
mu-logger: Add lock for file-logger and stress test
Add a lock to the file logger and add a unit-test to stress test it. (It does fail without the lock, and passed with it). Should help for: #2469.
This commit is contained in:
parent
c5c9531c37
commit
2aa0d20f39
|
@ -65,4 +65,10 @@ test('test-utils-file',
|
|||
cpp_args: ['-DBUILD_TESTS'],
|
||||
dependencies: [glib_dep, config_h_dep, lib_mu_utils_dep]))
|
||||
|
||||
test('test-logger',
|
||||
executable('test-logger', 'mu-logger.cc',
|
||||
install: false,
|
||||
cpp_args: ['-DBUILD_TESTS'],
|
||||
dependencies: [glib_dep, lib_mu_utils_dep]))
|
||||
|
||||
subdir('tests')
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#include "mu-logger.hh"
|
||||
|
||||
using namespace Mu;
|
||||
|
@ -36,6 +39,7 @@ static bool MuLogInitialized = false;
|
|||
static Mu::Logger::Options MuLogOptions;
|
||||
static std::ofstream MuStream;
|
||||
static auto MaxLogFileSize = 1000 * 1024;
|
||||
static std::mutex logger_mtx;
|
||||
|
||||
static std::string MuLogPath;
|
||||
|
||||
|
@ -84,6 +88,8 @@ maybe_rotate_logfile()
|
|||
static GLogWriterOutput
|
||||
log_file(GLogLevelFlags level, const GLogField* fields, gsize n_fields, gpointer user_data)
|
||||
{
|
||||
std::lock_guard lock{logger_mtx};
|
||||
|
||||
if (!maybe_open_logfile())
|
||||
return G_LOG_WRITER_UNHANDLED;
|
||||
|
||||
|
@ -124,7 +130,6 @@ Mu::Logger::make(const std::string& path, Mu::Logger::Options opts)
|
|||
return Ok(Logger(path, opts));
|
||||
}
|
||||
|
||||
|
||||
Mu::Logger::Logger(const std::string& path, Mu::Logger::Options opts)
|
||||
{
|
||||
if (g_getenv("MU_LOG_STDOUTERR"))
|
||||
|
@ -147,7 +152,8 @@ Mu::Logger::Logger(const std::string& path, Mu::Logger::Options opts)
|
|||
}
|
||||
|
||||
// log to the journal, or, if not available to a file.
|
||||
if (log_journal(level, fields, n_fields, user_data) != G_LOG_WRITER_HANDLED)
|
||||
if (any_of(MuLogOptions & Options::File) ||
|
||||
log_journal(level, fields, n_fields, user_data) != G_LOG_WRITER_HANDLED)
|
||||
return log_file(level, fields, n_fields, user_data);
|
||||
else
|
||||
return G_LOG_WRITER_HANDLED;
|
||||
|
@ -172,3 +178,56 @@ Logger::~Logger()
|
|||
|
||||
MuLogInitialized = false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BUILD_TESTS
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
#include "mu-test-utils.hh"
|
||||
|
||||
static void
|
||||
test_logger_threads(void)
|
||||
{
|
||||
const auto testpath{test_random_tmpdir() + "/test.log"};
|
||||
g_message("log-file: %s", testpath.c_str());
|
||||
|
||||
auto logger = Logger::make(testpath.c_str(), Logger::Options::File | Logger::Options::Debug);
|
||||
assert_valid_result(logger);
|
||||
|
||||
const auto thread_num = 16;
|
||||
std::atomic<bool> running = true;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
/* log to the logger file from many threass */
|
||||
for (auto n = 0; n != thread_num; ++n)
|
||||
threads.emplace_back(
|
||||
std::thread([n,&running]{
|
||||
while (running) {
|
||||
g_debug("log message from thread <%d>", n);
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}));
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(1s);
|
||||
running = false;
|
||||
|
||||
for (auto n = 0; n != 16; ++n)
|
||||
if (threads[n].joinable())
|
||||
threads[n].join();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
mu_test_init(&argc, &argv);
|
||||
|
||||
g_test_add_func("/utils/logger", test_logger_threads);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
#endif /*BUILD_TESTS*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Copyright (C) 2020-2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
** Copyright (C) 2020-2023 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify it
|
||||
** under the terms of the GNU General Public License as published by the
|
||||
|
@ -39,12 +39,12 @@ struct Logger {
|
|||
enum struct Options {
|
||||
None = 0, /**< Nothing specific */
|
||||
StdOutErr = 1 << 1, /**< Log to stdout/stderr */
|
||||
Debug = 1 << 2, /**< Include debug-level logs */
|
||||
File = 1 << 2, /**< Force logging to file, even if journal available */
|
||||
Debug = 1 << 3, /**< Include debug-level logs */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the logging system.
|
||||
* Initialize the logging sub-system.
|
||||
*
|
||||
* Note that the path is only used if structured logging fails --
|
||||
* practically, it goes to the file if there's no systemd/journald.
|
||||
|
|
Loading…
Reference in New Issue