diff --git a/CMakeLists.txt b/CMakeLists.txt index 65bafea..940ccc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,8 @@ include_directories( include ) set( sources src/logger.cpp + src/console_appender.cpp + src/file_appender.cpp src/appender.cpp src/logger_config.cpp src/ssh.cpp diff --git a/include/fc/console_appender.hpp b/include/fc/console_appender.hpp new file mode 100644 index 0000000..371d2b9 --- /dev/null +++ b/include/fc/console_appender.hpp @@ -0,0 +1,56 @@ +#pragma once +#include +#include + +namespace fc { + class console_appender : public appender { + public: + struct color { + enum type { + red, + green, + brown, + blue, + magenta, + cyan, + white, + console_default, + }; + }; + struct stream { enum type { std_out, std_error }; }; + + struct level_color { + level_color( log_level::type l=log_level::all, + color::type c=color::console_default ) + :level(l),color(c){} + + log_level::type level; + console_appender::color::type color; + }; + + struct config { + config() + :format( "${when} ${thread} ${context} ${file}:${line} ${method} ${level}] ${message}" ), + stream(console_appender::stream::std_error),flush(true){} + + fc::string format; + console_appender::stream::type stream; + fc::vector level_colors; + bool flush; + }; + + + console_appender( const value& args ); + const char* get_color( log_level::type l )const; + virtual void log( const log_message& m ); + private: + config cfg; + color::type lc[log_level::off+1]; + }; +} // namespace fc + +#include +FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) ) +FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) ) +FC_REFLECT( fc::console_appender::level_color, (level)(color) ) +FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(flush) ) diff --git a/include/fc/file_appender.hpp b/include/fc/file_appender.hpp new file mode 100644 index 0000000..0ffae0d --- /dev/null +++ b/include/fc/file_appender.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include + +namespace fc { + +class file_appender : public appender { + public: + struct config { + config( const fc::path& p = "log.txt" ); + + fc::string format; + fc::path filename; + bool flush; + bool truncate; + }; + file_appender( const value& args ); + ~file_appender(); + virtual void log( const log_message& m ); + + private: + class impl; + fc::shared_ptr my; + }; +} // namespace fc + +#include +FC_REFLECT( fc::file_appender::config, (format)(filename)(flush)(truncate) ) diff --git a/include/fc/logger.hpp b/include/fc/logger.hpp index 75019a0..d89a086 100644 --- a/include/fc/logger.hpp +++ b/include/fc/logger.hpp @@ -22,6 +22,7 @@ namespace fc { ostring context; ostring thread; ostring fiber; + ostring host; string file; int line; string method; @@ -102,7 +103,7 @@ namespace fc { } // namespace fc #include -FC_REFLECT( fc::log_message, (when)(level)(context)(thread)(method)(file)(line)(format)(args)(meta) ) +FC_REFLECT( fc::log_message, (when)(level)(context)(thread)(fiber)(host)(method)(file)(line)(format)(args)(meta) ) FC_REFLECT_ENUM( fc::log_level::type, (all)(trace)(debug)(info)(warn)(error)(fatal)(off) ) #define fc_scope_log( LOGGER, FORMAT, ... ) \ diff --git a/include/fc/logger_config.hpp b/include/fc/logger_config.hpp index e1464b7..a089052 100644 --- a/include/fc/logger_config.hpp +++ b/include/fc/logger_config.hpp @@ -22,6 +22,8 @@ namespace fc { /// if any appenders are sepecified, then parent's appenders are not set. bool additivity; fc::vector appenders; + + logger_config& add_appender( const string& s ); }; struct logging_config { diff --git a/src/appender.cpp b/src/appender.cpp index 9f10240..71a4ea2 100644 --- a/src/appender.cpp +++ b/src/appender.cpp @@ -9,11 +9,9 @@ #include #include #include -#include +#include +#include -#ifndef WIN32 -#include -#endif namespace fc { @@ -46,101 +44,7 @@ namespace fc { get_appender_map()[name] = ap; return ap; } - - class console_appender : public appender{ - public: - struct color { - enum type { - red, - green, - brown, - blue, - magenta, - cyan, - white, - console_default, - }; - }; - struct stream { enum type { std_out, std_error }; }; - - struct level_color { - level_color( log_level::type l=log_level::all, - color::type c=color::console_default ) - :level(l),color(c){} - - log_level::type level; - console_appender::color::type color; - }; - - struct config { - config() - :format( "${when} ${thread} ${context} ${file}:${line} ${method} ${level}] ${message}" ), - stream(console_appender::stream::std_error),flush(true){} - - fc::string format; - console_appender::stream::type stream; - fc::vector level_colors; - bool flush; - }; - - config cfg; - color::type lc[log_level::off+1]; - - console_appender( const value& args ); - const char* get_color(color::type t ) { - switch( t ) { - case color::red: return CONSOLE_RED; - case color::green: return CONSOLE_GREEN; - case color::brown: return CONSOLE_BROWN; - case color::blue: return CONSOLE_BLUE; - case color::magenta: return CONSOLE_MAGENTA; - case color::cyan: return CONSOLE_CYAN; - case color::white: return CONSOLE_WHITE; - case color::console_default: - default: - return CONSOLE_DEFAULT; - } - } - const char* get_color( log_level::type l ) { - return get_color( lc[l] ); - } - - virtual void log( const log_message& m ) { - fc::string message = fc::substitute( m.format, m.args ); - fc::value lmsg(m); - - FILE* out = stream::std_error ? stderr : stdout; - fc::string fmt_str = fc::substitute( cfg.format, value(m).set( "message", message) ); - - fc::unique_lock lock(log_mutex()); - #ifndef WIN32 - if(isatty(fileno(out))) fprintf( out, "\r%s", get_color( m.level ) ); - #endif - - fprintf( out, "%s", fmt_str.c_str() ); - - #ifndef WIN32 - if(isatty(fileno(out))) fprintf( out, "\r%s", CONSOLE_DEFAULT ); - #endif - fprintf( out, "\n" ); - if( cfg.flush ) fflush( out ); - } - }; -} // namespace fc - -FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) ) -FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) ) -FC_REFLECT( fc::console_appender::level_color, (level)(color) ) -FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(flush) ) - -namespace fc { - console_appender::console_appender( const value& args ) { - cfg = fc::value_cast(args); - for( int i = 0; i < log_level::off+1; ++i ) - lc[i] = color::console_default; - for( auto itr = cfg.level_colors.begin(); itr != cfg.level_colors.end(); ++itr ) - lc[itr->level] = itr->color; - } - + static bool reg_console_appender = appender::register_appender( "console" ); + static bool reg_file_appender = appender::register_appender( "file" ); } // namespace fc diff --git a/src/console_appender.cpp b/src/console_appender.cpp new file mode 100644 index 0000000..84f5f1a --- /dev/null +++ b/src/console_appender.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif + +namespace fc { + console_appender::console_appender( const value& args ) { + cfg = fc::value_cast(args); + for( int i = 0; i < log_level::off+1; ++i ) + lc[i] = color::console_default; + for( auto itr = cfg.level_colors.begin(); itr != cfg.level_colors.end(); ++itr ) + lc[itr->level] = itr->color; + } + const char* get_console_color(console_appender::color::type t ) { + switch( t ) { + case console_appender::color::red: return CONSOLE_RED; + case console_appender::color::green: return CONSOLE_GREEN; + case console_appender::color::brown: return CONSOLE_BROWN; + case console_appender::color::blue: return CONSOLE_BLUE; + case console_appender::color::magenta: return CONSOLE_MAGENTA; + case console_appender::color::cyan: return CONSOLE_CYAN; + case console_appender::color::white: return CONSOLE_WHITE; + case console_appender::color::console_default: + default: + return CONSOLE_DEFAULT; + } + } + const char* console_appender::get_color( log_level::type l )const { + return get_console_color( lc[l] ); + } + void console_appender::log( const log_message& m ) { + fc::string message = fc::substitute( m.format, m.args ); + fc::value lmsg(m); + + FILE* out = stream::std_error ? stderr : stdout; + fc::string fmt_str = fc::substitute( cfg.format, value(m).set( "message", message) ); + + fc::unique_lock lock(log_mutex()); + #ifndef WIN32 + if(isatty(fileno(out))) fprintf( out, "\r%s", get_color( m.level ) ); + #endif + + fprintf( out, "%s", fmt_str.c_str() ); + + #ifndef WIN32 + if(isatty(fileno(out))) fprintf( out, "\r%s", CONSOLE_DEFAULT ); + #endif + fprintf( out, "\n" ); + if( cfg.flush ) fflush( out ); + } + +} diff --git a/src/file_appender.cpp b/src/file_appender.cpp new file mode 100644 index 0000000..7e9b6ad --- /dev/null +++ b/src/file_appender.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace fc { + class file_appender::impl : public fc::retainable { + public: + config cfg; + ofstream out; + boost::mutex slock; + }; + file_appender::config::config( const fc::path& p ) + :format( "${when} ${thread} ${context} ${file}:${line} ${method} ${level}] ${message}" ), + filename(p),flush(true),truncate(true){} + + file_appender::file_appender( const value& args ) + :my( new impl() ) + { + try { + my->cfg = fc::value_cast(args); + my->out.open( my->cfg.filename.string().c_str() ); + } catch ( ... ) { + elog( "%s", fc::except_str().c_str() ); + } + } + file_appender::~file_appender(){} + + void file_appender::log( const log_message& m ) + { + fc::string message = fc::substitute( m.format, m.args ); + fc::value lmsg(m); + + fc::string fmt_str = fc::substitute( my->cfg.format, value(m).set( "message", message) ); + { + fc::scoped_lock lock(my->slock); + my->out << fmt_str << "\n"; + } + if( my->cfg.flush ) my->out.flush(); + } +} diff --git a/src/logger_config.cpp b/src/logger_config.cpp index 1ff2603..6d0e3d1 100644 --- a/src/logger_config.cpp +++ b/src/logger_config.cpp @@ -8,6 +8,7 @@ namespace fc { std::unordered_map& get_logger_map(); std::unordered_map& get_appender_map(); + logger_config& logger_config::add_appender( const string& s ) { appenders.push_back(s); return *this; } void configure_logging( const fc::path& lc ) { @@ -26,13 +27,15 @@ namespace fc { for( size_t i = 0; i < cfg.loggers.size(); ++i ) { auto lgr = logger::get( cfg.loggers[i].name ); - // TODO: configure logger here... + // TODO: finish configure logger here... + if( cfg.loggers[i].parent ) { + lgr.set_parent( logger::get( *cfg.loggers[i].parent ) ); + } lgr.set_name(cfg.loggers[i].name); lgr.set_log_level( *cfg.loggers[i].level ); - for( auto a = cfg.loggers[i].appenders.begin(); - a != cfg.loggers[i].appenders.end(); ++a ){ + for( auto a = cfg.loggers[i].appenders.begin(); a != cfg.loggers[i].appenders.end(); ++a ){ auto ap = appender::get( *a ); if( ap ) { lgr.add_appender(ap); } } diff --git a/tests/logger.cpp b/tests/logger.cpp index 2a56739..350cb85 100644 --- a/tests/logger.cpp +++ b/tests/logger.cpp @@ -1,12 +1,25 @@ #include +#include +#include int main( int argc, char** argv ) { auto lgr = fc::logger::get(); - fc::configure_logging( fc::logging_config::default_config() ); + auto dconfig = fc::logging_config::default_config(); + dconfig.appenders.push_back( fc::appender_config("logfile", "file", fc::value(fc::file_appender::config("test.log")) ) ); + dconfig.loggers.push_back( fc::logger_config("main").add_appender("stderr").add_appender("logfile") ); + fc::configure_logging( dconfig ); fc_dlog( lgr, "Hello Debug" ); fc_ilog( lgr, "Hello Info" ); fc_wlog( lgr, "Hello Warn" ); fc_elog( lgr, "Hello Error" ); fc_flog( lgr, "Hello Fatal" ); + + + auto main_lgr = fc::logger::get( "main" ); + fc_dlog( main_lgr, "Hello Debug" ); + fc_ilog( main_lgr, "Hello Info" ); + fc_wlog( main_lgr, "Hello Warn" ); + fc_elog( main_lgr, "Hello Error" ); + fc_flog( main_lgr, "Hello Fatal" ); return 0; }