From f7ce1845f34370009a3fbeb7aee1a4a1e7818901 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Wed, 14 May 2014 21:39:20 -0400 Subject: [PATCH] add "strict" logging option, to treat e.g. wml warnings as errors When the game is run using e.g. "--log-strict=warning", then writing anything to a log channel of severity warning or higher will result in a game::game_error exception being thrown. This will only happen the first time that such a write is attempted, subsequent attempts to get the logging object will pass without exception and such messages will be reported. --- src/commandline_options.cpp | 15 +++++++++++++++ src/commandline_options.hpp | 3 +++ src/log.cpp | 26 ++++++++++++++++++++++++-- src/log.hpp | 8 ++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/commandline_options.cpp b/src/commandline_options.cpp index dc3555eef0a8..41c9055b710d 100644 --- a/src/commandline_options.cpp +++ b/src/commandline_options.cpp @@ -196,6 +196,7 @@ commandline_options::commandline_options ( int argc, char** argv ) : ("log-info", po::value(), "sets the severity level of the specified log domain(s) to 'info'. Similar to --log-error.") ("log-debug", po::value(), "sets the severity level of the specified log domain(s) to 'debug'. Similar to --log-error.") ("log-precise", "shows the timestamps in the logfile with more precision") + ("log-strict", po::value(), "sets the strict level of the logger. messages to log domains of this level or more severe generate an in-game exception.") ; po::options_description multiplayer_opts("Multiplayer options"); @@ -332,6 +333,8 @@ commandline_options::commandline_options ( int argc, char** argv ) : logdomains = vm["logdomains"].as(); if (vm.count("log-precise")) log_precise_timestamps = true; + if (vm.count("log-strict")) + parse_log_strictness(vm["log-strict"].as()); if (vm.count("max-fps")) max_fps = vm["max-fps"].as(); if (vm.count("multiplayer")) @@ -444,6 +447,18 @@ void commandline_options::parse_log_domains_(const std::string &domains_string, } } +void commandline_options::parse_log_strictness (const std::string & severity ) { + static lg::logger const *loggers[] = { &lg::err, &lg::warn, &lg::info, &lg::debug }; + BOOST_FOREACH (const lg::logger * l, loggers ) { + if (severity == l->get_name()) { + lg::set_strict_severity(*l); + return ; + } + } + std::cerr << "Unrecognized argument to --log-strict : " << severity << " . \nDisabling strict mode logging." << std::endl; + lg::set_strict_severity(-1); +} + void commandline_options::parse_resolution_ ( const std::string& resolution_string ) { const std::vector tokens = utils::split(resolution_string, 'x'); diff --git a/src/commandline_options.hpp b/src/commandline_options.hpp index 1012f8a95e58..80f9274eff69 100644 --- a/src/commandline_options.hpp +++ b/src/commandline_options.hpp @@ -75,6 +75,8 @@ friend std::ostream& operator<<(std::ostream &os, const commandline_options& cmd /// Contains parsed arguments of --log-* (e.g. --log-debug). /// Vector of pairs (severity, log domain). boost::optional > > log; + /// Non-empty if --log-strict was given + boost::optional log_strict_level; /// Non-empty if --load was given on the command line. Savegame specified to load after start. boost::optional load; /// Non-empty if --logdomains was given on the command line. Prints possible logdomains filtered by given string and exits. @@ -191,6 +193,7 @@ friend std::ostream& operator<<(std::ostream &os, const commandline_options& cmd bool with_replay; private: void parse_log_domains_(const std::string &domains_string, const int severity); + void parse_log_strictness (const std::string &severity); void parse_resolution_ (const std::string &resolution_string); /// A helper function splitting vector of strings of format unsigned int:string to vector of tuples (unsigned int,string) std::vector > parse_to_uint_string_tuples_(const std::vector &strings, char separator = ':'); diff --git a/src/log.cpp b/src/log.cpp index 4b2d8d1dcb21..b0400a703773 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -19,6 +19,7 @@ * See also the command line switches --logdomains and --log-@="domain". */ +#include "game_errors.hpp" #include "global.hpp" #include "SDL.h" @@ -74,6 +75,8 @@ tredirect_output_setter::~tredirect_output_setter() typedef std::map domain_map; static domain_map *domains; +static int strict_level_ = -1; +static bool strict_threw_ = false; void timestamps(bool t) { timestamp = t; } void precise_timestamps(bool pt) { precise_timestamp = pt; } @@ -122,6 +125,14 @@ std::string list_logdomains(const std::string& filter) return res.str(); } +void set_strict_severity(int severity) { + strict_level_ = severity; +} + +void set_strict_severity(const logger &lg) { + set_strict_severity(lg.get_severity()); +} + std::string get_timestamp(const time_t& t, const std::string& format) { char buf[100] = {0}; tm* lt = localtime(&t); @@ -158,9 +169,20 @@ static void print_precise_timestamp(std::ostream & out) std::ostream &logger::operator()(log_domain const &domain, bool show_names, bool do_indent) const { - if (severity_ > domain.domain_->second) + if (severity_ > domain.domain_->second) { return null_ostream; - else { + } else if (!strict_threw_ && (severity_ <= strict_level_)) { + std::stringstream ss; + ss << "Error (strict mode, strict_level = " << strict_level_ << "): wesnoth reported on channel " << name_ << " " << domain.domain_->first; + std::cerr << ss.str() << std::endl; + //TODO: Would be nice to actually get whatever message they were going to log... + //perhaps could pass back a & to a stringstream with a custom destructor that + //throws this game::error when it goes out of scope, after capturing their message? + //TODO: The flag strict_threw_ makes sure that we only do this once, and don't block + //subsequent error logging. Does this need to be more robust? + strict_threw_ = true; + throw game::game_error(ss.str()); + } else { std::ostream& stream = output(); if(do_indent) { for(int i = 0; i != indent; ++i) diff --git a/src/log.hpp b/src/log.hpp index d88ee7879ffe..add80ad00cd2 100644 --- a/src/log.hpp +++ b/src/log.hpp @@ -78,6 +78,9 @@ bool set_log_domain_severity(std::string const &name, int severity); bool set_log_domain_severity(std::string const &name, const logger &lg); std::string list_logdomains(const std::string& filter); +void set_strict_severity(int severity); +void set_strict_severity(const logger &lg); + class logger { char const *name_; int severity_; @@ -95,6 +98,11 @@ class logger { { return severity_; } + + std::string get_name() const + { + return name_; + } }; void timestamps(bool);