Further consolidate logging functionality between Windows and non-Windows platforms.
For non-Windows platforms this adds: * a new check for whether the logs directory exists and is writable by attempting to write a single whitespace to a dummy.log file. * a popup shown immediately after the GUI system is initialized letting the player know if there was an issue creating the log file. For Windows, this changes: * instead of writing to the OS temp directory and then attempting to move that file to the logs directory, this uses the same check that was described above for non-Windows platforms. * the alert shown when writing the dummy log file fails is now a Wesnoth alert message rather than the Windows-specific MessageBox. * a failure to create a log file does not immediately exit wesnoth anymore. Additionally, this makes it so that for the default state (logging to file), all platforms follow the same code path by calling `lg::set_log_to_file()`. `log_windows` now contains only the Windows-specific logic needed for handling the creation/redirection of output to a console.
This commit is contained in:
parent
26400f9398
commit
3f63908296
13 changed files with 91 additions and 407 deletions
|
@ -805,7 +805,6 @@
|
|||
<Unit filename="../../src/language.cpp" />
|
||||
<Unit filename="../../src/language.hpp" />
|
||||
<Unit filename="../../src/lexical_cast.hpp" />
|
||||
<Unit filename="../../src/libc_error.hpp" />
|
||||
<Unit filename="../../src/log.cpp" />
|
||||
<Unit filename="../../src/log.hpp" />
|
||||
<Unit filename="../../src/log_windows.cpp" />
|
||||
|
|
|
@ -69,7 +69,6 @@
|
|||
<Unit filename="../../src/global.hpp" />
|
||||
<Unit filename="../../src/hash.cpp" />
|
||||
<Unit filename="../../src/hash.hpp" />
|
||||
<Unit filename="../../src/libc_error.hpp" />
|
||||
<Unit filename="../../src/log.cpp" />
|
||||
<Unit filename="../../src/log.hpp" />
|
||||
<Unit filename="../../src/log_windows.cpp" />
|
||||
|
|
|
@ -112,7 +112,6 @@
|
|||
<Unit filename="../../src/global.hpp" />
|
||||
<Unit filename="../../src/hash.cpp" />
|
||||
<Unit filename="../../src/hash.hpp" />
|
||||
<Unit filename="../../src/libc_error.hpp" />
|
||||
<Unit filename="../../src/log.cpp" />
|
||||
<Unit filename="../../src/log.hpp" />
|
||||
<Unit filename="../../src/log_windows.cpp" />
|
||||
|
|
|
@ -897,7 +897,6 @@
|
|||
<Unit filename="../../src/language.hpp" />
|
||||
<Unit filename="../../src/level_result.hpp" />
|
||||
<Unit filename="../../src/lexical_cast.hpp" />
|
||||
<Unit filename="../../src/libc_error.hpp" />
|
||||
<Unit filename="../../src/log.cpp" />
|
||||
<Unit filename="../../src/log.hpp" />
|
||||
<Unit filename="../../src/log_windows.cpp" />
|
||||
|
|
|
@ -892,7 +892,6 @@
|
|||
<Unit filename="../../src/language.hpp" />
|
||||
<Unit filename="../../src/level_result.hpp" />
|
||||
<Unit filename="../../src/lexical_cast.hpp" />
|
||||
<Unit filename="../../src/libc_error.hpp" />
|
||||
<Unit filename="../../src/log.cpp" />
|
||||
<Unit filename="../../src/log.hpp" />
|
||||
<Unit filename="../../src/log_windows.cpp" />
|
||||
|
|
|
@ -104,7 +104,6 @@
|
|||
<Unit filename="../../src/global.hpp" />
|
||||
<Unit filename="../../src/hash.cpp" />
|
||||
<Unit filename="../../src/hash.hpp" />
|
||||
<Unit filename="../../src/libc_error.hpp" />
|
||||
<Unit filename="../../src/log.cpp" />
|
||||
<Unit filename="../../src/log.hpp" />
|
||||
<Unit filename="../../src/log_windows.cpp" />
|
||||
|
|
|
@ -586,11 +586,7 @@ static void setup_user_data_dir()
|
|||
create_directory_if_missing(user_data_dir / "persist");
|
||||
create_directory_if_missing(filesystem::get_logs_dir());
|
||||
|
||||
#ifdef _WIN32
|
||||
lg::finish_log_file_setup();
|
||||
#else
|
||||
lg::rotate_logs(filesystem::get_logs_dir());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2015 - 2022
|
||||
by Iris Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
The contents of this file are placed in the public domain.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Exception type used to propagate C runtime errors across functions.
|
||||
*/
|
||||
class libc_error : public std::exception
|
||||
{
|
||||
public:
|
||||
libc_error()
|
||||
: e_(errno)
|
||||
, desc_(strerror(e_))
|
||||
, msg_("C library error: " + desc_)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~libc_error() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
/** Returns the value of @a errno at the time the exception was thrown. */
|
||||
int num() const
|
||||
{
|
||||
return e_;
|
||||
}
|
||||
|
||||
/** Returns an explanatory string describing the runtime error alone. */
|
||||
const std::string& desc() const
|
||||
{
|
||||
return desc_;
|
||||
}
|
||||
|
||||
/** Returns an explanatory string describing the exception. */
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return msg_.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
int e_;
|
||||
std::string desc_;
|
||||
std::string msg_;
|
||||
};
|
54
src/log.cpp
54
src/log.cpp
|
@ -57,6 +57,7 @@ static bool timestamp = true;
|
|||
static bool precise_timestamp = false;
|
||||
static std::mutex log_mutex;
|
||||
|
||||
static bool is_log_dir_writable_ = true;
|
||||
static std::ostream *output_stream_ = nullptr;
|
||||
|
||||
static std::ostream& output()
|
||||
|
@ -91,6 +92,11 @@ bool is_not_log_file(const std::string& fn)
|
|||
*/
|
||||
void rotate_logs(const std::string& log_dir)
|
||||
{
|
||||
// if logging to file is disabled, don't rotate the logs
|
||||
if(output_file_path_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> files;
|
||||
filesystem::get_files_in_dir(log_dir, &files);
|
||||
|
||||
|
@ -132,13 +138,53 @@ std::string unique_log_filename()
|
|||
return o.str();
|
||||
}
|
||||
|
||||
void check_log_dir_writable()
|
||||
{
|
||||
std::string dummy_log = filesystem::get_logs_dir()+"/dummy.log";
|
||||
|
||||
// log directory doesn't exist and can't be created
|
||||
if(!filesystem::file_exists(filesystem::get_logs_dir()) && !filesystem::make_directory(filesystem::get_logs_dir())) {
|
||||
is_log_dir_writable_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// can't create and write new log files
|
||||
try {
|
||||
filesystem::write_file(dummy_log, " ");
|
||||
} catch(const filesystem::io_exception&) {
|
||||
is_log_dir_writable_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// confirm that file exists and was written to
|
||||
if(filesystem::file_size(dummy_log) != 1) {
|
||||
is_log_dir_writable_ = false;
|
||||
}
|
||||
|
||||
// can't delete files - prevents log rotation
|
||||
if(filesystem::file_exists(dummy_log) && !filesystem::delete_file(dummy_log)) {
|
||||
is_log_dir_writable_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
is_log_dir_writable_ = true;
|
||||
}
|
||||
|
||||
void set_log_to_file()
|
||||
{
|
||||
check_log_dir_writable();
|
||||
// get the log file stream and assign cerr+cout to it
|
||||
output_file_path_ = filesystem::get_logs_dir()+"/"+unique_log_filename();
|
||||
output_file_.reset(filesystem::ostream_file(output_file_path_).release());
|
||||
std::cerr.rdbuf(output_file_.get()->rdbuf());
|
||||
std::cout.rdbuf(output_file_.get()->rdbuf());
|
||||
if(is_log_dir_writable_) {
|
||||
output_file_path_ = filesystem::get_logs_dir()+"/"+unique_log_filename();
|
||||
output_file_.reset(filesystem::ostream_file(output_file_path_).release());
|
||||
std::cerr.rdbuf(output_file_.get()->rdbuf());
|
||||
std::cout.rdbuf(output_file_.get()->rdbuf());
|
||||
}
|
||||
}
|
||||
|
||||
bool log_dir_writable()
|
||||
{
|
||||
return is_log_dir_writable_;
|
||||
}
|
||||
|
||||
std::string& get_log_file_path()
|
||||
|
|
|
@ -127,6 +127,8 @@ void set_strict_severity(int severity);
|
|||
void set_strict_severity(const logger &lg);
|
||||
bool broke_strict();
|
||||
void set_log_to_file();
|
||||
void check_log_dir_writable();
|
||||
bool log_dir_writable();
|
||||
|
||||
bool is_not_log_file(const std::string& filename);
|
||||
void rotate_logs(const std::string& log_dir);
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "log_windows.hpp"
|
||||
|
||||
#include "filesystem.hpp"
|
||||
#include "libc_error.hpp"
|
||||
#include "log.hpp"
|
||||
#include "serialization/unicode.hpp"
|
||||
|
||||
|
@ -49,72 +48,6 @@ namespace lg
|
|||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns the path to a system-defined temporary files dir.
|
||||
*/
|
||||
std::string temp_dir()
|
||||
{
|
||||
wchar_t tmpdir[MAX_PATH + 1];
|
||||
|
||||
if(GetTempPath(MAX_PATH + 1, tmpdir) == 0) {
|
||||
return ".";
|
||||
}
|
||||
|
||||
return unicode_cast<std::string>(std::wstring(tmpdir));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an alert box to warn about log initialization errors, and exit.
|
||||
*/
|
||||
void log_init_panic(const std::string& msg)
|
||||
{
|
||||
ERR_LS << "Log initialization panic call: " << msg;
|
||||
|
||||
const std::string full_msg = msg + "\n\n" + "This may indicate an issue with your Wesnoth launch configuration. If the problem persists, contact the development team for technical support, including the full contents of this message (copy with CTRL+C).";
|
||||
|
||||
// It may not be useful to write to stderr at this point, so warn the user
|
||||
// in a failsafe fashion via Windows UI API.
|
||||
MessageBox(nullptr,
|
||||
unicode_cast<std::wstring>(full_msg).c_str(),
|
||||
L"Battle for Wesnoth",
|
||||
MB_ICONEXCLAMATION | MB_OK);
|
||||
|
||||
// It may seem excessive to quit over something like this, but it's a good
|
||||
// indicator of possible configuration issues with the user data dir that
|
||||
// may cause much weirder symptoms later (see https://r.wesnoth.org/t42970
|
||||
// for an example).
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an alert box to warn about log initialization errors, and exit.
|
||||
*/
|
||||
void log_init_panic(const libc_error& e,
|
||||
const std::string& new_log_path,
|
||||
const std::string& old_log_path = std::string())
|
||||
{
|
||||
std::ostringstream msg;
|
||||
|
||||
if(old_log_path.empty()) {
|
||||
msg << "Early log initialization failed.";
|
||||
} else {
|
||||
msg << "Log relocation failed.";
|
||||
}
|
||||
|
||||
msg << "\n\n"
|
||||
<< "Runtime error: " << e.desc() << " (" << e.num() << ")\n";
|
||||
|
||||
if(old_log_path.empty()) {
|
||||
msg << "Log file path: " << new_log_path << '\n';
|
||||
} else {
|
||||
msg << "New log file path: " << new_log_path << '\n'
|
||||
<< "Old log file path: " << old_log_path;
|
||||
}
|
||||
|
||||
log_init_panic(msg.str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton class that deals with the intricacies of log file redirection.
|
||||
*/
|
||||
|
@ -124,21 +57,15 @@ public:
|
|||
log_file_manager(const log_file_manager&) = delete;
|
||||
log_file_manager& operator=(const log_file_manager&) = delete;
|
||||
|
||||
log_file_manager(bool native_console = false);
|
||||
~log_file_manager();
|
||||
log_file_manager(bool native_console);
|
||||
|
||||
/**
|
||||
* Moves the log file to a new directory.
|
||||
*
|
||||
* This causes the associated streams to closed momentarily in order to be
|
||||
* able to move the log file, because Windows does not allow move/rename
|
||||
* operations on currently-open files.
|
||||
*
|
||||
* @param log_dir Log directory path.
|
||||
*
|
||||
* @throw libc_error If the log file cannot be opened or relocated.
|
||||
* Returns whether we own the console we are attached to, if any.
|
||||
*/
|
||||
void move_log_file(const std::string& log_dir);
|
||||
bool owns_console() const;
|
||||
|
||||
private:
|
||||
bool created_wincon_;
|
||||
|
||||
/**
|
||||
* Switches to using a native console instead of log file redirection.
|
||||
|
@ -147,176 +74,23 @@ public:
|
|||
* someone deems it useful.
|
||||
*/
|
||||
void enable_native_console_output();
|
||||
|
||||
/**
|
||||
* Returns whether we are using a native console instead of a log file.
|
||||
*/
|
||||
bool console_enabled() const;
|
||||
|
||||
/**
|
||||
* Returns whether we are attached to a native console right now.
|
||||
*
|
||||
* Note that being attached to a console does not necessarily mean that the
|
||||
* standard streams are pointing to it. Use console_enabled to check that
|
||||
* instead.
|
||||
*/
|
||||
bool console_attached() const;
|
||||
|
||||
/**
|
||||
* Returns whether we own the console we are attached to, if any.
|
||||
*/
|
||||
bool owns_console() const;
|
||||
|
||||
private:
|
||||
std::string fn_;
|
||||
bool use_wincon_, created_wincon_;
|
||||
|
||||
enum STREAM_ID {
|
||||
STREAM_STDOUT = 1,
|
||||
STREAM_STDERR = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the log file for the current session in the specified directory.
|
||||
*
|
||||
* @param file_path Log file path.
|
||||
* @param truncate Whether to truncate an existing log file or append
|
||||
* to it instead.
|
||||
*
|
||||
* @throw libc_error If the log file cannot be opened.
|
||||
*/
|
||||
void open_log_file(const std::string& file_path,
|
||||
bool truncate);
|
||||
|
||||
/**
|
||||
* Takes care of any tasks required for redirecting a log stream.
|
||||
*
|
||||
* @param file_path Log file path.
|
||||
* @param stream Stream identifier.
|
||||
* @param truncate Whether to truncate an existing log file or append
|
||||
* to it instead.
|
||||
*
|
||||
* @throw libc_error If the log file cannot be opened.
|
||||
*
|
||||
* @note This does not set the log file path to the new path.
|
||||
*/
|
||||
void do_redirect_single_stream(const std::string& file_path,
|
||||
STREAM_ID stream,
|
||||
bool truncate);
|
||||
};
|
||||
|
||||
log_file_manager::log_file_manager(bool native_console)
|
||||
: fn_(lg::unique_log_filename())
|
||||
, use_wincon_(console_attached())
|
||||
, created_wincon_(false)
|
||||
: created_wincon_(false)
|
||||
{
|
||||
DBG_LS << "Early init message";
|
||||
|
||||
if(use_wincon_) {
|
||||
if(GetConsoleWindow() != nullptr) {
|
||||
// Someone already attached a console to us. Assume we were compiled
|
||||
// with the console subsystem flag and that the standard streams are
|
||||
// already pointing to the console.
|
||||
LOG_LS << "Console already attached at startup, log file disabled.";
|
||||
return;
|
||||
}
|
||||
|
||||
if(native_console) {
|
||||
LOG_LS << "Console already attached at startup (built with console subsystem flag?), log file disabled.";
|
||||
} else if(native_console) {
|
||||
enable_native_console_output();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// We use the Windows temp dir on startup,
|
||||
//
|
||||
const std::string new_path = temp_dir() + "/" + fn_;
|
||||
|
||||
try {
|
||||
open_log_file(new_path, true);
|
||||
} catch(const libc_error& e) {
|
||||
log_init_panic(e, new_path, lg::get_log_file_path());
|
||||
}
|
||||
|
||||
LOG_LS << "Opened log file at " << new_path;
|
||||
}
|
||||
|
||||
log_file_manager::~log_file_manager()
|
||||
{
|
||||
if(lg::get_log_file_path().empty()) {
|
||||
// No log file, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
}
|
||||
|
||||
void log_file_manager::move_log_file(const std::string& log_dir)
|
||||
{
|
||||
const std::string new_path = log_dir + "/" + fn_;
|
||||
|
||||
try {
|
||||
if(!lg::get_log_file_path().empty()) {
|
||||
const std::string old_path = lg::get_log_file_path();
|
||||
|
||||
// Need to close files before moving or renaming. This will replace
|
||||
// the log file path with NUL, hence the backup above.
|
||||
open_log_file("NUL", false);
|
||||
|
||||
const std::wstring old_path_w = unicode_cast<std::wstring>(old_path);
|
||||
const std::wstring new_path_w = unicode_cast<std::wstring>(new_path);
|
||||
|
||||
if(_wrename(old_path_w.c_str(), new_path_w.c_str()) != 0) {
|
||||
throw libc_error();
|
||||
}
|
||||
}
|
||||
|
||||
// Reopen.
|
||||
open_log_file(new_path, false);
|
||||
} catch(const libc_error& e) {
|
||||
log_init_panic(e, new_path, lg::get_log_file_path());
|
||||
}
|
||||
|
||||
LOG_LS << "Moved log file to " << new_path;
|
||||
}
|
||||
|
||||
void log_file_manager::open_log_file(const std::string& file_path, bool truncate)
|
||||
{
|
||||
do_redirect_single_stream(file_path, STREAM_STDERR, truncate);
|
||||
do_redirect_single_stream(file_path, STREAM_STDOUT, false);
|
||||
|
||||
lg::set_log_file_path(file_path);
|
||||
}
|
||||
|
||||
void log_file_manager::do_redirect_single_stream(const std::string& file_path,
|
||||
log_file_manager::STREAM_ID stream,
|
||||
bool truncate)
|
||||
{
|
||||
DBG_LS << stream << ' ' << lg::get_log_file_path() << " -> " << file_path << " [side A]";
|
||||
|
||||
FILE* crts = stream == STREAM_STDERR ? stderr : stdout;
|
||||
std::ostream& cxxs = stream == STREAM_STDERR ? std::cerr : std::cout;
|
||||
|
||||
fflush(crts);
|
||||
cxxs.flush();
|
||||
|
||||
const std::wstring file_path_w = unicode_cast<std::wstring>(file_path);
|
||||
|
||||
if(!_wfreopen(file_path_w.c_str(), (truncate ? L"w" : L"a"), crts))
|
||||
{
|
||||
throw libc_error();
|
||||
}
|
||||
|
||||
DBG_LS << stream << ' ' << lg::get_log_file_path() << " -> " << file_path << " [side B]";
|
||||
}
|
||||
|
||||
bool log_file_manager::console_enabled() const
|
||||
{
|
||||
return use_wincon_;
|
||||
}
|
||||
|
||||
bool log_file_manager::console_attached() const
|
||||
{
|
||||
return GetConsoleWindow() != nullptr;
|
||||
DBG_LS << "Windows console init complete!";
|
||||
}
|
||||
|
||||
bool log_file_manager::owns_console() const
|
||||
|
@ -326,15 +100,8 @@ bool log_file_manager::owns_console() const
|
|||
|
||||
void log_file_manager::enable_native_console_output()
|
||||
{
|
||||
if(use_wincon_) {
|
||||
// We either went over this already or the console was set up by
|
||||
// Windows itself (console subsystem flag in executable).
|
||||
return;
|
||||
}
|
||||
|
||||
if(AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||
LOG_LS << "Attached parent process console.";
|
||||
created_wincon_ = false;
|
||||
} else if(AllocConsole()) {
|
||||
LOG_LS << "Allocated own console.";
|
||||
created_wincon_ = true;
|
||||
|
@ -364,7 +131,6 @@ void log_file_manager::enable_native_console_output()
|
|||
// 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("");
|
||||
use_wincon_ = true;
|
||||
|
||||
LOG_LS << "Console streams handover complete!";
|
||||
}
|
||||
|
@ -373,30 +139,11 @@ std::unique_ptr<log_file_manager> lfm;
|
|||
|
||||
} // end anonymous namespace
|
||||
|
||||
static bool disable_redirect;
|
||||
|
||||
void early_log_file_setup(bool disable)
|
||||
void do_console_redirect(bool native_console)
|
||||
{
|
||||
if(lfm) {
|
||||
return;
|
||||
if(!lfm) {
|
||||
lfm.reset(new log_file_manager(native_console));
|
||||
}
|
||||
|
||||
if(disable) {
|
||||
disable_redirect = true;
|
||||
return;
|
||||
}
|
||||
|
||||
lfm.reset(new log_file_manager());
|
||||
}
|
||||
|
||||
void enable_native_console_output()
|
||||
{
|
||||
if(lfm) {
|
||||
lfm->enable_native_console_output();
|
||||
return;
|
||||
}
|
||||
|
||||
lfm.reset(new log_file_manager(true));
|
||||
}
|
||||
|
||||
bool using_own_console()
|
||||
|
@ -404,35 +151,4 @@ bool using_own_console()
|
|||
return lfm && lfm->owns_console();
|
||||
}
|
||||
|
||||
void finish_log_file_setup()
|
||||
{
|
||||
if(disable_redirect) return;
|
||||
// Make sure the LFM is actually set up just in case.
|
||||
early_log_file_setup(false);
|
||||
|
||||
if(lfm->console_enabled()) {
|
||||
// Nothing to do if running in console mode.
|
||||
return;
|
||||
}
|
||||
|
||||
static bool setup_complete = false;
|
||||
|
||||
if(setup_complete) {
|
||||
ERR_LS << "finish_log_file_setup() called more than once!";
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string log_dir = filesystem::get_logs_dir();
|
||||
if(!filesystem::file_exists(log_dir) && !filesystem::make_directory(log_dir)) {
|
||||
log_init_panic(std::string("Could not create logs directory at ") +
|
||||
log_dir + ".");
|
||||
} else {
|
||||
lg::rotate_logs(log_dir);
|
||||
}
|
||||
|
||||
lfm->move_log_file(log_dir);
|
||||
|
||||
setup_complete = true;
|
||||
}
|
||||
|
||||
} // end namespace lg
|
||||
|
|
|
@ -50,27 +50,7 @@ namespace lg
|
|||
* horribly wrong as soon as we try to use the logging facilities internally
|
||||
* for debug messages.
|
||||
*/
|
||||
void early_log_file_setup(bool disable);
|
||||
|
||||
/**
|
||||
* Relocates the stdout+stderr log file to the user data directory.
|
||||
*
|
||||
* This function exits the process if something goes wrong (including calling
|
||||
* it when the user data directory isn't known yet).
|
||||
*/
|
||||
void finish_log_file_setup();
|
||||
|
||||
/**
|
||||
* Switches to using a native console instead of log file redirection.
|
||||
*
|
||||
* In this mode, the log file is closed (if it was created in the first place)
|
||||
* and output is sent directly to an attached or allocated console instead.
|
||||
* This is used to implement the --wconsole command line option.
|
||||
*
|
||||
* Using a native console instead of a file has the benefit of allowing to see
|
||||
* output in real time or redirecting it to a user-specified file.
|
||||
*/
|
||||
void enable_native_console_output();
|
||||
void do_console_redirect(bool native_console);
|
||||
|
||||
/**
|
||||
* Returns true if a console was allocated by the Wesnoth process.
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "serialization/schema_validator.hpp" // for strict_validation_enabled and schema_validator
|
||||
#include "sound.hpp" // for commit_music_changes, etc
|
||||
#include "statistics.hpp" // for fresh_stats
|
||||
#include "formula/string_utils.hpp" // VGETTEXT
|
||||
#include <functional>
|
||||
#include "game_version.hpp" // for version_info
|
||||
#include "video.hpp" // for video::error and video::quit
|
||||
|
@ -805,6 +806,13 @@ static int do_gameloop(const std::vector<std::string>& args)
|
|||
gui2::init();
|
||||
const gui2::event::manager gui_event_manager;
|
||||
|
||||
if(!lg::log_dir_writable()) {
|
||||
utils::string_map symbols;
|
||||
symbols["logdir"] = filesystem::get_logs_dir();
|
||||
std::string msg = VGETTEXT("Unable to create log files in directory $logdir. This is often caused by incorrect folder permissions, anti-virus software restricting folder access, or using OneDrive to manage your My Documents folder.", symbols);
|
||||
gui2::show_message(_("Logging Failure"), msg, gui2::dialogs::message::ok_button);
|
||||
}
|
||||
|
||||
game_config_manager config_manager(cmdline_opts);
|
||||
|
||||
if(game_config::check_migration) {
|
||||
|
@ -1049,13 +1057,11 @@ int main(int argc, char** argv)
|
|||
_putenv("FONTCONFIG_PATH=fonts");
|
||||
#endif
|
||||
|
||||
// terminal_implied means a switch that implies an interactive terminal has been used.
|
||||
// This suggests we want the output right on standard out.
|
||||
// terminal_force means output has been explicitly requested on standard out.
|
||||
// file_force means the opposite, that logging to a file was explicitly requested.
|
||||
bool terminal_implied = false, file_force = false;
|
||||
// This is optional<bool> instead of tribool because value_or() is exactly the required semantic
|
||||
std::optional<bool> terminal_force;
|
||||
// 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;
|
||||
bool write_to_log_file = true;
|
||||
|
||||
// --nobanner needs to be detected before the main command-line parsing happens
|
||||
// --log-to needs to be detected so the logging output location is set before any actual logging happens
|
||||
|
@ -1098,7 +1104,7 @@ 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_implied = true;
|
||||
terminal_force = true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -1107,27 +1113,26 @@ int main(int argc, char** argv)
|
|||
} else if(arg == "--wconsole") {
|
||||
terminal_force = true;
|
||||
} else if(arg == "--wnoredirect") {
|
||||
log_redirect = false;
|
||||
write_to_log_file = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(arg == "--no-log-to-file") {
|
||||
terminal_force = true;
|
||||
} else if(arg == "--log-to-file") {
|
||||
file_force = true;
|
||||
write_to_log_file = true;
|
||||
}
|
||||
}
|
||||
|
||||
const bool log_to_terminal = terminal_force.value_or(terminal_implied);
|
||||
#ifdef _WIN32
|
||||
if(log_to_terminal) {
|
||||
lg::enable_native_console_output();
|
||||
}
|
||||
lg::early_log_file_setup(!log_redirect);
|
||||
#else
|
||||
if(!log_to_terminal || file_force) {
|
||||
// setup logging to file
|
||||
// else handle redirecting the output and/or attaching a console
|
||||
if(write_to_log_file && !terminal_force) {
|
||||
lg::set_log_to_file();
|
||||
}
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
lg::do_console_redirect(terminal_force);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Is there a reason not to just use SDL_INIT_EVERYTHING?
|
||||
if(SDL_Init(SDL_INIT_TIMER) < 0) {
|
||||
|
|
Loading…
Add table
Reference in a new issue