From 3df7bc037c3742e5770834b190685715b6f7fdde Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 11 Oct 2023 22:18:44 -0600 Subject: [PATCH] Adding Log to tools --- CMakeLists.txt | 2 +- cmake/unit_testing.cmake | 2 + src/tools/Log.hpp | 132 ++++++++++++++++++++++++++++++ src/tools/Log/test/CMakeLists.txt | 1 + src/tools/Log/test/Log.test.cpp | 57 +++++++++++++ 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/tools/Log.hpp create mode 100644 src/tools/Log/test/CMakeLists.txt create mode 100644 src/tools/Log/test/Log.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ef71e09..f474587 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ if( DEFINED PROJECT_NAME ) endif() project( tools - VERSION 0.1.0 + VERSION 0.2.0 LANGUAGES CXX ) diff --git a/cmake/unit_testing.cmake b/cmake/unit_testing.cmake index e1f93b4..689f045 100644 --- a/cmake/unit_testing.cmake +++ b/cmake/unit_testing.cmake @@ -25,3 +25,5 @@ endfunction() ####################################################################### # Unit testing directories ####################################################################### + +add_subdirectory( src/tools/Log/test ) diff --git a/src/tools/Log.hpp b/src/tools/Log.hpp new file mode 100644 index 0000000..521f0d2 --- /dev/null +++ b/src/tools/Log.hpp @@ -0,0 +1,132 @@ +#ifndef NJOY_TOOLS_LOG +#define NJOY_TOOLS_LOG + +// system includes + +// other includes +#include "spdlog/spdlog.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/sinks/basic_file_sink.h" + +namespace njoy { +namespace tools { + +/** + * @brief A singleton logger for njoy components + */ +class Log { + + static auto initialize_logger() { + + auto instance = spdlog::stdout_color_st( "njoy" ); + instance->set_pattern( "[%^%l%$] %v" ); + #ifndef NDEBUG + instance->set_level( spdlog::level::debug ); + #endif + return instance; + } + + static auto& logger() { + + static auto instance = initialize_logger(); + return instance; + } + + /* constructors */ + Log() {}; // private to avoid creation of Log instances + +public: + + Log( const Log& ) = delete; + void operator=( const Log& ) = delete; + + /** + * @brief Direct the logger output to the given file + */ + static void add_sink( const std::string& filename ) { + + auto sink_ptr = std::make_shared< spdlog::sinks::basic_file_sink_st >( filename ); + sink_ptr->set_pattern( "[%^%l%$] %v" ); + logger()->sinks().push_back( sink_ptr ); + } + + /** + * @brief Flush the logger + */ + static void flush() { + + logger()->flush(); + } + + /** + * @brief Print a message at the info level + * + * For example: + * + * int value = 10; + * utility::Log::info( "Some message with a value {}", value ); + */ + template< typename... Args > + static void info( Args... args ) { + + logger()->info( std::forward< Args >( args )... ); + } + + /** + * @brief Print a message at the warning level + * + * For example: + * + * int value = 10; + * utility::Log::warning( "Some message with a value {}", value ); + */ + template< typename... Args > + static void warning( Args... args ) { + + logger()->warn( std::forward< Args >( args )... ); + } + + /** + * @brief Print a message at the error level + * + * For example: + * + * int value = 10; + * utility::Log::info( "Some message with a value {}", value ); + */ + template< typename... Args > + static void error( Args... args ) { + + logger()->error( std::forward< Args >( args )... ); + } + + /** + * @brief Print a message at the debug level + * + * This only prints when NDEBUG is defined when compiling this code. + * + * For example: + * + * int value = 10; + * utility::Log::debug( "Some message with a value {}", value ); + */ + #ifdef NDEBUG + template< typename... Args > + static void debug( Args... ) {} + #else + template< typename... Args > + static void debug( Args... args ) { + + logger()->debug( std::forward< Args >( args )... ); + } + #endif +}; + +} // tools namespace + +/* type alias - for backwards compatibility reasons */ +using Log = tools::Log; + +} // njoy namespace + +#endif diff --git a/src/tools/Log/test/CMakeLists.txt b/src/tools/Log/test/CMakeLists.txt new file mode 100644 index 0000000..a58bc9e --- /dev/null +++ b/src/tools/Log/test/CMakeLists.txt @@ -0,0 +1 @@ +add_cpp_test( Log Log.test.cpp ) diff --git a/src/tools/Log/test/Log.test.cpp b/src/tools/Log/test/Log.test.cpp new file mode 100644 index 0000000..840538d --- /dev/null +++ b/src/tools/Log/test/Log.test.cpp @@ -0,0 +1,57 @@ +// include Catch2 +#include + +// what we are testing +#include "tools/Log.hpp" + +// other includes +#include +#include +#include + +// convenience typedefs +using namespace njoy::tools; + +std::string getContent( std::string filename ) { + + std::stringstream ss; + std::ifstream fs( filename, std::ifstream::in ); + ss << fs.rdbuf(); + return ss.str(); +} + +SCENARIO( "Log" ) { + + GIVEN( "a file name" ) { + + std::string filename = "output.txt"; + std::filesystem::remove( filename ); // ensure the file is not there + + WHEN( "the Log redirects to a file" ) { + + Log::add_sink( filename ); + + THEN( "the file contains the log after flushing" ) { + + Log::error( "Some error occurred" ); + Log::warning( "Some warning was issued" ); + Log::info( "Some info was printed" ); + Log::debug( "Some debug info was given" ); + Log::flush(); + + std::string content = getContent( filename ); + +#ifdef NDEBUG + CHECK( "[error] Some error occurred\n" + "[warning] Some warning was issued\n" + "[info] Some info was printed\n" == content ); +#else + CHECK( "[error] Some error occurred\n" + "[warning] Some warning was issued\n" + "[info] Some info was printed\n" + "[debug] Some debug info was given\n" == content ); +#endif + } // THEN + } // WHEN + } // GIVEN +} // SCENARIO