diff --git a/modules/core/inc/tactile/core/debug/log/logger.hpp b/modules/core/inc/tactile/core/debug/log/logger.hpp index 0446eab414..e6c543eeb0 100644 --- a/modules/core/inc/tactile/core/debug/log/logger.hpp +++ b/modules/core/inc/tactile/core/debug/log/logger.hpp @@ -5,6 +5,7 @@ #include #include "tactile/core/api.hpp" +#include "tactile/core/container/smart_ptr.hpp" #include "tactile/core/container/string.hpp" #include "tactile/core/container/vector.hpp" #include "tactile/core/debug/log/log_level.hpp" @@ -115,7 +116,7 @@ class TACTILE_CORE_API Logger final { private: LogLevel mMinLevel {LogLevel::kInfo}; LogLevel mFlushLevel {LogLevel::kError}; - Vector mSinks; + Vector> mSinks; Maybe mReferenceInstant; [[nodiscard]] diff --git a/modules/core/inc/tactile/core/debug/log/logger_builder.hpp b/modules/core/inc/tactile/core/debug/log/logger_builder.hpp new file mode 100644 index 0000000000..0fa2eaed2a --- /dev/null +++ b/modules/core/inc/tactile/core/debug/log/logger_builder.hpp @@ -0,0 +1,85 @@ +// Copyright (C) 2023 Albin Johansson (GNU General Public License v3.0) + +#pragma once + +#include "tactile/core/api.hpp" +#include "tactile/core/debug/log/log_level.hpp" +#include "tactile/core/debug/log/logger.hpp" +#include "tactile/core/functional/maybe.hpp" +#include "tactile/core/io/filesystem.hpp" +#include "tactile/core/prelude.hpp" + +namespace tactile { + +/** + * \brief Builder class for constructing `Logger` instances. + */ +class TACTILE_CORE_API LoggerBuilder final { + public: + using Self = LoggerBuilder; + + /** + * \brief Sets the initial minimum log level of log messages. + * + * \param level the minimum log level. + * + * \return the builder instance. + */ + auto min_level(LogLevel level) -> Self&; + + /** + * \brief Sets the minimum level of messages that would trigger a flush. + * + * \param level the minimum flush log level. + * + * \return the builder instance. + */ + auto flush_on(LogLevel level) -> Self&; + + /** + * \brief Uses the time of the logger initialization as the reference timepoint. + * + * \return the builder instance. + */ + auto use_initialization_time_as_reference_instant() -> Self&; + + /** + * \brief Enables colored terminal output. + * + * \note This function only has an effect if the terminal sink is included. + * + * \return the builder instance. + */ + auto use_colored_terminal_output() -> Self&; + + /** + * \brief Includes a terminal sink with the logger. + * + * \return the builder instance. + */ + auto with_terminal_sink() -> Self&; + + /** + * \brief Includes a log file sink with the logger. + * + * \return the builder instance. + */ + auto with_file_sink(FilePath file_path) -> Self&; + + /** + * \brief Constructs the described logger. + * + * \return a logger instance. + */ + auto build() -> Logger; + + private: + LogLevel mMinLevel {LogLevel::kTrace}; + LogLevel mFlushLevel {LogLevel::kError}; + Maybe mLogFilePath; + bool mUseStartupTimeAsReferenceInstant : 1 {}; + bool mUseTerminalSink : 1 {}; + bool mUseColoredTerminalOutput : 1 {}; +}; + +} // namespace tactile diff --git a/modules/core/src/tactile/core/debug/log/logger.cpp b/modules/core/src/tactile/core/debug/log/logger.cpp index 9fd2f77c63..1106c2d4e9 100644 --- a/modules/core/src/tactile/core/debug/log/logger.cpp +++ b/modules/core/src/tactile/core/debug/log/logger.cpp @@ -13,7 +13,7 @@ namespace tactile { namespace { -constinit Logger* gLogger = nullptr; +constinit Logger* gDefaultLogger = nullptr; } // namespace @@ -44,7 +44,7 @@ void Logger::log(const LogLevel level, const auto will_flush = would_flush(level); - for (auto* sink : mSinks) { + for (const Managed& sink : mSinks) { sink->log(msg); if (will_flush) { @@ -71,10 +71,10 @@ void Logger::flush_on(const LogLevel level) noexcept mFlushLevel = level; } -void Logger::add_sink(ILoggerSink* sink) +void Logger::add_sink(Managed sink) { if (sink) { - mSinks.push_back(sink); + mSinks.push_back(std::move(sink)); } } @@ -129,12 +129,12 @@ auto Logger::_to_elapsed_time(const SteadyClockInstant instant) const -> Microse void set_default_logger(Logger* logger) noexcept { - gLogger = logger; + gDefaultLogger = logger; } auto get_default_logger() noexcept -> Logger* { - return gLogger; + return gDefaultLogger; } } // namespace tactile diff --git a/modules/core/src/tactile/core/debug/profiler.cpp b/modules/core/src/tactile/core/debug/profiler.cpp index 5d2db8194c..0f9036dadb 100644 --- a/modules/core/src/tactile/core/debug/profiler.cpp +++ b/modules/core/src/tactile/core/debug/profiler.cpp @@ -20,7 +20,7 @@ ScopeProfiler::~ScopeProfiler() noexcept try { const auto end = SteadyClock::now(); const auto duration = duration_cast(end - mStartInstant); - TACTILE_LOG_DEBUG("[PROFILER] Scope '{}' took {}", mDescription, duration); + TACTILE_LOG_DEBUG("Scope '{}' took {}", mDescription, duration); } catch (const std::exception& ex) { TACTILE_LOG_ERROR("Scope profiler destructor threw unexpected exception: {}", diff --git a/modules/core/test/main.cpp b/modules/core/test/main.cpp index 25410469cb..02579fe838 100644 --- a/modules/core/test/main.cpp +++ b/modules/core/test/main.cpp @@ -2,8 +2,7 @@ #include -#include "tactile/core/debug/log/logger.hpp" -#include "tactile/core/debug/log/terminal_logger_sink.hpp" +#include "tactile/core/debug/log/logger_builder.hpp" #include "tactile/core/math/rng.hpp" #include "tactile/core/misc/scope_guard.hpp" @@ -11,14 +10,14 @@ using namespace tactile; auto main(int argc, char* argv[]) -> int { - Logger logger; - logger.set_reference_instant(SteadyClock::now()); - logger.set_min_level(LogLevel::kTrace); - logger.flush_on(LogLevel::kError); - - TerminalLoggerSink terminal_logger_sink; - terminal_logger_sink.use_ansi_colors(true); - logger.add_sink(&terminal_logger_sink); + auto logger = LoggerBuilder {} + .use_initialization_time_as_reference_instant() + .min_level(LogLevel::kDebug) + .flush_on(LogLevel::kError) + .with_file_sink("core_test_log.txt") + .with_terminal_sink() + .use_colored_terminal_output() + .build(); set_default_logger(&logger); const ScopeGuard logger_guard {[] { set_default_logger(nullptr); }}; diff --git a/modules/editor/test/main.cpp b/modules/editor/test/main.cpp index 68b5768daa..edb21ac35e 100644 --- a/modules/editor/test/main.cpp +++ b/modules/editor/test/main.cpp @@ -2,8 +2,25 @@ #include +#include "tactile/core/debug/log/logger_builder.hpp" +#include "tactile/core/misc/scope_guard.hpp" + +using namespace tactile; + auto main(int argc, char* argv[]) -> int { + auto logger = LoggerBuilder {} + .use_initialization_time_as_reference_instant() + .min_level(LogLevel::kDebug) + .flush_on(LogLevel::kError) + .with_file_sink("editor_test_log.txt") + .with_terminal_sink() + .use_colored_terminal_output() + .build(); + + set_default_logger(&logger); + const ScopeGuard logger_guard {[] { set_default_logger(nullptr); }}; + testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } \ No newline at end of file diff --git a/modules/main/src/tactile/main/main.cpp b/modules/main/src/tactile/main/main.cpp index 7e8b9659ea..b87a5a127b 100644 --- a/modules/main/src/tactile/main/main.cpp +++ b/modules/main/src/tactile/main/main.cpp @@ -4,9 +4,7 @@ #include // exception, set_terminate #include // current_path, create_directories -#include "tactile/core/debug/log/file_logger_sink.hpp" -#include "tactile/core/debug/log/logger.hpp" -#include "tactile/core/debug/log/terminal_logger_sink.hpp" +#include "tactile/core/debug/log/logger_builder.hpp" #include "tactile/core/debug/terminate_handler.hpp" #include "tactile/core/io/save/save_format_manager.hpp" #include "tactile/core/misc/scope_guard.hpp" @@ -30,19 +28,18 @@ auto main(const int argc, char* argv[]) -> int const auto log_dir = app_dir / "logs"; // FIXME std::filesystem::create_directories(log_dir); - tactile::FileLoggerSink file_sink {log_dir / "log.txt"}; - tactile::TerminalLoggerSink console_sink; - console_sink.use_ansi_colors(true); + auto logger = tactile::LoggerBuilder {} + .use_initialization_time_as_reference_instant() + .min_level(tactile::LogLevel::kTrace) + .flush_on(tactile::LogLevel::kError) + .with_file_sink(log_dir / "log.txt") + .with_terminal_sink() + .use_colored_terminal_output() + .build(); - tactile::Logger logger; const tactile::ScopeGuard logger_guard {[] { tactile::set_default_logger(nullptr); }}; - logger.set_reference_instant(startup_instant); - logger.set_min_level(tactile::LogLevel::kTrace); - logger.add_sink(&file_sink); - logger.add_sink(&console_sink); - tactile::set_default_logger(&logger); TACTILE_LOG_DEBUG("Initialized logger"); @@ -58,16 +55,13 @@ auto main(const int argc, char* argv[]) -> int } catch (const tactile::Error& err) { TACTILE_LOG_FATAL("Unhandled exception: {}\n{}", err.what(), err.get_trace()); - return EXIT_FAILURE; } catch (const std::exception& ex) { TACTILE_LOG_FATAL("Unhandled exception: {}", ex.what()); - return EXIT_FAILURE; } catch (...) { TACTILE_LOG_FATAL("Unhandled exception"); - return EXIT_FAILURE; } - return EXIT_SUCCESS; + return EXIT_FAILURE; } \ No newline at end of file diff --git a/modules/tmj-format/test/main.cpp b/modules/tmj-format/test/main.cpp index 68b5768daa..a9daf71b39 100644 --- a/modules/tmj-format/test/main.cpp +++ b/modules/tmj-format/test/main.cpp @@ -2,8 +2,25 @@ #include +#include "tactile/core/debug/log/logger_builder.hpp" +#include "tactile/core/misc/scope_guard.hpp" + +using namespace tactile; + auto main(int argc, char* argv[]) -> int { + auto logger = LoggerBuilder {} + .use_initialization_time_as_reference_instant() + .min_level(LogLevel::kDebug) + .flush_on(LogLevel::kError) + .with_file_sink("tmj_format_test_log.txt") + .with_terminal_sink() + .use_colored_terminal_output() + .build(); + + set_default_logger(&logger); + const ScopeGuard logger_guard {[] { set_default_logger(nullptr); }}; + testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } \ No newline at end of file