Add --log-file command line argument to write output log to a file

This works even if file logging is disabled in the project settings,
or for the editor/project manager.

`--log-file`'s value can be an absolute path or relative to the project
directory (similar to existing arguments like `--write-movie`).
This commit is contained in:
Hugo Locurcio 2024-01-19 14:39:00 +01:00
parent 0bcc0e92b3
commit 6e5e7b8cb7
No known key found for this signature in database
GPG key ID: 39E8F8BE30B0A49C
5 changed files with 38 additions and 9 deletions

View file

@ -433,16 +433,18 @@
If canvas item redraw debugging is active, this will be the time the flash will last each time they redraw. If canvas item redraw debugging is active, this will be the time the flash will last each time they redraw.
</member> </member>
<member name="debug/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false"> <member name="debug/file_logging/enable_file_logging" type="bool" setter="" getter="" default="false">
If [code]true[/code], logs all output to files. If [code]true[/code], logs all output and error messages to files. See also [member debug/file_logging/log_path], [member debug/file_logging/max_log_files], and [member application/run/flush_stdout_on_print].
</member> </member>
<member name="debug/file_logging/enable_file_logging.pc" type="bool" setter="" getter="" default="true"> <member name="debug/file_logging/enable_file_logging.pc" type="bool" setter="" getter="" default="true">
Desktop override for [member debug/file_logging/enable_file_logging], as log files are not readily accessible on mobile/Web platforms. Desktop override for [member debug/file_logging/enable_file_logging], as log files are not readily accessible on mobile/Web platforms.
</member> </member>
<member name="debug/file_logging/log_path" type="String" setter="" getter="" default="&quot;user://logs/godot.log&quot;"> <member name="debug/file_logging/log_path" type="String" setter="" getter="" default="&quot;user://logs/godot.log&quot;">
Path at which to store log files for the project. Using a path under [code]user://[/code] is recommended. Path at which to store log files for the project. Using a path under [code]user://[/code] is recommended.
This can be specified manually on the command line using the [code]--log-file &lt;file&gt;[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]. If this command line argument is specified, log rotation is automatically disabled (see [member debug/file_logging/max_log_files]).
</member> </member>
<member name="debug/file_logging/max_log_files" type="int" setter="" getter="" default="5"> <member name="debug/file_logging/max_log_files" type="int" setter="" getter="" default="5">
Specifies the maximum number of log files allowed (used for rotation). Specifies the maximum number of log files allowed (used for rotation). Set to [code]1[/code] to disable log file rotation.
If the [code]--log-file &lt;file&gt;[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url] is used, log rotation is always disabled.
</member> </member>
<member name="debug/gdscript/warnings/assert_always_false" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/assert_always_false" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to false. When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to false.

View file

