From aa794e7836244e0287f3fa3d94e8081b513af08f Mon Sep 17 00:00:00 2001 From: Eric Frias Date: Wed, 15 Jul 2015 14:37:03 -0400 Subject: [PATCH] By default, log p2p messages to logs/p2p/p2p.log, default to stderr, progress on #149 --- programs/witness_node/main.cpp | 142 +++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 5 deletions(-) diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 99387f31..cbf53f7d 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -23,9 +23,19 @@ #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include + #include #include @@ -35,6 +45,9 @@ using namespace graphene; namespace bpo = boost::program_options; + +void write_default_logging_config_to_stream(std::ostream& out); +fc::optional load_logging_config_from_ini_file(const fc::path& config_ini_filename); int main(int argc, char** argv) { try { @@ -80,14 +93,24 @@ int main(int argc, char** argv) { data_dir = fc::current_path() / data_dir; } - if( fc::exists(data_dir / "config.ini") ) - bpo::store(bpo::parse_config_file((data_dir / "config.ini").preferred_string().c_str(), cfg_options), options); - else { - ilog("Writing new config file at ${path}", ("path", data_dir/"config.ini")); + fc::path config_ini_path = data_dir / "config.ini"; + if( fc::exists(config_ini_path) ) + { + // get the basic options + bpo::store(bpo::parse_config_file(config_ini_path.preferred_string().c_str(), cfg_options, true), options); + + // try to get logging options from the config file. + fc::optional logging_config = load_logging_config_from_ini_file(config_ini_path); + if (logging_config) + fc::configure_logging(*logging_config); + } + else + { + ilog("Writing new config file at ${path}", ("path", config_ini_path)); if( !fc::exists(data_dir) ) fc::create_directories(data_dir); - std::ofstream out_cfg((data_dir / "config.ini").preferred_string()); + std::ofstream out_cfg(config_ini_path.preferred_string()); for( const boost::shared_ptr od : cfg_options.options() ) { if( !od->description().empty() ) @@ -109,6 +132,12 @@ int main(int argc, char** argv) { } out_cfg << "\n"; } + write_default_logging_config_to_stream(out_cfg); + out_cfg.close(); + // read the default logging config we just wrote out to the file and start using it + fc::optional logging_config = load_logging_config_from_ini_file(config_ini_path); + if (logging_config) + fc::configure_logging(*logging_config); } bpo::notify(options); @@ -136,3 +165,106 @@ int main(int argc, char** argv) { return 1; } } + +// logging config is too complicated to be parsed by boost::program_options, +// so we do it by hand +// +// Currently, you can only specify the filenames and logging levels, which +// are all most users would want to change. At a later time, options can +// be added to control rotation intervals, compression, and other seldom- +// used features +void write_default_logging_config_to_stream(std::ostream& out) +{ + out << "# declare an appender named \"stderr\" that writes messages to the console\n" + "[log.console_appender.stderr]\n" + "stream=std_error\n\n" + "# declare an appender named \"p2p\" that writes messages to p2p.log\n" + "[log.file_appender.p2p]\n" + "filename=logs/p2p/p2p.log\n" + "# filename can be absolute or relative to this config file\n\n" + "# route any messages logged to the default logger to the \"stderr\" logger we\n" + "# declared above, if they are info level are higher\n" + "[logger.default]\n" + "level=info\n" + "appenders=stderr\n\n" + "# route messages sent to the \"p2p\" logger to the p2p appender declared above\n" + "[logger.p2p]\n" + "level=debug\n" + "appenders=p2p\n\n"; +} + +fc::optional load_logging_config_from_ini_file(const fc::path& config_ini_filename) +{ + fc::logging_config logging_config; + bool found_logging_config = false; + + boost::property_tree::ptree config_ini_tree; + boost::property_tree::ini_parser::read_ini(config_ini_filename.preferred_string().c_str(), config_ini_tree); + for (const auto& section : config_ini_tree) + { + const std::string& section_name = section.first; + const boost::property_tree::ptree& section_tree = section.second; + + const std::string console_appender_section_prefix = "log.console_appender."; + const std::string file_appender_section_prefix = "log.file_appender."; + const std::string logger_section_prefix = "logger."; + + if (boost::starts_with(section_name, console_appender_section_prefix)) + { + std::string console_appender_name = section_name.substr(console_appender_section_prefix.length()); + std::string stream_name = section_tree.get("stream"); + + // construct a default console appender config here + // stdout/stderr will be taken from ini file, everything else hard-coded here + fc::console_appender::config console_appender_config; + console_appender_config.level_colors.emplace_back( + fc::console_appender::level_color(fc::log_level::debug, + fc::console_appender::color::green)); + console_appender_config.level_colors.emplace_back( + fc::console_appender::level_color(fc::log_level::warn, + fc::console_appender::color::brown)); + console_appender_config.level_colors.emplace_back( + fc::console_appender::level_color(fc::log_level::error, + fc::console_appender::color::cyan)); + console_appender_config.stream = fc::variant(stream_name).as(); + logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config))); + found_logging_config = true; + } + else if (boost::starts_with(section_name, file_appender_section_prefix)) + { + std::string file_appender_name = section_name.substr(file_appender_section_prefix.length()); + fc::path file_name = section_tree.get("filename"); + if (file_name.is_relative()) + file_name = fc::absolute(config_ini_filename).parent_path() / file_name; + + + // construct a default file appender config here + // filename will be taken from ini file, everything else hard-coded here + fc::file_appender::config file_appender_config; + file_appender_config.filename = file_name; + file_appender_config.flush = true; + file_appender_config.rotate = true; + file_appender_config.rotation_interval = fc::hours(1); + file_appender_config.rotation_limit = fc::days(1); + logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config))); + found_logging_config = true; + } + else if (boost::starts_with(section_name, logger_section_prefix)) + { + std::string logger_name = section_name.substr(logger_section_prefix.length()); + std::string level_string = section_tree.get("level"); + std::string appenders_string = section_tree.get("appenders"); + fc::logger_config logger_config(logger_name); + logger_config.level = fc::variant(level_string).as(); + boost::split(logger_config.appenders, appenders_string, + boost::is_any_of(" ,"), + boost::token_compress_on); + logging_config.loggers.push_back(logger_config); + found_logging_config = true; + } + } + if (found_logging_config) + return logging_config; + else + return fc::optional(); +}