35 #include <boost/property_tree/ptree.hpp> 36 #include <boost/property_tree/ini_parser.hpp> 37 #include <boost/algorithm/string/predicate.hpp> 38 #include <boost/algorithm/string/split.hpp> 39 #include <boost/algorithm/string/split.hpp> 40 #include <boost/algorithm/string.hpp> 44 namespace bpo = boost::program_options;
46 namespace graphene {
namespace app {
namespace detail {
53 deduplicator(
const boost::shared_ptr<bpo::option_description> (*mod_fn)(
const boost::shared_ptr<bpo::option_description>&))
56 const boost::shared_ptr<bpo::option_description>
next(
const boost::shared_ptr<bpo::option_description>& o)
58 const std::string name = o->long_name();
59 if( seen.find( name ) != seen.end() )
62 return modifier ? modifier(o) : o;
66 boost::container::flat_set<std::string> seen;
67 const boost::shared_ptr<bpo::option_description> (*modifier)(
const boost::shared_ptr<bpo::option_description>&);
76 static void write_default_logging_config_to_stream(std::ostream& out)
78 out <<
"# declare an appender named \"stderr\" that writes messages to the console\n" 79 "[log.console_appender.stderr]\n" 80 "stream=std_error\n\n" 81 "# declare an appender named \"default\" that writes messages to default.log\n" 82 "[log.file_appender.default]\n" 83 "# filename can be absolute or relative to this config file\n" 84 "filename=logs/default/default.log\n" 85 "# Rotate log every ? minutes, if leave out default to 60\n" 86 "rotation_interval=60\n" 87 "# how long will logs be kept (in days), if leave out default to 1\n" 88 "rotation_limit=7\n\n" 89 "# declare an appender named \"p2p\" that writes messages to p2p.log\n" 90 "[log.file_appender.p2p]\n" 91 "# filename can be absolute or relative to this config file\n" 92 "filename=logs/p2p/p2p.log\n" 93 "# Rotate log every ? minutes, if leave out default to 60\n" 94 "rotation_interval=60\n" 95 "# how long will logs be kept (in days), if leave out default to 1\n" 96 "rotation_limit=7\n\n" 97 "# declare an appender named \"rpc\" that writes messages to rpc.log\n" 98 "[log.file_appender.rpc]\n" 99 "# filename can be absolute or relative to this config file\n" 100 "filename=logs/rpc/rpc.log\n" 101 "# Rotate log every ? minutes, if leave out default to 60\n" 102 "rotation_interval=60\n" 103 "# how long will logs be kept (in days), if leave out default to 1\n" 104 "rotation_limit=7\n\n" 105 "# route any messages logged to the default logger to the \"stderr\" appender and\n" 106 "# \"default\" appender we declared above, if they are info level or higher\n" 109 "appenders=stderr,default\n\n" 110 "# route messages sent to the \"p2p\" logger to the \"p2p\" appender declared above\n" 114 "# route messages sent to the \"rpc\" logger to the \"rpc\" appender declared above\n" 127 bool found_logging_config =
false;
129 boost::property_tree::ptree config_ini_tree;
130 boost::property_tree::ini_parser::read_ini(config_ini_filename.
preferred_string().c_str(), config_ini_tree);
131 for (
const auto& section : config_ini_tree)
133 const std::string& section_name = section.first;
134 const boost::property_tree::ptree& section_tree = section.second;
136 const std::string console_appender_section_prefix =
"log.console_appender.";
137 const std::string file_appender_section_prefix =
"log.file_appender.";
138 const std::string logger_section_prefix =
"logger.";
140 if (boost::starts_with(section_name, console_appender_section_prefix))
142 std::string console_appender_name = section_name.substr(console_appender_section_prefix.length());
143 std::string stream_name = section_tree.get<std::string>(
"stream");
151 console_appender_config.level_colors.emplace_back(
154 console_appender_config.level_colors.emplace_back(
159 found_logging_config =
true;
161 else if (boost::starts_with(section_name, file_appender_section_prefix))
163 std::string file_appender_name = section_name.substr(file_appender_section_prefix.length());
164 fc::path file_name = section_tree.get<std::string>(
"filename");
168 int interval = section_tree.get_optional<
int>(
"rotation_interval").get_value_or(60);
169 int limit = section_tree.get_optional<
int>(
"rotation_limit").get_value_or(1);
174 file_appender_config.
filename = file_name;
175 file_appender_config.
flush =
true;
176 file_appender_config.
rotate =
true;
180 found_logging_config =
true;
182 else if (boost::starts_with(section_name, logger_section_prefix))
184 std::string logger_name = section_name.substr(logger_section_prefix.length());
185 std::string level_string = section_tree.get<std::string>(
"level");
186 std::string appenders_string = section_tree.get<std::string>(
"appenders");
189 boost::split(logger_config.appenders, appenders_string,
190 boost::is_any_of(
" ,"),
191 boost::token_compress_on);
192 logging_config.
loggers.push_back(logger_config);
193 found_logging_config =
true;
196 if (found_logging_config)
197 return logging_config;
204 static const boost::shared_ptr<bpo::option_description> new_option_description(
const std::string& name,
const bpo::value_semantic* value,
const std::string& description )
206 bpo::options_description helper(
"");
207 helper.add_options()( name.c_str(), value, description.c_str() );
208 return helper.options()[0];
212 static void load_config_file(
const fc::path& config_ini_path,
const bpo::options_description& cfg_options,
213 bpo::variables_map& options )
216 bpo::options_description unique_options(
"BitShares Witness Node");
217 for(
const boost::shared_ptr<bpo::option_description>& opt : cfg_options.options() )
219 const boost::shared_ptr<bpo::option_description> od = dedup.
next(opt);
221 unique_options.add( od );
225 bpo::store(bpo::parse_config_file<char>(config_ini_path.
preferred_string().c_str(),
226 unique_options,
true), options);
229 static bool load_logging_config_file(
const fc::path& config_ini_path)
243 wlog(
"Error parsing logging config from logging config file ${config}, using default config", (
"config", config_ini_path.
preferred_string()));
248 static void create_new_config_file(
const fc::path& config_ini_path,
const fc::path& data_dir,
249 const bpo::options_description& cfg_options )
251 ilog(
"Writing new config file at ${path}", (
"path", config_ini_path));
255 auto modify_option_defaults = [](
const boost::shared_ptr<bpo::option_description>& o) ->
const boost::shared_ptr<bpo::option_description> {
256 const std::string& name = o->long_name();
257 if( name ==
"partial-operations" )
258 return new_option_description(name, bpo::value<bool>()->default_value(
true), o->description() );
259 if( name ==
"max-ops-per-account" )
260 return new_option_description(name, bpo::value<uint64_t>()->default_value(100), o->description() );
265 std::string plugin_header_surrounding( 78,
'=' );
266 for(
const boost::shared_ptr<bpo::option_description>& opt : cfg_options.options() )
268 const boost::shared_ptr<bpo::option_description> od = dedup.
next(opt);
271 if( od->long_name().find(
"plugin-cfg-header-") == 0 )
274 out_cfg <<
"# " << plugin_header_surrounding <<
"\n";
275 out_cfg <<
"# " << od->description() <<
"\n";
276 out_cfg <<
"# " << plugin_header_surrounding <<
"\n";
281 if( !od->description().empty() )
282 out_cfg <<
"# " << od->description() <<
"\n";
284 if( !od->semantic()->apply_default(store) )
285 out_cfg <<
"# " << od->long_name() <<
" = \n";
287 auto example = od->format_parameter();
288 if( example.empty() )
290 out_cfg << od->long_name() <<
" = " <<
"false\n";
294 example.erase(example.length()-1);
295 out_cfg << od->long_name() <<
" = " << example <<
"\n";
302 <<
"# " << plugin_header_surrounding <<
"\n" 303 <<
"# logging options\n" 304 <<
"# " << plugin_header_surrounding <<
"\n" 306 <<
"# Logging configuration is loaded from logging.ini by default.\n" 307 <<
"# If logging.ini exists, logging configuration added in this file will be ignored.\n";
311 static void create_logging_config_file(
const fc::path& config_ini_path,
const fc::path& data_dir)
313 ilog(
"Writing new config file at ${path}", (
"path", config_ini_path));
320 write_default_logging_config_to_stream(out_cfg);
324 namespace graphene {
namespace app {
328 const auto config_ini_path = data_dir /
"config.ini";
329 const auto logging_ini_path = data_dir /
"logging.ini";
334 create_new_config_file(config_ini_path, data_dir, cfg_options);
336 else if(!
exists(config_ini_path))
339 create_new_config_file(config_ini_path, data_dir, cfg_options);
340 create_logging_config_file(logging_ini_path, data_dir);
344 load_config_file(config_ini_path, cfg_options, options);
349 load_logging_config_file(logging_ini_path);
354 load_logging_config_file(config_ini_path);
fc::path parent_path() const
std::vector< logger_config > loggers
bool exists(const path &p)
microseconds rotation_limit
microseconds minutes(int64_t m)
#define GRAPHENE_MAX_NESTED_OBJECTS
std::vector< level_color > level_colors
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
void create_directories(const path &p)
#define FC_RETHROW_EXCEPTIONS(LOG_LEVEL, FORMAT,...)
Catchs all exception's, std::exceptions, and ... and rethrows them after appending the provided log m...
deduplicator(const boost::shared_ptr< bpo::option_description >(*mod_fn)(const boost::shared_ptr< bpo::option_description > &))
std::string preferred_string() const
provides stack-based nullable value similar to boost::optional
void load_configuration_options(const fc::path &data_dir, const bpo::options_description &cfg_options, bpo::variables_map &options)
microseconds days(int64_t d)
microseconds rotation_interval
T as(uint32_t max_depth) const
const boost::shared_ptr< bpo::option_description > next(const boost::shared_ptr< bpo::option_description > &o)
void configure_logging(const fc::path &log_config)
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
std::vector< appender_config > appenders
Defines exception's used by fc.
wraps boost::filesystem::path to provide platform independent path manipulation.
path absolute(const path &p)