From a20361b3b4f3f43695740c59cc83b0bce62e8aeb Mon Sep 17 00:00:00 2001 From: nircoe Date: Mon, 28 Sep 2026 19:06:49 +0300 Subject: [PATCH 1/9] [Syntax]: Adopt gamecoe's naming convention --- CMakeLists.txt | 2 +- cmake/utils.cmake | 10 +++++----- tests/CMakeLists.txt | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 777f3f6..8c0e204 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ target_include_directories(logcoe include(cmake/utils.cmake) -enable_strict_warnings(logcoe) +logcoe_enable_strict_warnings(logcoe) option(LOGCOE_BUILD_TESTS "Build the logcoe test suite" OFF) if(LOGCOE_BUILD_TESTS) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 6903c01..0ad870f 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -1,6 +1,6 @@ # Automatically copies required MinGW DLLs to target directory on Windows -function(copy_mingw_dlls_to_target target_name) +function(logcoe_copy_mingw_dlls_to_target target_name) if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") message(STATUS "[logcoe] Setting up automatic MinGW DLL copying for ${target_name}") @@ -34,13 +34,13 @@ function(copy_mingw_dlls_to_target target_name) endfunction() # Alternative function for multiple targets -function(copy_mingw_dlls_to_targets) +function(logcoe_copy_mingw_dlls_to_targets) foreach(target_name ${ARGN}) - copy_mingw_dlls_to_target(${target_name}) + logcoe_copy_mingw_dlls_to_target(${target_name}) endforeach() endfunction() -function(ignore_external_warnings target_name) +function(logcoe_ignore_external_warnings target_name) if(TARGET ${target_name}) get_target_property(INCLUDE_DIRS ${target_name} INTERFACE_INCLUDE_DIRECTORIES) if(INCLUDE_DIRS) @@ -54,7 +54,7 @@ function(ignore_external_warnings target_name) endif() endfunction() -function(enable_strict_warnings target_name) +function(logcoe_enable_strict_warnings target_name) if(MSVC) target_compile_options(${target_name} PRIVATE /W4 /WX) else() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f955532..bcda13e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,7 +12,7 @@ else() FetchContent_MakeAvailable(testcoe) endif() -ignore_external_warnings(testcoe) +logcoe_ignore_external_warnings(testcoe) add_executable(logcoe_tests main.cpp logcoe_test.cpp logcoe_thread_test.cpp) @@ -22,7 +22,7 @@ target_link_libraries(logcoe_tests testcoe ) -enable_strict_warnings(logcoe_tests) +logcoe_enable_strict_warnings(logcoe_tests) add_custom_target(run_logcoe_tests COMMAND logcoe_tests @@ -38,7 +38,7 @@ target_link_libraries(logcoe_strip_tests testcoe ) -enable_strict_warnings(logcoe_strip_tests) +logcoe_enable_strict_warnings(logcoe_strip_tests) add_custom_target(run_logcoe_strip_tests COMMAND logcoe_strip_tests @@ -46,4 +46,4 @@ add_custom_target(run_logcoe_strip_tests WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) -copy_mingw_dlls_to_targets(logcoe_tests logcoe_strip_tests) \ No newline at end of file +logcoe_copy_mingw_dlls_to_targets(logcoe_tests logcoe_strip_tests) \ No newline at end of file From 069d1044e079982096df701bfbc722c9d665f927 Mon Sep 17 00:00:00 2001 From: nircoe Date: Mon, 28 Sep 2026 21:35:18 +0300 Subject: [PATCH 2/9] Align public API --- include/logcoe.hpp | 44 +++++++-------- src/logcoe.cpp | 130 ++++++++++++++++++++++----------------------- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/include/logcoe.hpp b/include/logcoe.hpp index 6190f9f..705885f 100644 --- a/include/logcoe.hpp +++ b/include/logcoe.hpp @@ -4,36 +4,36 @@ namespace logcoe { - enum class LogLevel + enum class log_level { - DEBUG, - INFO, - WARNING, - ERROR, - NONE + debug, + info, + warning, + error, + none }; - void initialize(LogLevel level = LogLevel::DEBUG, - const std::string &defaultSource = "", - bool enableConsole = true, - bool enableFile = false, + void initialize(log_level level = log_level::debug, + const std::string &default_source = "", + bool enable_console = true, + bool enable_file = false, const std::string &filename = "logcoe.log"); void shutdown(); - void setLogLevel(LogLevel level); - void setConsoleOutput(std::ostream &stream); - bool setFileOutput(const std::string &filename); - void disableConsoleOutput(); - void disableFileOutput(); - void setTimeFormat(const std::string &format); + void set_log_level(log_level level); + void set_console_output(std::ostream &stream); + bool set_file_output(const std::string &filename); + void disable_console_output(); + void disable_file_output(); + void set_time_format(const std::string &format); - bool isInitialized(); - LogLevel getLogLevel(); + bool is_initialized(); + log_level get_log_level(); - void debug(const std::string &message, const std::string &source = "", bool flush = true); - void info(const std::string &message, const std::string &source = "", bool flush = true); - void warning(const std::string &message, const std::string &source = "", bool flush = true); - void error(const std::string &message, const std::string &source = "", bool flush = true); + void debug(const std::string &message, const std::string &source = "", bool flush_ = true); + void info(const std::string &message, const std::string &source = "", bool flush_ = true); + void warning(const std::string &message, const std::string &source = "", bool flush_ = true); + void error(const std::string &message, const std::string &source = "", bool flush_ = true); void flush(); } // namespace logcoe \ No newline at end of file diff --git a/src/logcoe.cpp b/src/logcoe.cpp index 592daa2..f74b23e 100644 --- a/src/logcoe.cpp +++ b/src/logcoe.cpp @@ -7,7 +7,7 @@ #include #include -using logcoe::LogLevel; +using logcoe::log_level; #ifndef NDEBUG namespace @@ -15,7 +15,7 @@ namespace class LoggerImpl { static unsigned int s_initCounter; - static LogLevel s_logLevel; + static log_level s_logLevel; static std::string s_defaultSource; static std::mutex s_mutex; static std::string s_filename; @@ -26,21 +26,21 @@ namespace static std::string s_timeFormat; static std::string getCurrentTimestamp(); - static std::string getLogLevelAsString(LogLevel level); + static std::string getLogLevelAsString(log_level level); static void writeToOutputs(const std::string &formattedMessage, - LogLevel level = LogLevel::INFO, - bool flush = true); - static void log(LogLevel level, const std::string &message, const std::string &source, bool flush); + log_level level = log_level::info, + bool flush_ = true); + static void log(log_level level, const std::string &message, const std::string &source, bool flush_); public: - static void initialize(LogLevel level = LogLevel::INFO, - const std::string &defaultSource = "", - bool enableConsole = true, - bool enableFile = false, + static void initialize(log_level level = log_level::info, + const std::string &default_source = "", + bool enable_console = true, + bool enable_file = false, const std::string &filename = "logcoe.log"); static void shutdown(); - static void setLogLevel(LogLevel level); + static void setLogLevel(log_level level); static void setConsoleOutput(std::ostream &stream); static bool setFileOutput(const std::string &filename); static void disableConsoleOutput(); @@ -48,17 +48,17 @@ namespace static void setTimeFormat(const std::string &format); static bool isInitialized(); - static LogLevel getLogLevel(); + static log_level getLogLevel(); - static void debug(const std::string &message, const std::string &source = "", bool flush = true); - static void info(const std::string &message, const std::string &source = "", bool flush = true); - static void warning(const std::string &message, const std::string &source = "", bool flush = true); - static void error(const std::string &message, const std::string &source = "", bool flush = true); + static void debug(const std::string &message, const std::string &source = "", bool flush_ = true); + static void info(const std::string &message, const std::string &source = "", bool flush_ = true); + static void warning(const std::string &message, const std::string &source = "", bool flush_ = true); + static void error(const std::string &message, const std::string &source = "", bool flush_ = true); static void flush(); }; unsigned int LoggerImpl::s_initCounter = 0; - LogLevel LoggerImpl::s_logLevel = LogLevel::INFO; + log_level LoggerImpl::s_logLevel = log_level::info; std::string LoggerImpl::s_defaultSource = ""; std::mutex LoggerImpl::s_mutex; std::string LoggerImpl::s_filename = "logcoe.log"; @@ -88,26 +88,26 @@ namespace return std::string(buffer); } - std::string LoggerImpl::getLogLevelAsString(LogLevel level) + std::string LoggerImpl::getLogLevelAsString(log_level level) { if(s_initCounter == 0) return ""; switch (level) { - case LogLevel::DEBUG: + case log_level::debug: return "DEBUG"; - case LogLevel::INFO: + case log_level::info: return "INFO"; - case LogLevel::WARNING: + case log_level::warning: return "WARNING"; - case LogLevel::ERROR: + case log_level::error: return "ERROR"; default: return "NONE"; } } - void LoggerImpl::writeToOutputs(const std::string &formattedMessage, LogLevel level, bool flush) + void LoggerImpl::writeToOutputs(const std::string &formattedMessage, log_level level, bool flush_) { if (s_initCounter == 0 || static_cast(level) < static_cast(s_logLevel)) return; @@ -115,19 +115,19 @@ namespace if (s_useConsole && s_consoleStream) { *s_consoleStream << formattedMessage << std::endl; - if (flush) + if (flush_) s_consoleStream->flush(); } if (s_useFile) { s_fileStream << formattedMessage << std::endl; - if (flush) + if (flush_) s_fileStream.flush(); } } - void LoggerImpl::log(LogLevel level, const std::string &message, const std::string &source, bool flush) + void LoggerImpl::log(log_level level, const std::string &message, const std::string &source, bool flush_) { std::lock_guard lock(s_mutex); if(s_initCounter == 0) return; @@ -139,21 +139,21 @@ namespace formattedMessage << " [" << source << "]"; formattedMessage << ": " << message; - writeToOutputs(formattedMessage.str(), level, flush); + writeToOutputs(formattedMessage.str(), level, flush_); } - void LoggerImpl::initialize(LogLevel level, const std::string &defaultSource, bool enableConsole, bool enableFile, const std::string &filename) + void LoggerImpl::initialize(log_level level, const std::string &default_source, bool enable_console, bool enable_file, const std::string &filename) { std::lock_guard lock(s_mutex); if(s_initCounter++ > 0) return writeToOutputs("[logcoe] Already initialized, ignoring new configurations"); s_logLevel = level; - s_defaultSource = defaultSource; - s_useConsole = enableConsole; + s_defaultSource = default_source; + s_useConsole = enable_console; if (s_useConsole && !s_consoleStream) s_consoleStream = &std::cout; - s_useFile = enableFile; + s_useFile = enable_file; if (filename != s_filename) s_filename = filename; @@ -200,12 +200,12 @@ namespace s_consoleStream = nullptr; s_useConsole = false; s_useFile = false; - s_logLevel = LogLevel::NONE; + s_logLevel = log_level::none; s_filename = "logcoe.log"; s_initCounter = 0; } - void LoggerImpl::setLogLevel(LogLevel level) + void LoggerImpl::setLogLevel(log_level level) { std::lock_guard lock(s_mutex); if(s_initCounter == 0) return; @@ -317,31 +317,31 @@ namespace return s_initCounter > 0; } - LogLevel LoggerImpl::getLogLevel() + log_level LoggerImpl::getLogLevel() { std::lock_guard lock(s_mutex); return s_logLevel; } - void LoggerImpl::debug(const std::string &message, const std::string &source, bool flush) + void LoggerImpl::debug(const std::string &message, const std::string &source, bool flush_) { - log(LogLevel::DEBUG, message, source.empty() ? s_defaultSource : source, flush); + log(log_level::debug, message, source.empty() ? s_defaultSource : source, flush_); } - void LoggerImpl::info(const std::string &message, const std::string &source, bool flush) + void LoggerImpl::info(const std::string &message, const std::string &source, bool flush_) { - log(LogLevel::INFO, message, source.empty() ? s_defaultSource : source, flush); + log(log_level::info, message, source.empty() ? s_defaultSource : source, flush_); } - void LoggerImpl::warning(const std::string &message, const std::string &source, bool flush) + void LoggerImpl::warning(const std::string &message, const std::string &source, bool flush_) { - log(LogLevel::WARNING, message, source.empty() ? s_defaultSource : source, flush); + log(log_level::warning, message, source.empty() ? s_defaultSource : source, flush_); } - void LoggerImpl::error(const std::string &message, const std::string &source, bool flush) + void LoggerImpl::error(const std::string &message, const std::string &source, bool flush_) { - log(LogLevel::ERROR, message, source.empty() ? s_defaultSource : source, flush); + log(log_level::error, message, source.empty() ? s_defaultSource : source, flush_); } void LoggerImpl::flush() @@ -358,19 +358,19 @@ namespace namespace logcoe { #ifdef NDEBUG - void initialize(LogLevel, const std::string &, bool, bool, const std::string &) { } + void initialize(log_level, const std::string &, bool, bool, const std::string &) { } void shutdown() { } - void setLogLevel(LogLevel) { } - void setConsoleOutput(std::ostream &) { } - bool setFileOutput(const std::string &) { return false; } - void disableConsoleOutput() { } - void disableFileOutput() { } - void setTimeFormat(const std::string &) { } + void set_log_level(log_level) { } + void set_console_output(std::ostream &) { } + bool set_file_output(const std::string &) { return false; } + void disable_console_output() { } + void disable_file_output() { } + void set_time_format(const std::string &) { } - bool isInitialized() { return false; } - LogLevel getLogLevel() { return LogLevel::NONE; } + bool is_initialized() { return false; } + log_level get_log_level() { return log_level::none; } void debug(const std::string &, const std::string &, bool) { } void info(const std::string &, const std::string &, bool) { } @@ -378,25 +378,25 @@ namespace logcoe void error(const std::string &, const std::string &, bool) { } void flush() { } #else - void initialize(LogLevel level, const std::string &defaultSource, bool enableConsole, - bool enableFile, const std::string &filename) { LoggerImpl::initialize(level, defaultSource, enableConsole, enableFile, filename); } + void initialize(log_level level, const std::string &default_source, bool enable_console, + bool enable_file, const std::string &filename) { LoggerImpl::initialize(level, default_source, enable_console, enable_file, filename); } void shutdown() { LoggerImpl::shutdown(); } - void setLogLevel(LogLevel level) { LoggerImpl::setLogLevel(level); } - void setConsoleOutput(std::ostream &stream) { LoggerImpl::setConsoleOutput(stream); } - bool setFileOutput(const std::string &filename) { return LoggerImpl::setFileOutput(filename); } - void disableConsoleOutput() { LoggerImpl::disableConsoleOutput(); } - void disableFileOutput() { LoggerImpl::disableFileOutput(); } - void setTimeFormat(const std::string &format) { LoggerImpl::setTimeFormat(format); } + void set_log_level(log_level level) { LoggerImpl::setLogLevel(level); } + void set_console_output(std::ostream &stream) { LoggerImpl::setConsoleOutput(stream); } + bool set_file_output(const std::string &filename) { return LoggerImpl::setFileOutput(filename); } + void disable_console_output() { LoggerImpl::disableConsoleOutput(); } + void disable_file_output() { LoggerImpl::disableFileOutput(); } + void set_time_format(const std::string &format) { LoggerImpl::setTimeFormat(format); } - bool isInitialized() { return LoggerImpl::isInitialized(); } - LogLevel getLogLevel() { return LoggerImpl::getLogLevel(); } + bool is_initialized() { return LoggerImpl::isInitialized(); } + log_level get_log_level() { return LoggerImpl::getLogLevel(); } - void debug(const std::string &message, const std::string &source, bool flush) { LoggerImpl::debug(message, source, flush); } - void info(const std::string &message, const std::string &source, bool flush) { LoggerImpl::info(message, source, flush); } - void warning(const std::string &message, const std::string &source, bool flush) { LoggerImpl::warning(message, source, flush); } - void error(const std::string &message, const std::string &source, bool flush) { LoggerImpl::error(message, source, flush); } + void debug(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::debug(message, source, flush_); } + void info(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::info(message, source, flush_); } + void warning(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::warning(message, source, flush_); } + void error(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::error(message, source, flush_); } void flush() { LoggerImpl::flush(); } #endif From fb0757aa8e5e93b8e2b758f6bb576497d72152cf Mon Sep 17 00:00:00 2001 From: nircoe Date: Mon, 28 Sep 2026 21:55:46 +0300 Subject: [PATCH 3/9] Drop LoggerImpl for free functions --- src/logcoe.cpp | 357 ++++++++++++++++++++++--------------------------- 1 file changed, 159 insertions(+), 198 deletions(-) diff --git a/src/logcoe.cpp b/src/logcoe.cpp index f74b23e..10c8427 100644 --- a/src/logcoe.cpp +++ b/src/logcoe.cpp @@ -12,65 +12,20 @@ using logcoe::log_level; #ifndef NDEBUG namespace { - class LoggerImpl + unsigned int g_init_counter = 0; + log_level g_log_level = log_level::info; + std::string g_default_source = ""; + std::mutex g_mutex; + std::string g_filename = "logcoe.log"; + std::ofstream g_file_stream; + std::ostream *g_console_stream = &std::cout; + bool g_use_file = false; + bool g_use_console = true; + std::string g_time_format = "%d/%m/%Y__%H:%M:%S"; + + std::string get_current_timestamp() { - static unsigned int s_initCounter; - static log_level s_logLevel; - static std::string s_defaultSource; - static std::mutex s_mutex; - static std::string s_filename; - static std::ofstream s_fileStream; - static std::ostream *s_consoleStream; - static bool s_useFile; - static bool s_useConsole; - static std::string s_timeFormat; - - static std::string getCurrentTimestamp(); - static std::string getLogLevelAsString(log_level level); - static void writeToOutputs(const std::string &formattedMessage, - log_level level = log_level::info, - bool flush_ = true); - static void log(log_level level, const std::string &message, const std::string &source, bool flush_); - - public: - static void initialize(log_level level = log_level::info, - const std::string &default_source = "", - bool enable_console = true, - bool enable_file = false, - const std::string &filename = "logcoe.log"); - static void shutdown(); - - static void setLogLevel(log_level level); - static void setConsoleOutput(std::ostream &stream); - static bool setFileOutput(const std::string &filename); - static void disableConsoleOutput(); - static void disableFileOutput(); - static void setTimeFormat(const std::string &format); - - static bool isInitialized(); - static log_level getLogLevel(); - - static void debug(const std::string &message, const std::string &source = "", bool flush_ = true); - static void info(const std::string &message, const std::string &source = "", bool flush_ = true); - static void warning(const std::string &message, const std::string &source = "", bool flush_ = true); - static void error(const std::string &message, const std::string &source = "", bool flush_ = true); - static void flush(); - }; - - unsigned int LoggerImpl::s_initCounter = 0; - log_level LoggerImpl::s_logLevel = log_level::info; - std::string LoggerImpl::s_defaultSource = ""; - std::mutex LoggerImpl::s_mutex; - std::string LoggerImpl::s_filename = "logcoe.log"; - std::ofstream LoggerImpl::s_fileStream; - std::ostream *LoggerImpl::s_consoleStream = &std::cout; - bool LoggerImpl::s_useFile = false; - bool LoggerImpl::s_useConsole = true; - std::string LoggerImpl::s_timeFormat = "%d/%m/%Y__%H:%M:%S"; - - std::string LoggerImpl::getCurrentTimestamp() - { - if(s_initCounter == 0) return ""; + if(g_init_counter == 0) return ""; auto now = std::chrono::system_clock::now(); std::time_t time_t_now = std::chrono::system_clock::to_time_t(now); @@ -83,14 +38,14 @@ namespace #endif char buffer[256]; - std::strftime(buffer, sizeof(buffer), s_timeFormat.c_str(), &tm_now); + std::strftime(buffer, sizeof(buffer), g_time_format.c_str(), &tm_now); return std::string(buffer); } - std::string LoggerImpl::getLogLevelAsString(log_level level) + std::string get_log_level_as_string(log_level level) { - if(s_initCounter == 0) return ""; + if(g_init_counter == 0) return ""; switch (level) { @@ -107,179 +62,185 @@ namespace } } - void LoggerImpl::writeToOutputs(const std::string &formattedMessage, log_level level, bool flush_) + void write_to_outputs(const std::string &formatted_message, log_level level = log_level::info, bool flush_ = true) { - if (s_initCounter == 0 || static_cast(level) < static_cast(s_logLevel)) + if (g_init_counter == 0 || static_cast(level) < static_cast(g_log_level)) return; - if (s_useConsole && s_consoleStream) + if (g_use_console && g_console_stream) { - *s_consoleStream << formattedMessage << std::endl; + *g_console_stream << formatted_message << std::endl; if (flush_) - s_consoleStream->flush(); + g_console_stream->flush(); } - if (s_useFile) + if (g_use_file) { - s_fileStream << formattedMessage << std::endl; + g_file_stream << formatted_message << std::endl; if (flush_) - s_fileStream.flush(); + g_file_stream.flush(); } } - void LoggerImpl::log(log_level level, const std::string &message, const std::string &source, bool flush_) + void log(log_level level, const std::string &message, const std::string &source, bool flush_) { - std::lock_guard lock(s_mutex); - if(s_initCounter == 0) return; + std::lock_guard lock(g_mutex); + if(g_init_counter == 0) return; - std::stringstream formattedMessage; - formattedMessage << "[" << getCurrentTimestamp() << "] "; - formattedMessage << "[" << getLogLevelAsString(level) << "]"; + std::stringstream formatted_message; + formatted_message << "[" << get_current_timestamp() << "] "; + formatted_message << "[" << get_log_level_as_string(level) << "]"; if (!source.empty()) - formattedMessage << " [" << source << "]"; - formattedMessage << ": " << message; + formatted_message << " [" << source << "]"; + formatted_message << ": " << message; - writeToOutputs(formattedMessage.str(), level, flush_); + write_to_outputs(formatted_message.str(), level, flush_); } - void LoggerImpl::initialize(log_level level, const std::string &default_source, bool enable_console, bool enable_file, const std::string &filename) + void initialize(log_level level = log_level::info, + const std::string &default_source = "", + bool enable_console = true, + bool enable_file = false, + const std::string &filename = "logcoe.log") { - std::lock_guard lock(s_mutex); - if(s_initCounter++ > 0) - return writeToOutputs("[logcoe] Already initialized, ignoring new configurations"); + std::lock_guard lock(g_mutex); + if(g_init_counter++ > 0) + return write_to_outputs("[logcoe] Already initialized, ignoring new configurations"); - s_logLevel = level; - s_defaultSource = default_source; - s_useConsole = enable_console; - if (s_useConsole && !s_consoleStream) - s_consoleStream = &std::cout; - s_useFile = enable_file; + g_log_level = level; + g_default_source = default_source; + g_use_console = enable_console; + if (g_use_console && !g_console_stream) + g_console_stream = &std::cout; + g_use_file = enable_file; - if (filename != s_filename) - s_filename = filename; + if (filename != g_filename) + g_filename = filename; - if (s_filename == "logcoe.log") - s_filename = "logcoe_" + getCurrentTimestamp() + ".log"; + if (g_filename == "logcoe.log") + g_filename = "logcoe_" + get_current_timestamp() + ".log"; - if (s_useFile && !filename.empty()) + if (g_use_file && !filename.empty()) { - if (s_fileStream.is_open()) - s_fileStream.close(); + if (g_file_stream.is_open()) + g_file_stream.close(); - std::filesystem::path filepath(s_filename); + std::filesystem::path filepath(g_filename); if (filepath.has_parent_path() && !std::filesystem::exists(filepath.parent_path())) std::filesystem::create_directories(filepath.parent_path()); - + if (std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath)) std::filesystem::remove(filepath); - s_fileStream.open(s_filename); - if (!s_fileStream.is_open()) + g_file_stream.open(g_filename); + if (!g_file_stream.is_open()) { - writeToOutputs("[logcoe] ERROR: Failed to open log file: " + s_filename); - s_useFile = false; + write_to_outputs("[logcoe] ERROR: Failed to open log file: " + g_filename); + g_use_file = false; } } - writeToOutputs("[logcoe] Initialized, log level: " + getLogLevelAsString(s_logLevel)); + write_to_outputs("[logcoe] Initialized, log level: " + get_log_level_as_string(g_log_level)); } - void LoggerImpl::shutdown() + void flush(); + + void shutdown() { - std::lock_guard lock(s_mutex); - if (--s_initCounter > 0) return; + std::lock_guard lock(g_mutex); + if (--g_init_counter > 0) return; - std::string shutdownMessage = "[logcoe] shutting down"; - writeToOutputs(shutdownMessage); + std::string shutdown_message = "[logcoe] shutting down"; + write_to_outputs(shutdown_message); flush(); - if (s_fileStream.is_open()) - s_fileStream.close(); - - s_consoleStream = nullptr; - s_useConsole = false; - s_useFile = false; - s_logLevel = log_level::none; - s_filename = "logcoe.log"; - s_initCounter = 0; + if (g_file_stream.is_open()) + g_file_stream.close(); + + g_console_stream = nullptr; + g_use_console = false; + g_use_file = false; + g_log_level = log_level::none; + g_filename = "logcoe.log"; + g_init_counter = 0; } - void LoggerImpl::setLogLevel(log_level level) + void set_log_level(log_level level) { - std::lock_guard lock(s_mutex); - if(s_initCounter == 0) return; + std::lock_guard lock(g_mutex); + if(g_init_counter == 0) return; - s_logLevel = level; + g_log_level = level; } - void LoggerImpl::setConsoleOutput(std::ostream &stream) + void set_console_output(std::ostream &stream) { - std::lock_guard lock(s_mutex); - if(s_initCounter == 0) return; + std::lock_guard lock(g_mutex); + if(g_init_counter == 0) return; - if (s_useConsole && s_consoleStream) - s_consoleStream->flush(); - s_consoleStream = &stream; - s_useConsole = true; + if (g_use_console && g_console_stream) + g_console_stream->flush(); + g_console_stream = &stream; + g_use_console = true; } - bool LoggerImpl::setFileOutput(const std::string &filename) + bool set_file_output(const std::string &filename) { - std::lock_guard lock(s_mutex); - if(s_initCounter == 0) return false; + std::lock_guard lock(g_mutex); + if(g_init_counter == 0) return false; - if (s_fileStream.is_open()) + if (g_file_stream.is_open()) { - if (s_useFile) - s_fileStream.flush(); - s_fileStream.close(); + if (g_use_file) + g_file_stream.flush(); + g_file_stream.close(); } - s_filename = filename.empty() ? "logcoe_" + getCurrentTimestamp() + ".log" : filename; - s_useFile = true; + g_filename = filename.empty() ? "logcoe_" + get_current_timestamp() + ".log" : filename; + g_use_file = true; - s_fileStream.open(s_filename); - if (!s_fileStream.is_open()) + g_file_stream.open(g_filename); + if (!g_file_stream.is_open()) { - writeToOutputs("[logcoe] ERROR: Failed to open log file: " + s_filename); - s_useFile = false; + write_to_outputs("[logcoe] ERROR: Failed to open log file: " + g_filename); + g_use_file = false; } - return s_useFile; + return g_use_file; } - void LoggerImpl::disableConsoleOutput() + void disable_console_output() { - std::lock_guard lock(s_mutex); - if(s_initCounter == 0) return; + std::lock_guard lock(g_mutex); + if(g_init_counter == 0) return; - if (s_useConsole && s_consoleStream) - s_consoleStream->flush(); - s_consoleStream = nullptr; - s_useConsole = false; + if (g_use_console && g_console_stream) + g_console_stream->flush(); + g_console_stream = nullptr; + g_use_console = false; } - void LoggerImpl::disableFileOutput() + void disable_file_output() { - std::lock_guard lock(s_mutex); - if(s_initCounter == 0) return; + std::lock_guard lock(g_mutex); + if(g_init_counter == 0) return; - if (s_fileStream.is_open()) + if (g_file_stream.is_open()) { - if (s_useFile) - s_fileStream.flush(); - s_fileStream.close(); + if (g_use_file) + g_file_stream.flush(); + g_file_stream.close(); } - s_filename = "logcoe.log"; - s_useFile = false; + g_filename = "logcoe.log"; + g_use_file = false; } - void LoggerImpl::setTimeFormat(const std::string &format) + void set_time_format(const std::string &format) { - std::lock_guard lock(s_mutex); - if(s_initCounter == 0) return; + std::lock_guard lock(g_mutex); + if(g_init_counter == 0) return; try { @@ -296,61 +257,61 @@ namespace std::size_t result = std::strftime(buffer, sizeof(buffer), format.c_str(), &tm_now); if (result == 0) { - writeToOutputs("[logcoe] ERROR: Invalid time format provided: \"" + format + "\". Keeping the current format"); + write_to_outputs("[logcoe] ERROR: Invalid time format provided: \"" + format + "\". Keeping the current format"); return; } - s_timeFormat = format; + g_time_format = format; } catch (const std::exception &e) { std::stringstream message; message << "[logcoe] ERROR: Exception while validating time format: " << e.what(); - writeToOutputs(message.str()); + write_to_outputs(message.str()); } } - bool LoggerImpl::isInitialized() + bool is_initialized() { - std::lock_guard lock(s_mutex); + std::lock_guard lock(g_mutex); - return s_initCounter > 0; + return g_init_counter > 0; } - log_level LoggerImpl::getLogLevel() + log_level get_log_level() { - std::lock_guard lock(s_mutex); + std::lock_guard lock(g_mutex); - return s_logLevel; + return g_log_level; } - void LoggerImpl::debug(const std::string &message, const std::string &source, bool flush_) + void debug(const std::string &message, const std::string &source = "", bool flush_ = true) { - log(log_level::debug, message, source.empty() ? s_defaultSource : source, flush_); + log(log_level::debug, message, source.empty() ? g_default_source : source, flush_); } - void LoggerImpl::info(const std::string &message, const std::string &source, bool flush_) + void info(const std::string &message, const std::string &source = "", bool flush_ = true) { - log(log_level::info, message, source.empty() ? s_defaultSource : source, flush_); + log(log_level::info, message, source.empty() ? g_default_source : source, flush_); } - void LoggerImpl::warning(const std::string &message, const std::string &source, bool flush_) + void warning(const std::string &message, const std::string &source = "", bool flush_ = true) { - log(log_level::warning, message, source.empty() ? s_defaultSource : source, flush_); + log(log_level::warning, message, source.empty() ? g_default_source : source, flush_); } - void LoggerImpl::error(const std::string &message, const std::string &source, bool flush_) + void error(const std::string &message, const std::string &source = "", bool flush_ = true) { - log(log_level::error, message, source.empty() ? s_defaultSource : source, flush_); + log(log_level::error, message, source.empty() ? g_default_source : source, flush_); } - void LoggerImpl::flush() + void flush() { - if(s_initCounter == 0) return; - if (s_useConsole && s_consoleStream) - s_consoleStream->flush(); - if (s_useFile && s_fileStream.is_open()) - s_fileStream.flush(); + if(g_init_counter == 0) return; + if (g_use_console && g_console_stream) + g_console_stream->flush(); + if (g_use_file && g_file_stream.is_open()) + g_file_stream.flush(); } } #endif @@ -379,25 +340,25 @@ namespace logcoe void flush() { } #else void initialize(log_level level, const std::string &default_source, bool enable_console, - bool enable_file, const std::string &filename) { LoggerImpl::initialize(level, default_source, enable_console, enable_file, filename); } + bool enable_file, const std::string &filename) { ::initialize(level, default_source, enable_console, enable_file, filename); } - void shutdown() { LoggerImpl::shutdown(); } + void shutdown() { ::shutdown(); } - void set_log_level(log_level level) { LoggerImpl::setLogLevel(level); } - void set_console_output(std::ostream &stream) { LoggerImpl::setConsoleOutput(stream); } - bool set_file_output(const std::string &filename) { return LoggerImpl::setFileOutput(filename); } - void disable_console_output() { LoggerImpl::disableConsoleOutput(); } - void disable_file_output() { LoggerImpl::disableFileOutput(); } - void set_time_format(const std::string &format) { LoggerImpl::setTimeFormat(format); } + void set_log_level(log_level level) { ::set_log_level(level); } + void set_console_output(std::ostream &stream) { ::set_console_output(stream); } + bool set_file_output(const std::string &filename) { return ::set_file_output(filename); } + void disable_console_output() { ::disable_console_output(); } + void disable_file_output() { ::disable_file_output(); } + void set_time_format(const std::string &format) { ::set_time_format(format); } - bool is_initialized() { return LoggerImpl::isInitialized(); } - log_level get_log_level() { return LoggerImpl::getLogLevel(); } + bool is_initialized() { return ::is_initialized(); } + log_level get_log_level() { return ::get_log_level(); } - void debug(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::debug(message, source, flush_); } - void info(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::info(message, source, flush_); } - void warning(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::warning(message, source, flush_); } - void error(const std::string &message, const std::string &source, bool flush_) { LoggerImpl::error(message, source, flush_); } - void flush() { LoggerImpl::flush(); } + void debug(const std::string &message, const std::string &source, bool flush_) { ::debug(message, source, flush_); } + void info(const std::string &message, const std::string &source, bool flush_) { ::info(message, source, flush_); } + void warning(const std::string &message, const std::string &source, bool flush_) { ::warning(message, source, flush_); } + void error(const std::string &message, const std::string &source, bool flush_) { ::error(message, source, flush_); } + void flush() { ::flush(); } #endif } // namespace logcoe \ No newline at end of file From c98a78a4b8da979ad2357594061879d62a198876 Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 29 Sep 2026 15:13:45 +0300 Subject: [PATCH 4/9] Update tests to renamed API --- tests/logcoe_strip_test.cpp | 28 +++++++-------- tests/logcoe_test.cpp | 70 ++++++++++++++++++------------------ tests/logcoe_thread_test.cpp | 26 +++++++------- 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/tests/logcoe_strip_test.cpp b/tests/logcoe_strip_test.cpp index 979a746..749287f 100644 --- a/tests/logcoe_strip_test.cpp +++ b/tests/logcoe_strip_test.cpp @@ -14,12 +14,12 @@ class LogcoeStripTest : public ::testing::Test void SetUp() override { testFilename = "test_logfile_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count()) + ".log"; - while(logcoe::isInitialized()) { logcoe::shutdown(); } + while(logcoe::is_initialized()) { logcoe::shutdown(); } } void TearDown() override { - while(logcoe::isInitialized()) { logcoe::shutdown(); } + while(logcoe::is_initialized()) { logcoe::shutdown(); } if (std::filesystem::exists(testFilename)) std::filesystem::remove(testFilename); } @@ -27,26 +27,26 @@ class LogcoeStripTest : public ::testing::Test TEST_F(LogcoeStripTest, InitializeAndStateQueries) { - logcoe::initialize(logcoe::LogLevel::INFO); + logcoe::initialize(logcoe::log_level::info); { - EXPECT_FALSE(logcoe::isInitialized()); + EXPECT_FALSE(logcoe::is_initialized()); } { - EXPECT_EQ(logcoe::getLogLevel(), logcoe::LogLevel::NONE); + EXPECT_EQ(logcoe::get_log_level(), logcoe::log_level::none); } { - logcoe::setLogLevel(logcoe::LogLevel::DEBUG); - EXPECT_EQ(logcoe::getLogLevel(), logcoe::LogLevel::NONE); + logcoe::set_log_level(logcoe::log_level::debug); + EXPECT_EQ(logcoe::get_log_level(), logcoe::log_level::none); } } TEST_F(LogcoeStripTest, ConsoleOutput) { logcoe::initialize(); - logcoe::setConsoleOutput(testStream); + logcoe::set_console_output(testStream); { logcoe::debug("Debug message"); @@ -58,7 +58,7 @@ TEST_F(LogcoeStripTest, ConsoleOutput) } { - logcoe::disableConsoleOutput(); + logcoe::disable_console_output(); EXPECT_TRUE(testStream.str().empty()); } } @@ -68,7 +68,7 @@ TEST_F(LogcoeStripTest, FileOutput) logcoe::initialize(); { - bool result = logcoe::setFileOutput(testFilename); + bool result = logcoe::set_file_output(testFilename); EXPECT_FALSE(result); } @@ -77,7 +77,7 @@ TEST_F(LogcoeStripTest, FileOutput) } { - logcoe::disableFileOutput(); + logcoe::disable_file_output(); EXPECT_FALSE(std::filesystem::exists(testFilename)); } } @@ -87,11 +87,11 @@ TEST_F(LogcoeStripTest, TimeFormat) logcoe::initialize(); { - EXPECT_NO_THROW(logcoe::setTimeFormat("bogus")); + EXPECT_NO_THROW(logcoe::set_time_format("bogus")); } { - EXPECT_NO_THROW(logcoe::setTimeFormat("%H:%M:%S")); + EXPECT_NO_THROW(logcoe::set_time_format("%H:%M:%S")); } } @@ -108,7 +108,7 @@ TEST_F(LogcoeStripTest, Lifecycle) { logcoe::initialize(); logcoe::shutdown(); - logcoe::initialize(logcoe::LogLevel::DEBUG, "", true, true, testFilename); + logcoe::initialize(logcoe::log_level::debug, "", true, true, testFilename); logcoe::shutdown(); EXPECT_FALSE(std::filesystem::exists(testFilename)); diff --git a/tests/logcoe_test.cpp b/tests/logcoe_test.cpp index 79bee13..88abd6d 100644 --- a/tests/logcoe_test.cpp +++ b/tests/logcoe_test.cpp @@ -16,12 +16,12 @@ class LogcoeTest : public ::testing::Test { testFilename = "test_logfile_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count()) + ".log"; - while(logcoe::isInitialized()) { logcoe::shutdown(); } + while(logcoe::is_initialized()) { logcoe::shutdown(); } } void TearDown() override { - while(logcoe::isInitialized()) { logcoe::shutdown(); } + while(logcoe::is_initialized()) { logcoe::shutdown(); } if (std::filesystem::exists(testFilename)) std::filesystem::remove(testFilename); @@ -38,22 +38,22 @@ class LogcoeTest : public ::testing::Test return buffer.str(); } - bool matchesLogPattern(const std::string &text, logcoe::LogLevel level, + bool matchesLogPattern(const std::string &text, logcoe::log_level level, const std::string &message, const std::string &source = "") { std::string levelStr; switch (level) { - case logcoe::LogLevel::DEBUG: + case logcoe::log_level::debug: levelStr = "DEBUG"; break; - case logcoe::LogLevel::INFO: + case logcoe::log_level::info: levelStr = "INFO"; break; - case logcoe::LogLevel::WARNING: + case logcoe::log_level::warning: levelStr = "WARNING"; break; - case logcoe::LogLevel::ERROR: + case logcoe::log_level::error: levelStr = "ERROR"; break; default: @@ -77,29 +77,29 @@ TEST_F(LogcoeTest, DefaultInitialization) { logcoe::initialize(); - EXPECT_EQ(logcoe::getLogLevel(), logcoe::LogLevel::DEBUG); + EXPECT_EQ(logcoe::get_log_level(), logcoe::log_level::debug); logcoe::info("Test info message"); } TEST_F(LogcoeTest, CustomInitialization) { - logcoe::initialize(logcoe::LogLevel::INFO, "", true, true, testFilename); + logcoe::initialize(logcoe::log_level::info, "", true, true, testFilename); - EXPECT_EQ(logcoe::getLogLevel(), logcoe::LogLevel::INFO); + EXPECT_EQ(logcoe::get_log_level(), logcoe::log_level::info); logcoe::info("Test debug message"); EXPECT_TRUE(std::filesystem::exists(testFilename)); std::string fileContent = readLogFile(testFilename); - EXPECT_TRUE(matchesLogPattern(fileContent, logcoe::LogLevel::INFO, "Test debug message")); + EXPECT_TRUE(matchesLogPattern(fileContent, logcoe::log_level::info, "Test debug message")); } TEST_F(LogcoeTest, LogLevelFiltering) { - logcoe::initialize(logcoe::LogLevel::WARNING); - logcoe::setConsoleOutput(testStream); + logcoe::initialize(logcoe::log_level::warning); + logcoe::set_console_output(testStream); logcoe::debug("Debug message"); logcoe::info("Info message"); @@ -109,83 +109,83 @@ TEST_F(LogcoeTest, LogLevelFiltering) std::string output = testStream.str(); - EXPECT_FALSE(matchesLogPattern(output, logcoe::LogLevel::DEBUG, "Debug message")); - EXPECT_FALSE(matchesLogPattern(output, logcoe::LogLevel::INFO, "Info message")); + EXPECT_FALSE(matchesLogPattern(output, logcoe::log_level::debug, "Debug message")); + EXPECT_FALSE(matchesLogPattern(output, logcoe::log_level::info, "Info message")); - EXPECT_TRUE(matchesLogPattern(output, logcoe::LogLevel::WARNING, "Warning message")); - EXPECT_TRUE(matchesLogPattern(output, logcoe::LogLevel::ERROR, "Error message")); + EXPECT_TRUE(matchesLogPattern(output, logcoe::log_level::warning, "Warning message")); + EXPECT_TRUE(matchesLogPattern(output, logcoe::log_level::error, "Error message")); } TEST_F(LogcoeTest, ChangeLogLevel) { - logcoe::initialize(logcoe::LogLevel::ERROR); - EXPECT_EQ(logcoe::getLogLevel(), logcoe::LogLevel::ERROR); + logcoe::initialize(logcoe::log_level::error); + EXPECT_EQ(logcoe::get_log_level(), logcoe::log_level::error); - logcoe::setLogLevel(logcoe::LogLevel::DEBUG); - EXPECT_EQ(logcoe::getLogLevel(), logcoe::LogLevel::DEBUG); + logcoe::set_log_level(logcoe::log_level::debug); + EXPECT_EQ(logcoe::get_log_level(), logcoe::log_level::debug); } TEST_F(LogcoeTest, ConsoleRedirection) { logcoe::initialize(); - logcoe::setConsoleOutput(testStream); + logcoe::set_console_output(testStream); logcoe::info("Test message"); std::string output = testStream.str(); - EXPECT_TRUE(matchesLogPattern(output, logcoe::LogLevel::INFO, "Test message")); + EXPECT_TRUE(matchesLogPattern(output, logcoe::log_level::info, "Test message")); } TEST_F(LogcoeTest, FileOutput) { logcoe::initialize(); - EXPECT_TRUE(logcoe::setFileOutput(testFilename)); + EXPECT_TRUE(logcoe::set_file_output(testFilename)); logcoe::info("File test message"); std::string fileContent = readLogFile(testFilename); - EXPECT_TRUE(matchesLogPattern(fileContent, logcoe::LogLevel::INFO, "File test message")); + EXPECT_TRUE(matchesLogPattern(fileContent, logcoe::log_level::info, "File test message")); - logcoe::disableFileOutput(); + logcoe::disable_file_output(); logcoe::info("This shouldn't be in the file"); fileContent = readLogFile(testFilename); - EXPECT_FALSE(matchesLogPattern(fileContent, logcoe::LogLevel::INFO, "This shouldn't be in the file")); + EXPECT_FALSE(matchesLogPattern(fileContent, logcoe::log_level::info, "This shouldn't be in the file")); } TEST_F(LogcoeTest, DisableConsole) { logcoe::initialize(); - logcoe::setConsoleOutput(testStream); + logcoe::set_console_output(testStream); logcoe::info("Before disable"); - logcoe::disableConsoleOutput(); + logcoe::disable_console_output(); logcoe::info("After disable"); std::string output = testStream.str(); - EXPECT_TRUE(matchesLogPattern(output, logcoe::LogLevel::INFO, "Before disable")); - EXPECT_FALSE(matchesLogPattern(output, logcoe::LogLevel::INFO, "After disable")); + EXPECT_TRUE(matchesLogPattern(output, logcoe::log_level::info, "Before disable")); + EXPECT_FALSE(matchesLogPattern(output, logcoe::log_level::info, "After disable")); } TEST_F(LogcoeTest, SourceField) { logcoe::initialize(); - logcoe::setConsoleOutput(testStream); + logcoe::set_console_output(testStream); logcoe::info("Message with source", "TestSource"); std::string output = testStream.str(); - EXPECT_TRUE(matchesLogPattern(output, logcoe::LogLevel::INFO, "Message with source", "TestSource")); + EXPECT_TRUE(matchesLogPattern(output, logcoe::log_level::info, "Message with source", "TestSource")); } TEST_F(LogcoeTest, TimeFormat) { logcoe::initialize(); - logcoe::setConsoleOutput(testStream); + logcoe::set_console_output(testStream); - logcoe::setTimeFormat("%H:%M:%S"); + logcoe::set_time_format("%H:%M:%S"); logcoe::info("Custom time format"); diff --git a/tests/logcoe_thread_test.cpp b/tests/logcoe_thread_test.cpp index 0f94513..0bce106 100644 --- a/tests/logcoe_thread_test.cpp +++ b/tests/logcoe_thread_test.cpp @@ -21,12 +21,12 @@ class LogcoeThreadTest : public ::testing::Test { testFilename = "thread_test_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count()) + ".log"; - while(logcoe::isInitialized()) { logcoe::shutdown(); } + while(logcoe::is_initialized()) { logcoe::shutdown(); } } void TearDown() override { - while(logcoe::isInitialized()) { logcoe::shutdown(); } + while(logcoe::is_initialized()) { logcoe::shutdown(); } if (std::filesystem::exists(testFilename)) std::filesystem::remove(testFilename); @@ -68,7 +68,7 @@ class LogcoeThreadTest : public ::testing::Test TEST_F(LogcoeThreadTest, ConcurrentFileLogging) { - logcoe::initialize(logcoe::LogLevel::DEBUG, "", false, true, testFilename); + logcoe::initialize(logcoe::log_level::debug, "", false, true, testFilename); std::vector threads; std::atomic thread_id_counter(0); @@ -114,8 +114,8 @@ TEST_F(LogcoeThreadTest, ConcurrentFileLogging) TEST_F(LogcoeThreadTest, ConcurrentConsoleOutput) { - logcoe::initialize(logcoe::LogLevel::DEBUG, "", true, false); - logcoe::setConsoleOutput(testStream); + logcoe::initialize(logcoe::log_level::debug, "", true, false); + logcoe::set_console_output(testStream); std::vector threads; std::atomic thread_id_counter(0); @@ -160,7 +160,7 @@ TEST_F(LogcoeThreadTest, ConcurrentConsoleOutput) TEST_F(LogcoeThreadTest, ConcurrentLogLevelChange) { - logcoe::initialize(logcoe::LogLevel::INFO, "", false, true, testFilename); + logcoe::initialize(logcoe::log_level::info, "", false, true, testFilename); std::vector threads; std::atomic start_flag(false); @@ -174,11 +174,11 @@ TEST_F(LogcoeThreadTest, ConcurrentLogLevelChange) for (int i = 0; i < 5; i++) { - logcoe::setLogLevel(logcoe::LogLevel::DEBUG); + logcoe::set_log_level(logcoe::log_level::debug); std::this_thread::sleep_for(std::chrono::milliseconds(20)); - logcoe::setLogLevel(logcoe::LogLevel::WARNING); + logcoe::set_log_level(logcoe::log_level::warning); std::this_thread::sleep_for(std::chrono::milliseconds(20)); - logcoe::setLogLevel(logcoe::LogLevel::INFO); + logcoe::set_log_level(logcoe::log_level::info); std::this_thread::sleep_for(std::chrono::milliseconds(20)); } }); @@ -249,17 +249,17 @@ TEST_F(LogcoeThreadTest, ConcurrentOutputConfigChange) for (int i = 0; i < 5; i++) { - logcoe::setFileOutput(testFilename); + logcoe::set_file_output(testFilename); std::this_thread::sleep_for(std::chrono::milliseconds(20)); - logcoe::disableFileOutput(); + logcoe::disable_file_output(); std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::stringstream temp; - logcoe::setConsoleOutput(temp); + logcoe::set_console_output(temp); std::this_thread::sleep_for(std::chrono::milliseconds(20)); - logcoe::setConsoleOutput(std::cout); + logcoe::set_console_output(std::cout); std::this_thread::sleep_for(std::chrono::milliseconds(20)); } }); From 54cabb4c97389120db212c64991728bfd747baf6 Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 29 Sep 2026 15:50:19 +0300 Subject: [PATCH 5/9] Update docs --- README.md | 52 ++++++++++++++++++++++---------------------- docs/ARCHITECTURE.md | 52 ++++++++++++++++++++++---------------------- docs/CONTRIBUTING.md | 18 +++++++-------- src/logcoe.cpp | 16 +++++++------- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 2a9a548..da90d5a 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ target_link_libraries(your_target PRIVATE logcoe) int main() { // Initialize with INFO level, no default source (empty string), console enabled, file disabled // logs will be printed as [timestamp] [log_level]: - logcoe::initialize(logcoe::LogLevel::INFO, std::string{}, true, false); + logcoe::initialize(logcoe::log_level::info, std::string{}, true, false); logcoe::info("Application started"); logcoe::warning("This is a warning message"); @@ -67,10 +67,10 @@ int main() { int main() { // Enable both console and file output with DEBUG level and default source as logcoe // logs will be printed as [timestamp] [log_level] [logcoe]: - logcoe::initialize(logcoe::LogLevel::DEBUG, "logcoe", true, true, "app.log"); + logcoe::initialize(logcoe::log_level::debug, "logcoe", true, true, "app.log"); // Customize time format - logcoe::setTimeFormat("%H:%M:%S"); + logcoe::set_time_format("%H:%M:%S"); // Log with source information logcoe::debug("Debugging network connection", "NetworkModule"); @@ -78,10 +78,10 @@ int main() { // Redirect console to custom stream std::ofstream customLog("custom.log"); - logcoe::setConsoleOutput(customLog); + logcoe::set_console_output(customLog); // Change log level at runtime - logcoe::setLogLevel(logcoe::LogLevel::WARNING); + logcoe::set_log_level(logcoe::log_level::warning); logcoe::shutdown(); return 0; @@ -108,11 +108,11 @@ logcoe::initialize(); // Full configuration logcoe::initialize( - logcoe::LogLevel::DEBUG, // Log level - "logcoe", // Default source - true, // Enable console - true, // Enable file - "application.log" // Filename + logcoe::log_level::debug, // Log level + "logcoe", // Default source + true, // Enable console + true, // Enable file + "application.log" // Filename ); // shutdown @@ -122,17 +122,17 @@ logcoe::shutdown(); ### Configuration ```cpp // Runtime log level changes -logcoe::setLogLevel(logcoe::LogLevel::WARNING); -LogLevel current = logcoe::getLogLevel(); +logcoe::set_log_level(logcoe::log_level::warning); +log_level current = logcoe::get_log_level(); // Output configuration -logcoe::setFileOutput("new_logfile.log"); -logcoe::disableFileOutput(); -logcoe::setConsoleOutput(std::cerr); -logcoe::disableConsoleOutput(); +logcoe::set_file_output("new_logfile.log"); +logcoe::disable_file_output(); +logcoe::set_console_output(std::cerr); +logcoe::disable_console_output(); // Time formatting (strftime compatible) -logcoe::setTimeFormat("%Y-%m-%d %H:%M:%S"); +logcoe::set_time_format("%Y-%m-%d %H:%M:%S"); ``` ### Logging @@ -155,11 +155,11 @@ logcoe::flush(); // Flush all pending messages | Level | Value | Description | |-------|-------|-------------| -| `DEBUG` | 0 | Detailed diagnostic information | -| `INFO` | 1 | General application information | -| `WARNING` | 2 | Warning conditions that should be noted | -| `ERROR` | 3 | Error conditions that affect functionality | -| `NONE` | 4 | Disable all logging | +| `debug` | 0 | Detailed diagnostic information | +| `info` | 1 | General application information | +| `warning` | 2 | Warning conditions that should be noted | +| `error` | 3 | Error conditions that affect functionality | +| `none` | 4 | Disable all logging | ## Thread Safety @@ -176,7 +176,7 @@ void worker_thread(int id) { } int main() { - logcoe::initialize(logcoe::LogLevel::INFO, std::string{}, false, true, "concurrent.log"); + logcoe::initialize(logcoe::log_level::info, std::string{}, false, true, "concurrent.log"); std::vector workers; for (int i = 0; i < 10; ++i) { @@ -211,9 +211,9 @@ time. Every call site keeps working with zero code changes, but none of the logg or file I/O gets compiled in: - `initialize`, `debug`/`info`/`warning`/`error`, `flush`, `shutdown`, and the setters do nothing. -- `isInitialized()` returns `false`. -- `getLogLevel()` returns `LogLevel::NONE`. -- `setFileOutput(...)` returns `false` and never creates a file. +- `is_initialized()` returns `false`. +- `get_log_level()` returns `log_level::none`. +- `set_file_output(...)` returns `false` and never creates a file. No opt-in macro or CMake option needed, it's automatic whenever `NDEBUG` is defined. That includes `RelWithDebInfo` and `MinSizeRel`, since CMake defines `NDEBUG` for those build types too, not just diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 48885de..b574325 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -2,7 +2,7 @@ ## Overview -logcoe is designed as a lightweight, thread-safe logging library that provides flexible output management with minimal performance overhead. The architecture follows a singleton pattern with internal implementation hiding for API stability. +logcoe is designed as a lightweight, thread-safe logging library that provides flexible output management with minimal performance overhead. The public API hides all implementation details through an anonymous namespace containing free functions and static state, maintaining API stability across changes. ## Component Architecture @@ -18,8 +18,8 @@ logcoe is designed as a lightweight, thread-safe logging library that provides f └──────────────────┬──────────────────┘ │ ┌──────────────────▼──────────────────┐ - │ LoggerImpl │ - │ (Internal Implementation) │ + │ Anonymous Namespace (Internal) │ + │ (Free Functions & State) │ │ │ │ ┌─────────────┬─────────────────┐ │ │ │ Mutex │ Output Streams │ │ @@ -41,33 +41,33 @@ logcoe is designed as a lightweight, thread-safe logging library that provides f - Simple function-based API - No exposed implementation details - Header-only public interface - - All functions forward to LoggerImpl + - All functions forward to anonymous-namespace implementations -### LoggerImpl (Internal Implementation) +### Internal Implementation (Anonymous Namespace) - **File**: `src/logcoe.cpp` (anonymous namespace) - **Purpose**: Contains all logging logic and state management -- **Design Pattern**: Singleton with static members +- **Design**: Free functions with implicit internal linkage through namespace scope #### Thread Safety Manager ```cpp -static std::mutex s_mutex; +std::mutex g_mutex; ``` -- Ensures thread-safe access to all static members and operations +- Ensures thread-safe access to all state variables and operations #### State Management ```cpp -static LogLevel s_logLevel; -static bool s_useFile; -static bool s_useConsole; -static std::string s_timeFormat; +log_level g_log_level; +bool g_use_file; +bool g_use_console; +std::string g_time_format; ``` -- Maintains current logger configuration, Can be changed at runtime +- Maintains current logger configuration, can be changed at runtime #### Output Stream Management ```cpp -static std::string s_filename; -static std::ofstream s_fileStream; -static std::ostream* s_consoleStream; +std::string g_filename; +std::ofstream g_file_stream; +std::ostream* g_console_stream; ``` - **File Output**: Direct file stream management with automatic opening/closing - **Console Output**: Configurable output stream (default: std::cout) @@ -105,7 +105,7 @@ Generate timestamp ↓ Format message with metadata ↓ -writeToOutputs() +write_to_outputs() ↓ Write to console (if enabled) ↓ @@ -118,7 +118,7 @@ Release mutex lock ### 3. Configuration Changes ``` -setLogLevel/setFileOutput/etc() called +set_log_level/set_file_output/etc() called ↓ Acquire mutex lock ↓ @@ -133,7 +133,7 @@ Release mutex lock ## Thread Safety Implementation -- **Single Global Mutex**: `std::mutex s_mutex` +- **Single Global Mutex**: `std::mutex g_mutex` - **Lock Scope**: Every public API call acquires lock for entire duration ### Thread Safety Guarantees @@ -168,12 +168,12 @@ std::tm tm_now; ## Release Build Stripping -Under `NDEBUG`, the entire anonymous-namespace `LoggerImpl` implementation is compiled out via -`#ifndef NDEBUG`, so a Release build carries none of its code or static state. The public +Under `NDEBUG`, the entire anonymous-namespace implementation is compiled out via +`#ifndef NDEBUG`, so a Release build carries none of its code or state variables. The public `logcoe::` wrapper functions in `src/logcoe.cpp` switch to a separate `#ifdef NDEBUG` branch of no-op stubs, so every call site keeps compiling unchanged. Two stubs return a fixed value instead -of an empty body, since there's no real state left to report: `isInitialized()` always returns -`false`, and `getLogLevel()` always returns `LogLevel::NONE`. The guard is on the bare `NDEBUG` +of an empty body, since there's no real state left to report: `is_initialized()` always returns +`false`, and `get_log_level()` always returns `log_level::none`. The guard is on the bare `NDEBUG` macro, not a check for a "Release" build type specifically, so `RelWithDebInfo` and `MinSizeRel` trigger the same stripping since CMake defines `NDEBUG` for them too. @@ -193,11 +193,11 @@ trigger the same stripping since CMake defines `NDEBUG` for them too. ### Level Hierarchy ``` -DEBUG (0) < INFO (1) < WARNING (2) < ERROR (3) < NONE (4) +debug (0) < info (1) < warning (2) < error (3) < none (4) ``` ```cpp -if (static_cast(level) < static_cast(s_logLevel)) +if (static_cast(level) < static_cast(g_log_level)) return; ``` @@ -212,7 +212,7 @@ if (static_cast(level) < static_cast(s_logLevel)) ``` - **Timestamp**: Configurable format using strftime -- **Level**: String representation of LogLevel enum +- **Level**: String representation of log_level enum - **Source**: Optional component identifier - **Message**: User-provided content diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index a55f8f7..ca25e0b 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -71,21 +71,21 @@ The CI runs the following checks: ### Code Style - Follow existing naming conventions: - - `camelCase` for functions and variables - - `PascalCase` for classes and enums - - `s_` prefix for static members + - `snake_case` for functions, variables, types, and enumerators + - `g_` prefix for anonymous-namespace variables (implicit internal linkage) + - Trailing underscore for parameters that shadow another identifier in scope (e.g. `flush_` shadows the `flush()` function) - Keep lines under 120 characters - Add comments for complex logic - Use `const` and `constexpr` where appropriate ### Example Code Style ```cpp -namespace logcoe +namespace { - void setLogLevel(LogLevel level) + void set_log_level(log_level level) { - std::lock_guard lock(s_mutex); - s_logLevel = level; + std::lock_guard lock(g_mutex); + g_log_level = level; } } ``` @@ -131,7 +131,7 @@ When adding features: - Maintain backward compatibility - Add documentation comments -2. **Implement in LoggerImpl**: +2. **Implement in the anonymous namespace**: - Add to `src/logcoe.cpp` - Ensure thread safety with proper locking - Handle error cases gracefully @@ -150,7 +150,7 @@ When adding features: When modifying logcoe: -1. **Always Use Mutex**: Every function that accesses static state must lock `s_mutex` +1. **Always Use Mutex**: Every function that accesses static state must lock `g_mutex` 2. **Minimize Lock Duration**: Perform I/O operations efficiently under lock 3. **Avoid Nested Locks**: Current design uses single mutex to prevent deadlocks 4. **Test Concurrency**: Add thread safety tests for new features diff --git a/src/logcoe.cpp b/src/logcoe.cpp index 10c8427..493b6d8 100644 --- a/src/logcoe.cpp +++ b/src/logcoe.cpp @@ -12,16 +12,16 @@ using logcoe::log_level; #ifndef NDEBUG namespace { - unsigned int g_init_counter = 0; - log_level g_log_level = log_level::info; - std::string g_default_source = ""; - std::mutex g_mutex; - std::string g_filename = "logcoe.log"; + unsigned int g_init_counter = 0; + log_level g_log_level = log_level::info; + std::string g_default_source = ""; + std::mutex g_mutex; + std::string g_filename = "logcoe.log"; std::ofstream g_file_stream; std::ostream *g_console_stream = &std::cout; - bool g_use_file = false; - bool g_use_console = true; - std::string g_time_format = "%d/%m/%Y__%H:%M:%S"; + bool g_use_file = false; + bool g_use_console = true; + std::string g_time_format = "%d/%m/%Y__%H:%M:%S"; std::string get_current_timestamp() { From fa7b510a79d2aba413a46b0342cbeca246c1294f Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 29 Sep 2026 16:03:51 +0300 Subject: [PATCH 6/9] Apply simplify pass --- src/logcoe.cpp | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/logcoe.cpp b/src/logcoe.cpp index 493b6d8..18a6083 100644 --- a/src/logcoe.cpp +++ b/src/logcoe.cpp @@ -97,11 +97,11 @@ namespace write_to_outputs(formatted_message.str(), level, flush_); } - void initialize(log_level level = log_level::info, - const std::string &default_source = "", - bool enable_console = true, - bool enable_file = false, - const std::string &filename = "logcoe.log") + void initialize(log_level level, + const std::string &default_source, + bool enable_console, + bool enable_file, + const std::string &filename) { std::lock_guard lock(g_mutex); if(g_init_counter++ > 0) @@ -144,7 +144,14 @@ namespace write_to_outputs("[logcoe] Initialized, log level: " + get_log_level_as_string(g_log_level)); } - void flush(); + void flush() + { + if(g_init_counter == 0) return; + if (g_use_console && g_console_stream) + g_console_stream->flush(); + if (g_use_file && g_file_stream.is_open()) + g_file_stream.flush(); + } void shutdown() { @@ -285,34 +292,25 @@ namespace return g_log_level; } - void debug(const std::string &message, const std::string &source = "", bool flush_ = true) + void debug(const std::string &message, const std::string &source, bool flush_) { log(log_level::debug, message, source.empty() ? g_default_source : source, flush_); } - void info(const std::string &message, const std::string &source = "", bool flush_ = true) + void info(const std::string &message, const std::string &source, bool flush_) { log(log_level::info, message, source.empty() ? g_default_source : source, flush_); } - void warning(const std::string &message, const std::string &source = "", bool flush_ = true) + void warning(const std::string &message, const std::string &source, bool flush_) { log(log_level::warning, message, source.empty() ? g_default_source : source, flush_); } - void error(const std::string &message, const std::string &source = "", bool flush_ = true) + void error(const std::string &message, const std::string &source, bool flush_) { log(log_level::error, message, source.empty() ? g_default_source : source, flush_); } - - void flush() - { - if(g_init_counter == 0) return; - if (g_use_console && g_console_stream) - g_console_stream->flush(); - if (g_use_file && g_file_stream.is_open()) - g_file_stream.flush(); - } } #endif From 20c03ea511a97481acfc1b7f7e3c6c6e1330e47c Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 29 Sep 2026 19:53:51 +0300 Subject: [PATCH 7/9] Wrap Impl function in internal:: namespace --- src/logcoe.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/logcoe.cpp b/src/logcoe.cpp index 18a6083..76061c2 100644 --- a/src/logcoe.cpp +++ b/src/logcoe.cpp @@ -23,6 +23,9 @@ namespace bool g_use_console = true; std::string g_time_format = "%d/%m/%Y__%H:%M:%S"; + namespace internal + { + std::string get_current_timestamp() { if(g_init_counter == 0) return ""; @@ -311,6 +314,8 @@ namespace { log(log_level::error, message, source.empty() ? g_default_source : source, flush_); } + + } // namespace internal } #endif @@ -338,25 +343,25 @@ namespace logcoe void flush() { } #else void initialize(log_level level, const std::string &default_source, bool enable_console, - bool enable_file, const std::string &filename) { ::initialize(level, default_source, enable_console, enable_file, filename); } + bool enable_file, const std::string &filename) { internal::initialize(level, default_source, enable_console, enable_file, filename); } - void shutdown() { ::shutdown(); } + void shutdown() { internal::shutdown(); } - void set_log_level(log_level level) { ::set_log_level(level); } - void set_console_output(std::ostream &stream) { ::set_console_output(stream); } - bool set_file_output(const std::string &filename) { return ::set_file_output(filename); } - void disable_console_output() { ::disable_console_output(); } - void disable_file_output() { ::disable_file_output(); } - void set_time_format(const std::string &format) { ::set_time_format(format); } + void set_log_level(log_level level) { internal::set_log_level(level); } + void set_console_output(std::ostream &stream) { internal::set_console_output(stream); } + bool set_file_output(const std::string &filename) { return internal::set_file_output(filename); } + void disable_console_output() { internal::disable_console_output(); } + void disable_file_output() { internal::disable_file_output(); } + void set_time_format(const std::string &format) { internal::set_time_format(format); } - bool is_initialized() { return ::is_initialized(); } - log_level get_log_level() { return ::get_log_level(); } + bool is_initialized() { return internal::is_initialized(); } + log_level get_log_level() { return internal::get_log_level(); } - void debug(const std::string &message, const std::string &source, bool flush_) { ::debug(message, source, flush_); } - void info(const std::string &message, const std::string &source, bool flush_) { ::info(message, source, flush_); } - void warning(const std::string &message, const std::string &source, bool flush_) { ::warning(message, source, flush_); } - void error(const std::string &message, const std::string &source, bool flush_) { ::error(message, source, flush_); } - void flush() { ::flush(); } + void debug(const std::string &message, const std::string &source, bool flush_) { internal::debug(message, source, flush_); } + void info(const std::string &message, const std::string &source, bool flush_) { internal::info(message, source, flush_); } + void warning(const std::string &message, const std::string &source, bool flush_) { internal::warning(message, source, flush_); } + void error(const std::string &message, const std::string &source, bool flush_) { internal::error(message, source, flush_); } + void flush() { internal::flush(); } #endif } // namespace logcoe \ No newline at end of file From f0cf7a80d4f8ceaa32a05307c594af4d22b97940 Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 29 Sep 2026 22:35:26 +0300 Subject: [PATCH 8/9] Apply code review fixes --- docs/CONTRIBUTING.md | 2 +- src/logcoe.cpp | 33 +++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index ca25e0b..6ae71b8 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -73,7 +73,7 @@ The CI runs the following checks: - Follow existing naming conventions: - `snake_case` for functions, variables, types, and enumerators - `g_` prefix for anonymous-namespace variables (implicit internal linkage) - - Trailing underscore for parameters that shadow another identifier in scope (e.g. `flush_` shadows the `flush()` function) + - Trailing underscore for parameters that would otherwise shadow another identifier in scope (e.g. a `flush` parameter is renamed to `flush_` to avoid shadowing the `flush()` function) - Keep lines under 120 characters - Add comments for complex logic - Use `const` and `constexpr` where appropriate diff --git a/src/logcoe.cpp b/src/logcoe.cpp index 76061c2..8230a41 100644 --- a/src/logcoe.cpp +++ b/src/logcoe.cpp @@ -85,16 +85,26 @@ namespace } } + void flush_streams() + { + if (g_use_console && g_console_stream) + g_console_stream->flush(); + if (g_use_file && g_file_stream.is_open()) + g_file_stream.flush(); + } + void log(log_level level, const std::string &message, const std::string &source, bool flush_) { std::lock_guard lock(g_mutex); if(g_init_counter == 0) return; + const std::string &resolved_source = source.empty() ? g_default_source : source; + std::stringstream formatted_message; formatted_message << "[" << get_current_timestamp() << "] "; formatted_message << "[" << get_log_level_as_string(level) << "]"; - if (!source.empty()) - formatted_message << " [" << source << "]"; + if (!resolved_source.empty()) + formatted_message << " [" << resolved_source << "]"; formatted_message << ": " << message; write_to_outputs(formatted_message.str(), level, flush_); @@ -149,22 +159,21 @@ namespace void flush() { - if(g_init_counter == 0) return; - if (g_use_console && g_console_stream) - g_console_stream->flush(); - if (g_use_file && g_file_stream.is_open()) - g_file_stream.flush(); + std::lock_guard lock(g_mutex); + if (g_init_counter == 0) return; + flush_streams(); } void shutdown() { std::lock_guard lock(g_mutex); + if (g_init_counter == 0) return; if (--g_init_counter > 0) return; std::string shutdown_message = "[logcoe] shutting down"; write_to_outputs(shutdown_message); - flush(); + flush_streams(); if (g_file_stream.is_open()) g_file_stream.close(); @@ -297,22 +306,22 @@ namespace void debug(const std::string &message, const std::string &source, bool flush_) { - log(log_level::debug, message, source.empty() ? g_default_source : source, flush_); + log(log_level::debug, message, source, flush_); } void info(const std::string &message, const std::string &source, bool flush_) { - log(log_level::info, message, source.empty() ? g_default_source : source, flush_); + log(log_level::info, message, source, flush_); } void warning(const std::string &message, const std::string &source, bool flush_) { - log(log_level::warning, message, source.empty() ? g_default_source : source, flush_); + log(log_level::warning, message, source, flush_); } void error(const std::string &message, const std::string &source, bool flush_) { - log(log_level::error, message, source.empty() ? g_default_source : source, flush_); + log(log_level::error, message, source, flush_); } } // namespace internal From 012b1ebe2e17f279307aae413c1da563987a1a81 Mon Sep 17 00:00:00 2001 From: nircoe Date: Tue, 29 Sep 2026 22:48:08 +0300 Subject: [PATCH 9/9] Upgrade checkout version in CI --- .github/workflows/ci-linux.yml | 2 +- .github/workflows/ci-macos.yml | 2 +- .github/workflows/ci-windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index a9f381a..1f5206a 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v7 with: submodules: 'recursive' diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index e4eb86b..3a5cc8d 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v7 with: submodules: 'recursive' diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index c68ef41..1e50e44 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -36,7 +36,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v7 with: submodules: 'recursive'