@ -172,6 +172,7 @@ static bool editor = false;
static bool project_manager = false; static bool project_manager = false;
static bool cmdline_tool = false; static bool cmdline_tool = false;
static String locale; static String locale;
static String log_file;
static bool show_help = false; static bool show_help = false;
static uint64_t quit_after = 0; static uint64_t quit_after = 0;
static OS::ProcessID editor_pid = 0; static OS::ProcessID editor_pid = 0;
@ -450,7 +451,9 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --text-driver <driver> Text driver (Fonts, BiDi, shaping).\n"); OS::get_singleton()->print(" --text-driver <driver> Text driver (Fonts, BiDi, shaping).\n");
OS::get_singleton()->print(" --tablet-driver <driver> Pen tablet input driver.\n"); OS::get_singleton()->print(" --tablet-driver <driver> Pen tablet input driver.\n");
OS::get_singleton()->print(" --headless Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script.\n"); OS::get_singleton()->print(" --headless Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script.\n");
OS::get_singleton()->print(" --write-movie <file> Writes a video to the specified path (usually with .avi or .png extension).\n"); OS::get_singleton()->print(" --log-file <file> Write output/error log to the specified path instead of the default location defined by the project.\n");
OS::get_singleton()->print(" <file> path should be absolute or relative to the project directory.\n");
OS::get_singleton()->print(" --write-movie <file> Write a video to the specified path (usually with .avi or .png extension).\n");
OS::get_singleton()->print(" --fixed-fps is forced when enabled, but it can be used to change movie FPS.\n"); OS::get_singleton()->print(" --fixed-fps is forced when enabled, but it can be used to change movie FPS.\n");
OS::get_singleton()->print(" --disable-vsync can speed up movie writing but makes interaction more difficult.\n"); OS::get_singleton()->print(" --disable-vsync can speed up movie writing but makes interaction more difficult.\n");
OS::get_singleton()->print(" --quit-after can be used to specify the number of frames to write.\n"); OS::get_singleton()->print(" --quit-after can be used to specify the number of frames to write.\n");
@ -1165,6 +1168,15 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
audio_driver = NULL_AUDIO_DRIVER; audio_driver = NULL_AUDIO_DRIVER;
display_driver = NULL_DISPLAY_DRIVER; display_driver = NULL_DISPLAY_DRIVER;
} else if (I->get() == "--log-file") { // write to log file
if (I->next()) {
log_file = I->next()->get();
N = I->next()->next();
} else {
OS::get_singleton()->print("Missing log file path argument, aborting.\n");
goto error;
}
} else if (I->get() == "--profiling") { // enable profiling } else if (I->get() == "--profiling") { // enable profiling
use_debug_profiler = true; use_debug_profiler = true;
@ -1689,12 +1701,24 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF("debug/file_logging/log_path", "user://logs/godot.log"); GLOBAL_DEF("debug/file_logging/log_path", "user://logs/godot.log");
GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater"), 5); GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater"), 5);
if (!project_manager && !editor && FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) && // If `--log-file` is used to override the log path, allow creating logs for the project manager or editor
GLOBAL_GET("debug/file_logging/enable_file_logging")) { // and even if file logging is disabled in the Project Settings.
// `--log-file` can be used with any path (including absolute paths outside the project folder),
// so check for filesystem access if it's used.
if (FileAccess::get_create_func(!log_file.is_empty() ? FileAccess::ACCESS_FILESYSTEM : FileAccess::ACCESS_USERDATA) &&
(!log_file.is_empty() || (!project_manager && !editor && GLOBAL_GET("debug/file_logging/enable_file_logging")))) {
// Don't create logs for the project manager as they would be written to // Don't create logs for the project manager as they would be written to
// the current working directory, which is inconvenient. // the current working directory, which is inconvenient.
String base_path = GLOBAL_GET("debug/file_logging/log_path"); String base_path;
int max_files = GLOBAL_GET("debug/file_logging/max_log_files"); int max_files;
if (!log_file.is_empty()) {
base_path = log_file;
// Ensure log file name respects the specified override by disabling log rotation.
max_files = 1;
} else {
base_path = GLOBAL_GET("debug/file_logging/log_path");
max_files = GLOBAL_GET("debug/file_logging/max_log_files");
}
OS::get_singleton()->add_logger(memnew(RotatedFileLogger(base_path, max_files))); OS::get_singleton()->add_logger(memnew(RotatedFileLogger(base_path, max_files)));
} }

View file

@ -51,7 +51,8 @@ _arguments \
'--text-driver[set the text driver]:text driver name' \ '--text-driver[set the text driver]:text driver name' \
'--tablet-driver[set the pen tablet input driver]:tablet driver name' \ '--tablet-driver[set the pen tablet input driver]:tablet driver name' \
'--headless[enable headless mode (--display-driver headless --audio-driver Dummy), useful for servers and with --script]' \ '--headless[enable headless mode (--display-driver headless --audio-driver Dummy), useful for servers and with --script]' \
'--write-movie[writes a video to the specified path (usually with .avi or .png extension)]:path to output video file' \ '--log-file[write output/error log to the specified path instead of the default location defined by the project]:path to output log file' \
'--write-movie[write a video to the specified path (usually with .avi or .png extension)]:path to output video file' \
'(-f --fullscreen)'{-f,--fullscreen}'[request fullscreen mode]' \ '(-f --fullscreen)'{-f,--fullscreen}'[request fullscreen mode]' \
'(-m --maximized)'{-m,--maximized}'[request a maximized window]' \ '(-m --maximized)'{-m,--maximized}'[request a maximized window]' \
'(-w --windowed)'{-w,--windowed}'[request windowed mode]' \ '(-w --windowed)'{-w,--windowed}'[request windowed mode]' \

View file

@ -54,6 +54,7 @@ _complete_godot_options() {
--text-driver --text-driver
--tablet-driver --tablet-driver
--headless --headless
--log-file
--write-movie --write-movie
--fullscreen --fullscreen
--maximized --maximized

View file

@ -67,7 +67,8 @@ complete -c godot -l gpu-index -d "Use a specific GPU (run with --verbose to get
complete -c godot -l text-driver -d "Set the text driver" -x complete -c godot -l text-driver -d "Set the text driver" -x
complete -c godot -l tablet-driver -d "Set the pen tablet input driver" -x complete -c godot -l tablet-driver -d "Set the pen tablet input driver" -x
complete -c godot -l headless -d "Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script" complete -c godot -l headless -d "Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script"
complete -c godot -l write-movie -d "Writes a video to the specified path (usually with .avi or .png extension). --fixed-fps is forced when enabled" -x complete -c godot -l log-file -d "Write output/error log to the specified path instead of the default location defined by the project" -x
complete -c godot -l write-movie -d "Write a video to the specified path (usually with .avi or .png extension). --fixed-fps is forced when enabled" -x
# Display options: # Display options:
complete -c godot -s f -l fullscreen -d "Request fullscreen mode" complete -c godot -s f -l fullscreen -d "Request fullscreen mode"