日志
Godot 提供了多种方式来组织和收集日志消息。
打印消息
参见
有关打印消息的说明,请参阅:ref:doc_output_panel_printing_messages。打印输出的内容通常与日志输出内容一致。
When running a project from the editor, the editor will display logged text in the 输出面板.
项目设置
There are several project settings to control logging behavior in Godot:
应用程序 > 运行 > 禁用标准输出(Application > Run > Disable stdout): 完全禁用向标准输出的日志记录。这也会影响自定义日志记录器接收到的内容。可在运行时通过设置:ref:`Engine.print_to_stdout <class_Engine_property_print_to_stdout>`来控制此选项。
应用程序 > 运行 > 禁用标准错误(Application > Run > Disable stderr): 完全禁用向标准错误输出的日志记录。这也会影响自定义日志记录器接收到的内容。可在运行时通过设置:ref:`Engine.print_error_messages <class_Engine_property_print_error_messages>`来控制此选项。
调试 > 设置 > 标准输出 > 详细标准输出(Debug > Settings > stdout > Verbose stdout): 启用向标准输出的详细日志记录。仅当启用详细模式时,:ref:`print_verbose() <class_@GlobalScope_method_print_verbose>`的输出内容才会显示。
调试 > 设置 > 标准输出 > 打印 FPS(Debug > Settings > stdout > Print FPS): 每秒打印一次帧率(FPS),并在启动时打印垂直同步(V-Sync)状态(因为它可能有效限制最大帧率)。
调试 > 设置 > 标准输出 > 打印 GPU 性能分析(Debug > Settings > stdout > Print GPU Profile): 每秒打印一次 GPU 使用情况报告,数据来源与 :ref:`doc_debugger_panel_visual_profiler`相同。
这些项目设置中的一部分也可以通过 command line arguments 进行覆盖,例如 --quiet``(静默模式)、--verbose``(详细模式)和 ``--print-fps``(打印帧率)。
引擎自身的文件日志记录功能也可进行配置,具体说明见下文。
Built-in file logging
By default, Godot writes log files in user://logs/godot.log on desktop
platforms. You can change this location by modifying the
debug/file_logging/log_path project setting. Logs are rotated to keep older
files available for inspection. Each session creates a new log file, with the
old file renamed to contain the date at which it was rotated. Up to 5 log files
are kept by default, which can be adjusted using the
debug/file_logging/max_log_files project setting.
File logging can also be disabled completely using the
debug/file_logging/enable_file_logging project setting.
When the project crashes, crash logs are written to the same file as the log file. The crash log will only contain a usable backtrace if the binary that was run contains debugging symbols, or if it can find a debug symbols file that matches the binary. Official binaries don't provide debugging symbols, so this requires a custom build to work. See Debugging symbols for guidance on compiling binaries with debugging symbols enabled.
备注
Log files for print() statements are updated when standard output is flushed by the engine. Standard output is flushed on every print in debug builds only. In projects that are exported in release mode, standard output is only flushed when the project exits or crashes to improve performance, especially if the project is often printing text to standard output.
On the other hand, the standard error stream (used by printerr(), push_error(), and push_warning()) is always flushed on every print, even in projects exported in release mode.
For some use cases like dedicated servers, it can be preferred to have release
builds always flush stdout on print, so that logging services like journald can
collect logs while the process is running. This can be done by enabling
application/run/flush_stdout_on_print in the Project Settings.
Script backtraces
自 Godot 4.5 起,当 GDScript 代码遇到错误时,会记录一个指向错误源头的回溯信息(backtrace),并包含导致该错误的调用栈。此功能在编辑器内运行或项目以调试模式导出时始终启用。
在以发布模式导出的项目中,出于性能考虑,默认禁用回溯功能。您可以通过在项目设置中勾选 调试 > 设置 > GDScript > 始终跟踪调用栈(Debug > Settings > GDScript > Always Track Call Stacks) 来启用该功能。如果您使用自定义日志系统将异常上报至远程服务,建议启用此选项,以便让上报的错误信息更具可操作性。
崩溃回溯
警告
崩溃回溯仅在包含 debugging symbols 的构建版本中才有实际意义。官方发布的 Godot 二进制文件不包含调试符号,因此您必须自行编译自定义的编辑器或导出模板二进制文件,才能获得有用的崩溃回溯信息。
当项目崩溃时,崩溃回溯信息会被打印到标准错误流。在包含调试符号的构建版本中,其输出可能如下所示:
================================================================
handle_crash: Program crashed with signal 4
Engine version: Godot Engine v4.5.beta.custom_build (6c9aa4c7d3b9b91cd50714c40eeb234874df7075)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /lib64/libc.so.6(+0x1a070) [0x7f6e5e277070] (??:0)
[2] godot() [0x4da3358] (/path/to/godot/core/core_bind.cpp:336 (discriminator 2))
[3] godot() [0xdf5f2f] (/path/to/godot/modules/gdscript/gdscript.h:591)
[4] godot() [0xbffd46] (/path/to/godot/modules/gdscript/gdscript.cpp:2065 (discriminator 1))
[5] godot() [0x30f2ea4] (/path/to/godot/core/variant/variant.h:870)
[6] godot() [0x550d4e1] (/path/to/godot/core/object/object.cpp:933)
[7] godot() [0x30d996a] (/path/to/godot/scene/main/node.cpp:318 (discriminator 1))
[8] godot() [0x3131a7f] (/path/to/godot/core/templates/hash_map.h:465)
[9] godot() [0x424589] (/path/to/godot/platform/linuxbsd/os_linuxbsd.cpp:970)
[10] /lib64/libc.so.6(+0x3575) [0x7f6e5e260575] (??:0)
[11] /lib64/libc.so.6(__libc_start_main+0x88) [0x7f6e5e260628] (??:0)
[12] godot() [0x464df5] (??:?)
-- END OF C++ BACKTRACE --
================================================================
GDScript backtrace (most recent call first):
[0] _ready (res://test.gd:5)
-- END OF GDSCRIPT BACKTRACE --
================================================================
另一方面,如果没有调试符号,输出将如下所示:
================================================================
handle_crash: Program crashed with signal 4
Engine version: Godot Engine v4.5.beta.custom_build (6c9aa4c7d3b9b91cd50714c40eeb234874df7075)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /lib64/libc.so.6(+0x1a070) [0x7fdfaf666070] (??:0)
[2] godot() [0x4da3358] (??:0)
[3] godot() [0xdf5f2f] (??:0)
[4] godot() [0xbffd46] (??:0)
[5] godot() [0x30f2ea4] (??:0)
[6] godot() [0x550d4e1] (??:0)
[7] godot() [0x30d996a] (??:0)
[8] godot() [0x3131a7f] (??:0)
[9] godot() [0x424589] (??:0)
[10] /lib64/libc.so.6(+0x3575) [0x7fdfaf64f575] (??:0)
[11] /lib64/libc.so.6(__libc_start_main+0x88) [0x7fdfaf64f628] (??:0)
[12] godot() [0x464df5] (??:0)
-- END OF C++ BACKTRACE --
================================================================
GDScript backtrace (most recent call first):
[0] _ready (res://test.gd:5)
-- END OF GDSCRIPT BACKTRACE --
================================================================
此回溯信息也会被记录到当前会话的日志文件中,但 not 显示在编辑器的输出面板中。由于引擎崩溃时脚本系统已停止运行,因此无法在同一次会话中通过脚本访问该信息。不过,您仍可在下一次会话中通过加载日志文件,并使用 FileAccess 搜索崩溃回溯字符串(Program crashed with signal)来读取崩溃回溯内容。只要用户重新启动项目且已启用文件日志记录,即可在崩溃后获取回溯信息:
# This script can be made an autoload, so that it runs when the project starts.
extends Node
func _ready() -> void:
var log_dir: String = String(ProjectSettings.get_setting("debug/file_logging/log_path")).get_base_dir()
# Get the last log file by alphabetical order.
# Since the timestamp is featured in the file name, it should always be the most recent
# log file that was rotated. The non-timestamped log file is for the current session,
# so we don't want to read that one.
var last_log_file: String = log_dir.path_join(DirAccess.get_files_at(log_dir)[-1])
var last_long_contents: String = FileAccess.get_file_as_string(last_log_file)
var crash_begin_idx: int = last_long_contents.find("Program crashed with signal")
if crash_begin_idx != -1:
print("The previous session has crashed with the following backtrace:\n")
print(last_long_contents.substr(crash_begin_idx))
您可以通过 调试 > 设置 > 崩溃处理器 > 消息(Debug > Settings > Crash Handler > Message) 项目设置,自定义回溯信息顶部显示的消息内容。此功能可用于引导用户访问指定的网址或邮箱地址,以便提交问题反馈。
Creating custom loggers
自 Godot 4.5 起,可以创建自定义日志记录器。自定义日志功能可用于多种用途:
在游戏内显示一个控制台,展示与引擎输出相同的消息,而无需修改其他脚本。
将玩家设备上打印的错误信息上报至远程服务器。这有助于开发者在游戏已发布或进行试玩测试时更便捷地修复错误。
将专用服务器导出版本与监控平台集成。
可通过创建一个继承自 Logger 的类来注册自定义日志记录器,然后在脚本的 OS.add_logger 方法中,将该类的实例传递给 _init()。一个合适的实现位置是 autoload。
该类必须定义两个方法:_log_message() 和 _log_error()。
以下是一个最小可运行的自定义日志记录器示例,该脚本已作为自动加载(autoload)添加:
extends Node
class CustomLogger extends Logger:
# Note that this method is not called for messages that use
# `push_error()` and `push_warning()`, even though these are printed to stderr.
func _log_message(message: String, error: bool) -> void:
# Do something with `message`.
# `error` is `true` for messages printed to the standard error stream (stderr) with `print_error()`.
# Note that this method will be called from threads other than the main thread, possibly at the same
# time, so you will need to have some kind of thread-safety as part of it, like a Mutex.
pass
func _log_error(
function: String,
file: String,
line: int,
code: String,
rationale: String,
editor_notify: bool,
error_type: int,
script_backtraces: Array[ScriptBacktrace]
) -> void:
# Do something with the error. The error text is in `rationale`.
# See the Logger class reference for details on other parameters.
# Note that this method will be called from threads other than the main thread, possibly at the same
# time, so you will need to have some kind of thread-safety as part of it, like a Mutex.
pass
# Use `_init()` to initialize the logger as early as possible, which ensures that messages
# printed early are taken into account. However, even when using `_init()`, the engine's own
# initialization messages are not accessible.
func _init() -> void:
OS.add_logger(CustomLogger.new())
请注意,为避免无限递归,在 _log_message() 中不能有效使用 print() 及其相关方法;同样,在 _log_error() 中也不能有效使用 push_error() 或 push_warning()。若尝试这样做,消息将被输出到与原始消息相同的流中,而该消息对自定义日志记录器不可见,这正是防止无限递归发生的原因:
While attempting to print a message, another message was printed:
...
While attempting to print an error, another error was printed:
...
参见
You can find an example of an in-game console built with a custom logger in the Custom Logging demo project.