Simplify logging options (#7620)

This removes --wconsole, --wnoconsole, and --wnoredirect. Instead these are now handled by --no-log-to-file and --log-to-file.

If logging to file is enabled, then output will be written to the log file. If logging to file is not enabled, then output is written to the terminal. On Windows, a terminal will be created for the output to be written to if wesnoth is not launched from a terminal.
This commit is contained in:
Pentarctagon 2023-05-14 12:47:43 -05:00 committed by GitHub
parent 729dcb842e
commit 0f550369b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 78 deletions

View file

@ -11,6 +11,6 @@ setlocal
rem Disable stdout.txt/stderr.txt redirection in SDLmain.
set SDL_STDIO_REDIRECT=0
wesnoth --wconsole %*
wesnoth --no-log-to-file %*
endlocal

View file

@ -169,9 +169,6 @@ class WesnothRunner:
if options.debug_bin:
path += "-debug"
self.common_args = [path, "--nobanner"]
if os.name == 'nt':
self.common_args.append("--wnoconsole")
self.common_args.append("--wnoredirect")
if options.strict_mode:
self.common_args.append("--log-strict=warning")
if options.clean:

View file

@ -61,11 +61,7 @@ bad_commandline_tuple::bad_commandline_tuple(const std::string& str,
}
#ifdef _WIN32
#define IMPLY_WCONSOLE " Implies --wconsole."
#else
#define IMPLY_WCONSOLE " Implies --no-log-to-file"
#endif // _WIN32
#define IMPLY_TERMINAL " Implies --no-log-to-file"
commandline_options::commandline_options(const std::vector<std::string>& args)
@ -178,14 +174,14 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
po::options_description general_opts("General options");
general_opts.add_options()
("all-translations", "Show all translations, even incomplete ones.")
("bunzip2", po::value<std::string>(), "decompresses a file (<arg>.bz2) in bzip2 format and stores it without the .bz2 suffix. <arg>.bz2 will be removed." IMPLY_WCONSOLE)
("bzip2", po::value<std::string>(), "compresses a file (<arg>) in bzip2 format, stores it as <arg>.bz2 and removes <arg>." IMPLY_WCONSOLE)
("bunzip2", po::value<std::string>(), "decompresses a file (<arg>.bz2) in bzip2 format and stores it without the .bz2 suffix. <arg>.bz2 will be removed." IMPLY_TERMINAL)
("bzip2", po::value<std::string>(), "compresses a file (<arg>) in bzip2 format, stores it as <arg>.bz2 and removes <arg>." IMPLY_TERMINAL)
("clock", "Adds the option to show a clock for testing the drawing timer.")
("config-dir", po::value<std::string>(), "sets the path of the userdata directory to $HOME/<arg> or My Documents\\My Games\\<arg> for Windows. You can specify also an absolute path outside the $HOME or My Documents\\My Games directory. DEPRECATED: use userdata-dir instead.")
("config-path", "prints the path of the userdata directory and exits. DEPRECATED: use userdata-path instead." IMPLY_WCONSOLE)
("config-path", "prints the path of the userdata directory and exits. DEPRECATED: use userdata-path instead." IMPLY_TERMINAL)
("core", po::value<std::string>(), "overrides the loaded core with the one whose id is specified.")
("data-dir", po::value<std::string>(), "overrides the data directory with the one specified.")
("data-path", "prints the path of the data directory and exits." IMPLY_WCONSOLE)
("data-path", "prints the path of the data directory and exits." IMPLY_TERMINAL)
("debug,d", "enables additional command mode options in-game.")
("debug-lua", "enables some Lua debugging mechanisms")
("strict-lua", "disallow deprecated Lua API calls")
@ -195,9 +191,9 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
("debug-dot-domain", po::value<std::string>(), "sets the domain of the debug dot files. <arg> should be a comma separated list of domains. See --debug-dot-level for more info. Available domains: show (generate the data when the dialog is about to be shown), layout (generate the data during the layout phase - might result in multiple files). The data can also be generated when the F12 is pressed in a dialog.")
#endif
("editor,e", po::value<std::string>()->implicit_value(std::string()), "starts the in-game map editor directly. If file <arg> is specified, equivalent to -e --load <arg>.")
("gunzip", po::value<std::string>(), "decompresses a file (<arg>.gz) in gzip format and stores it without the .gz suffix. <arg>.gz will be removed." IMPLY_WCONSOLE)
("gzip", po::value<std::string>(), "compresses a file (<arg>) in gzip format, stores it as <arg>.gz and removes <arg>." IMPLY_WCONSOLE)
("help,h", "prints this message and exits." IMPLY_WCONSOLE)
("gunzip", po::value<std::string>(), "decompresses a file (<arg>.gz) in gzip format and stores it without the .gz suffix. <arg>.gz will be removed." IMPLY_TERMINAL)
("gzip", po::value<std::string>(), "compresses a file (<arg>) in gzip format, stores it as <arg>.gz and removes <arg>." IMPLY_TERMINAL)
("help,h", "prints this message and exits." IMPLY_TERMINAL)
("language,L", po::value<std::string>(), "uses language <arg> (symbol) this session. Example: --language ang_GB@latin")
("load,l", po::value<std::string>(), "loads the save <arg> from the standard save game directory. When launching the map editor via -e, the map <arg> is loaded, relative to the current directory. If it is a directory, the editor will start with a load map dialog opened there.")
("noaddons", "disables the loading of all add-ons.")
@ -207,10 +203,10 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
("nosound", "runs the game without sounds and music.")
("password", po::value<std::string>(), "uses <password> when connecting to a server, ignoring other preferences.")
("plugin", po::value<std::string>(), "(experimental) load a script which defines a wesnoth plugin. similar to --script below, but Lua file should return a function which will be run as a coroutine and periodically woken up with updates.")
("render-image", po::value<two_strings>()->multitoken(), "takes two arguments: <image> <output>. Like screenshot, but instead of a map, takes a valid Wesnoth 'image path string' with image path functions, and writes it to a .png file." IMPLY_WCONSOLE)
("report,R", "initializes game directories, prints build information suitable for use in bug reports, and exits." IMPLY_WCONSOLE)
("render-image", po::value<two_strings>()->multitoken(), "takes two arguments: <image> <output>. Like screenshot, but instead of a map, takes a valid Wesnoth 'image path string' with image path functions, and writes it to a .png file." IMPLY_TERMINAL)
("report,R", "initializes game directories, prints build information suitable for use in bug reports, and exits." IMPLY_TERMINAL)
("rng-seed", po::value<unsigned int>(), "seeds the random number generator with number <arg>. Example: --rng-seed 0")
("screenshot", po::value<two_strings>()->multitoken(), "takes two arguments: <map> <output>. Saves a screenshot of <map> to <output> without initializing a screen. Editor must be compiled in for this to work." IMPLY_WCONSOLE)
("screenshot", po::value<two_strings>()->multitoken(), "takes two arguments: <map> <output>. Saves a screenshot of <map> to <output> without initializing a screen. Editor must be compiled in for this to work." IMPLY_TERMINAL)
("script", po::value<std::string>(), "(experimental) file containing a Lua script to control the client")
("server,s", po::value<std::string>()->implicit_value(std::string()), "connects to the host <arg> if specified or to the first host in your preferences.")
("strict-validation", "makes validation errors fatal")
@ -221,17 +217,12 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
("userconfig-dir", po::value<std::string>(), "sets the path of the user config directory to $HOME/<arg> or My Documents\\My Games\\<arg> for Windows. You can specify also an absolute path outside the $HOME or My Documents\\My Games directory. Defaults to $HOME/.config/wesnoth on X11 and to the userdata-dir on other systems.")
("userconfig-path", "prints the path of the user config directory and exits.")
("userdata-dir", po::value<std::string>(), "sets the path of the userdata directory to $HOME/<arg> or My Documents\\My Games\\<arg> for Windows. You can specify also an absolute path outside the $HOME or My Documents\\My Games directory.")
("userdata-path", "prints the path of the userdata directory and exits." IMPLY_WCONSOLE)
("userdata-path", "prints the path of the userdata directory and exits." IMPLY_TERMINAL)
("username", po::value<std::string>(), "uses <username> when connecting to a server, ignoring other preferences.")
("validcache", "assumes that the cache is valid. (dangerous)")
("version,v", "prints the game's version number and exits." IMPLY_WCONSOLE)
("simple-version", "prints the game's version number and nothing else." IMPLY_WCONSOLE)
("version,v", "prints the game's version number and exits." IMPLY_TERMINAL)
("simple-version", "prints the game's version number and nothing else." IMPLY_TERMINAL)
("with-replay", "replays the file loaded with the --load option.")
#ifdef _WIN32
("wconsole", "attaches a console window on startup (Windows only). Implied by any option that prints something and exits.")
("wnoconsole", "don't attach a console window on startup (Windows only). Overrides options that imply --wconsole.")
("wnoredirect", "disables standard redirection of logging to a file (Windows only), allowing the output to be piped to another command")
#endif // _WIN32
;
po::options_description campaign_opts("Campaign options");
@ -254,7 +245,7 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
po::options_description logging_opts("Logging options");
logging_opts.add_options()
("logdomains", po::value<std::string>()->implicit_value(std::string()), "lists defined log domains (only the ones containing <arg> filter if such is provided) and exits." IMPLY_WCONSOLE)
("logdomains", po::value<std::string>()->implicit_value(std::string()), "lists defined log domains (only the ones containing <arg> filter if such is provided) and exits." IMPLY_TERMINAL)
("log-error", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'error'. <arg> should be given as a comma-separated list of domains, wildcards are allowed. Example: --log-error=network,gui/*,engine/enemies")
("log-warning", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'warning'. Similar to --log-error.")
("log-info", po::value<std::string>(), "sets the severity level of the specified log domain(s) to 'info'. Similar to --log-error.")
@ -276,7 +267,7 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
("ignore-map-settings", "do not use map settings.")
("label", po::value<std::string>(), "sets the label for AIs.") // TODO: is the description precise? this option was undocumented before.
("multiplayer-repeat", po::value<unsigned int>(), "repeats a multiplayer game after it is finished <arg> times.")
("nogui", "runs the game without the GUI." IMPLY_WCONSOLE)
("nogui", "runs the game without the GUI." IMPLY_TERMINAL)
("parm", po::value<std::vector<std::string>>()->composing(), "sets additional parameters for this side. <arg> should have format side:name:value.")
("scenario", po::value<std::string>(), "selects a multiplayer scenario. The default scenario is \"multiplayer_The_Freelands\".")
("side", po::value<std::vector<std::string>>()->composing(), "selects a faction of the current era for this side by id. <arg> should have format side:value.")
@ -286,7 +277,7 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
po::options_description testing_opts("Testing options");
testing_opts.add_options()
("test,t", po::value<std::string>()->implicit_value(std::string()), "runs the game in a small test scenario. If specified, scenario <arg> will be used instead.")
("unit,u", po::value<std::vector<std::string>>(), "runs a unit test scenario. The GUI is not shown and the exit code of the program reflects the victory / defeat conditions of the scenario.\n\t0 - PASS\n\t1 - FAIL\n\t3 - FAIL (INVALID REPLAY)\n\t4 - FAIL (ERRORED REPLAY)\n\t5 - FAIL (BROKE STRICT)\n\t6 - FAIL (WML EXCEPTION)\n\tMultiple tests can be run by giving this option multiple times, in this case the test run will stop immediately after any test which doesn't PASS and the return code will be the status of the test that caused the stop." IMPLY_WCONSOLE)
("unit,u", po::value<std::vector<std::string>>(), "runs a unit test scenario. The GUI is not shown and the exit code of the program reflects the victory / defeat conditions of the scenario.\n\t0 - PASS\n\t1 - FAIL\n\t3 - FAIL (INVALID REPLAY)\n\t4 - FAIL (ERRORED REPLAY)\n\t5 - FAIL (BROKE STRICT)\n\t6 - FAIL (WML EXCEPTION)\n\tMultiple tests can be run by giving this option multiple times, in this case the test run will stop immediately after any test which doesn't PASS and the return code will be the status of the test that caused the stop." IMPLY_TERMINAL)
("showgui", "don't run headlessly (for debugging a failing test)")
("log-strict", po::value<std::string>(), "sets the strict level of the logger. any messages sent to log domains of this level or more severe will cause the unit test to fail regardless of the victory result.")
("nobanner", "suppress startup banner.")
@ -297,14 +288,14 @@ commandline_options::commandline_options(const std::vector<std::string>& args)
po::options_description parsing_opts("WML parsing options");
parsing_opts.add_options()
("use-schema,S", po::value<std::string>(), "specify a schema to validate WML against (defaults to the core schema).")
("validate,V", po::value<std::string>(), "validate a specified WML file against a schema." IMPLY_WCONSOLE)
("validate,V", po::value<std::string>(), "validate a specified WML file against a schema." IMPLY_TERMINAL)
("validate-addon", po::value<std::string>(), "validate the specified addon's WML against the schema. Requires the user to play the campaign (in the GUI) to trigger the validation.")
("validate-core", "validate the core WML against the schema.")
("validate-schema", po::value<std::string>(), "validate a specified WML schema." IMPLY_WCONSOLE)
("diff,D", po::value<two_strings>()->multitoken(), "diff two preprocessed WML documents." IMPLY_WCONSOLE)
("validate-schema", po::value<std::string>(), "validate a specified WML schema." IMPLY_TERMINAL)
("diff,D", po::value<two_strings>()->multitoken(), "diff two preprocessed WML documents." IMPLY_TERMINAL)
("output,o", po::value<std::string>(), "output to specified file")
("patch,P", po::value<two_strings>()->multitoken(), "apply a patch to a preprocessed WML document." IMPLY_WCONSOLE)
("preprocess,p", po::value<two_strings>()->multitoken(), "requires two arguments: <file/folder> <target directory>. Preprocesses a specified file/folder. The preprocessed file(s) will be written in the specified target directory: a plain cfg file and a processed cfg file." IMPLY_WCONSOLE)
("patch,P", po::value<two_strings>()->multitoken(), "apply a patch to a preprocessed WML document." IMPLY_TERMINAL)
("preprocess,p", po::value<two_strings>()->multitoken(), "requires two arguments: <file/folder> <target directory>. Preprocesses a specified file/folder. The preprocessed file(s) will be written in the specified target directory: a plain cfg file and a processed cfg file." IMPLY_TERMINAL)
("preprocess-defines", po::value<std::string>(), "comma separated list of defines to be used by '--preprocess' command. If 'SKIP_CORE' is in the define list the data/core won't be preprocessed. Example: --preprocess-defines=FOO,BAR")
("preprocess-input-macros", po::value<std::string>(), "used only by the '--preprocess' command. Specifies source file <arg> that contains [preproc_define]s to be included before preprocessing.")
("preprocess-output-macros", po::value<std::string>()->implicit_value(std::string()), "used only by the '--preprocess' command. Will output all preprocessed macros in the target file <arg>. If the file is not specified the output will be file '_MACROS_.cfg' in the target directory of preprocess's command.")

View file

@ -49,15 +49,15 @@ namespace lg
namespace
{
/**
* Singleton class that deals with the intricacies of log file redirection.
* Singleton class that handles sending logging output to a console on windows.
*/
class log_file_manager
class console_handler
{
public:
log_file_manager(const log_file_manager&) = delete;
log_file_manager& operator=(const log_file_manager&) = delete;
console_handler(const console_handler&) = delete;
console_handler& operator=(const console_handler&) = delete;
log_file_manager(bool native_console);
console_handler();
/**
* Returns whether we own the console we are attached to, if any.
@ -68,15 +68,12 @@ private:
bool created_wincon_;
/**
* Switches to using a native console instead of log file redirection.
*
* This is an irreversible operation right now. This might change later if
* someone deems it useful.
* Switches to using a native console.
*/
void enable_native_console_output();
};
log_file_manager::log_file_manager(bool native_console)
console_handler::console_handler()
: created_wincon_(false)
{
DBG_LS << "Early init message";
@ -86,19 +83,19 @@ log_file_manager::log_file_manager(bool native_console)
// with the console subsystem flag and that the standard streams are
// already pointing to the console.
LOG_LS << "Console already attached at startup (built with console subsystem flag?), log file disabled.";
} else if(native_console) {
} else {
enable_native_console_output();
}
DBG_LS << "Windows console init complete!";
}
bool log_file_manager::owns_console() const
bool console_handler::owns_console() const
{
return created_wincon_;
}
void log_file_manager::enable_native_console_output()
void console_handler::enable_native_console_output()
{
if(AttachConsole(ATTACH_PARENT_PROCESS)) {
LOG_LS << "Attached parent process console.";
@ -127,22 +124,17 @@ void log_file_manager::enable_native_console_output()
DBG_LS << "stdin from console";
assert(freopen("CONIN$", "rb", stdin) == stdin);
// At this point the log file has been closed and it's no longer our
// responsibility to clean up anything; Windows will figure out what to do
// when the time comes for the process to exit.
lg::set_log_file_path("");
LOG_LS << "Console streams handover complete!";
}
std::unique_ptr<log_file_manager> lfm;
std::unique_ptr<console_handler> lfm;
} // end anonymous namespace
void do_console_redirect(bool native_console)
void do_console_redirect()
{
if(!lfm) {
lfm.reset(new log_file_manager(native_console));
lfm.reset(new console_handler());
}
}

View file

@ -30,7 +30,7 @@
* Because Wesnoth is normally built with the GUI subsystem option, there is no
* console on startup and thus no way to see stdout/stderr output. Since
* version 1.13.1, we can allocate a console during initialization when started
* with the --wconsole option, but that is a somewhat clunky hack that does not
* with the --wconsole option (now --no-log-to-file), but that is a somewhat clunky hack that does not
* help with post mortem debugging.
*
* SDL 1.2 used to redirect stdout and stderr to stdout.txt and stderr.txt in
@ -50,7 +50,7 @@ namespace lg
* horribly wrong as soon as we try to use the logging facilities internally
* for debug messages.
*/
void do_console_redirect(bool native_console);
void do_console_redirect();
/**
* Returns true if a console was allocated by the Wesnoth process.

View file

@ -1056,10 +1056,9 @@ int main(int argc, char** argv)
_putenv("FONTCONFIG_PATH=fonts");
#endif
// terminal_force means output has been explicitly (via command line argument)
// or implicitly (by a command line argument that implies an interactive terminal has been used) requested on standard out.
// write_to_log_file means that writing to the log file will be done. terminal_force takes priority, but writing to a log file is the default.
bool terminal_force = false;
// write_to_log_file means that writing to the log file will be done, if true.
// if false, output will be written to the terminal
// on windows, if wesnoth was not started from a console, then it will allocate one
bool write_to_log_file = true;
// --nobanner needs to be detected before the main command-line parsing happens
@ -1074,11 +1073,11 @@ int main(int argc, char** argv)
// Some switches force a Windows console to be attached to the process even
// if Wesnoth is an IMAGE_SUBSYSTEM_WINDOWS_GUI executable because they
// turn it into a CLI application. Also, --wconsole in particular attaches
// turn it into a CLI application. Also, --no-log-to-file in particular attaches
// a console to a regular GUI game session.
//
// It's up to commandline_options later to handle these switches (except
// --wconsole) later and emit any applicable console output, but right here
// --no-log-to-file) later and emit any applicable console output, but right here
// we need a rudimentary check for the switches in question to set up the
// console before proceeding any further.
for(const auto& arg : args) {
@ -1103,33 +1102,23 @@ int main(int argc, char** argv)
if(terminal_switches.find(arg) != terminal_switches.end() ||
std::find_if(terminal_arg_switches.begin(), terminal_arg_switches.end(), switch_matches_arg) != terminal_arg_switches.end()) {
terminal_force = true;
}
#ifdef _WIN32
if(arg == "--wnoconsole") {
terminal_force = false;
} else if(arg == "--wconsole") {
terminal_force = true;
} else if(arg == "--wnoredirect") {
write_to_log_file = false;
}
#endif
if(arg == "--no-log-to-file") {
terminal_force = true;
write_to_log_file = false;
} else if(arg == "--log-to-file") {
write_to_log_file = true;
}
}
// setup logging to file
// else handle redirecting the output and/or attaching a console
if(write_to_log_file && !terminal_force) {
// else handle redirecting the output and potentially attaching a console on windows
if(write_to_log_file) {
lg::set_log_to_file();
} else {
#ifdef _WIN32
lg::do_console_redirect(terminal_force);
lg::do_console_redirect();
#endif
}