Godot 引擎 Logger 类完全指南:拦截内部错误/警告流,打造自定义日志与错误上报系统
文档教程游戏开发【免费下载链接】godot-docsGodot Engine official documentation项目地址https://gitcode.com/GitHub_Trending/go/godot-docs点击查看免费下载Godot 4.5 起引擎引入了Logger类允许开发者以自定义对象接管引擎内部错误/警告消息流实现游戏内控制台、远程错误上报、专用服务器日志监控等能力。本文以 Logger 类参考 为主线结合 日志教程 与OS、Engine、ScriptBacktrace、ProjectSettings等关联类参考系统讲解Logger的虚方法签名、ErrorType枚举、注册/注销机制、线程安全约束、防递归陷阱及配套项目设置读完即可写出可落地的自定义日志器。一、Logger 是什么接入引擎内部消息流的自定义日志器Logger继承自RefCounted再往上为Object官方描述为Custom logger to receive messages from the internal error/warning stream.即自定义日志器用于接收来自引擎内部错误/警告流internal error/warning stream的消息。它本身不产生日志而是提供一个被引擎回调的挂钩hook接口让开发者能旁路监听引擎与脚本打印的所有内容。关键注册入口在 OS 类OS.add_logger(logger)注册一个自定义 Logger拦截内部消息流见 add_logger 定义OS.remove_logger(logger)注销之前注册的自定义 Logger见 remove_logger 定义。也就是说引擎默认的日志行为写入 stdout/stderr、写文件、编辑器输出面板不会被替换自定义 Logger 是在其上叠加的额外接收器。这也是它与内置文件日志user://logs/godot.log的本质区别文件日志是引擎内置输出目标而Logger是开发者自建的输入管道。二、ErrorType 枚举错误类型的四种语义Logger定义了唯一的枚举ErrorType用于在_log_error()回调中标识错误种类常量值含义ERROR_TYPE_ERROR0接收到的消息是一条错误errorERROR_TYPE_WARNING1接收到的消息是一条警告warningERROR_TYPE_SCRIPT2接收到的消息是一条脚本错误script errorERROR_TYPE_SHADER3接收到的消息是一条着色器错误shader error注意error_type参数的类型是int在_log_error()中可通过与上述常量比较来分发处理逻辑例如把脚本错误与引擎错误区分开、单独上报。三、必须重写的两个虚方法自定义 Logger 的核心在于重写以下两个virtual方法它们是引擎回调的唯二入口。3.1_log_message(message: String, error: bool)当一条普通消息被打印时回调void _log_message(message: String, error: bool) # virtualmessage日志正文error若为true表示该消息本意是发往stderr标准错误流的。实战中可借此捕获print()、printerr()等的输出用于实现游戏内控制台——游戏内 UI 无需任何其他脚本配合就能显示与引擎完全一致的输出。3.2_log_error(function, file, line, code, rationale, editor_notify, error_type, script_backtraces)当一条错误被记录时回调携带错误产生的上下文信息参数类型含义functionString产生错误的函数名fileString产生错误的源文件lineint产生错误所在的行号codeString产生该错误的代码片段与rationale二选一提供rationaleString错误的说明文本reason例如push_error()传入的字符串editor_notifybool该错误是否需要在编辑器中弹出/提示error_typeint错误类型取值见上文ErrorType枚举script_backtracesArray[ScriptBacktrace]各脚本语言的回溯栈backtrace数组关于script_backtraces的三个要点默认仅编辑器/调试构建包含栈帧。只有 editor builds 与 debug builds 默认记录脚本调用栈若要在 release 导出包中也启用需要打开项目设置debug/settings/gdscript/always_track_call_stacks默认false见 ProjectSettings 参考。不包含捕获的变量值。由于代价过高script_backtraces不会携带局部变量/成员变量的值。若确需变量信息应在Logger虚方法内部自行调用Engine.capture_script_backtraces()主动捕获该方法支持include_variables参数见 Engine 参考。由多个脚本语言分别提供。数组中的每个 ScriptBacktrace 代表一种脚本语言如 GDScript、C#捕获到的回溯可通过其format()、get_frame_count()、get_frame_file()等方法格式化与遍历。四、实战从零实现并注册一个自定义 Logger4.1 最小实现官方 日志教程 给出了最小可用示例——把脚本设为 autoload 单例在_init()中尽早注册extends Node class CustomLogger extends Logger: # 注意push_error() 与 push_warning() 打印的消息不会进入本方法 # 即使它们同样输出到 stderr。 func _log_message(message: String, error: bool) - void: # 在这里处理 message。 # error 为 true 表示消息来自 stderr如 print_error()。 # 注意本方法可能被主线程以外的线程同时调用 # 因此需要自备线程安全机制例如 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: # 在这里处理错误错误文本在 rationale 中。 # 其余参数含义见 Logger 类参考。 # 注意同样需要线程安全。 pass # 使用 _init() 尽早初始化确保早期打印的消息也能被捕获。 # 即使如此引擎自身初始化阶段的消息仍不可见。 func _init() - void: OS.add_logger(CustomLogger.new())4.2 注册时机的选择_init()是官方推荐时机节点脚本的_init()在场景实例化早期执行能覆盖尽量多的启动日志。但无论多早引擎自身的初始化消息如版本 banner、渲染设备信息都不会进入自定义 Logger因为这些消息发生在脚本系统启动之前。若在 autoload 之外使用应确保 Logger 实例在OS.add_logger()调用后一直存活——由于Logger继承RefCounted在 GDScript 侧只要保持引用例如作为 autoload 的属性或单例内部持有即可避免被回收。4.3 线程安全回调可能来自任意线程_log_message与_log_error的文档中都带有同样的警告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 in your implementation.引擎的线程如WorkerThreadPool、渲染线程、资源加载线程都会打印消息因此回调可能并发、可能不在主线程。实现里必须自带同步机制最直接的做法是配合 Mutex 类extends Node class CustomLogger extends Logger: var _mutex : Mutex.new() var _buffer: PackedStringArray [] func _log_message(message: String, error: bool) - void: _mutex.lock() _buffer.append(message) _mutex.unlock() func _log_error( function: String, file: String, line: int, code: String, rationale: String, editor_notify: bool, error_type: int, script_backtraces: Array[ScriptBacktrace] ) - void: _mutex.lock() _buffer.append(ERROR(%d) %s %s:%d % [error_type, rationale, file, line]) _mutex.unlock() func get_buffer() - PackedStringArray: _mutex.lock() var result : _buffer.duplicate() _mutex.unlock() return result随后在 autoload 中注册func _init() - void: OS.add_logger(CustomLogger.new())主线程的 UI 可以定时调用get_buffer()把新消息渲染到游戏内控制台而不会与后台线程产生数据竞争。五、进阶结合回溯栈做远程错误上报Logger最有价值的场景之一是把玩家设备上发生的错误连同调用栈上报到远程服务。此时script_backtraces的完整度至关重要开发/调试期栈帧默认开启开箱即用release 导出默认关闭以提升性能需在 Project Settings 勾选Debug Settings GDScript Always Track Call Stacks对应设置键debug/settings/gdscript/always_track_call_stacks后才会携带栈帧。官方日志教程明确建议凡使用自定义日志系统向远程服务上报异常的项目都应开启该选项让上报的错误更可操作。若需要变量值级别的现场信息script_backtraces不会提供成本过高。正确姿势是在_log_error()内部主动捕获func _log_error( function: String, file: String, line: int, code: String, rationale: String, editor_notify: bool, error_type: int, script_backtraces: Array[ScriptBacktrace] ) - void: var detailed : Engine.capture_script_backtraces(true) # 含全局/局部/成员变量 # 注意include_variablestrue 时返回的回溯可能持有对象引用 # 长期保存会阻止这些对象被释放一般不建议持久化。Engine.capture_script_backtraces(include_variables: bool false)会从所有已注册脚本语言捕获回溯见 Engine 方法参考。捕获到的 ScriptBacktrace 对象可用format()直接格式化为字符串indent_all、indent_frames控制缩进to_string()等价于默认参数调用或用get_frame_count()/get_frame_file()/get_frame_function()/get_frame_line()逐帧遍历。六、防递归陷阱回调内禁止再次打印Logger的回调发生在引擎消息分发路径上因此在回调内再次使用打印函数会触发无限递归。两个方法各有明确禁令_log_message()内不能有效使用print()及其相关方法_log_error()内不能有效使用push_error()或push_warning()。引擎对此有保护机制当你违规打印时输出不会进入自定义 Logger而是在控制台显示如下提示见 日志教程While attempting to print a message, another message was printed: ... While attempting to print an error, another error was printed: ...这正是引擎阻止递归的方式——二次打印的消息被旁路到控制台不再回到 Logger 回调。因此想边接收边转发时必须把消息写入自己的缓冲区或文件如上面的_buffer方案而不是在回调内直接print()。写入文件同样建议使用异步队列或自建线程避免在回调内做阻塞 I/O。七、配套的项目设置掌握引擎日志的整体开关自定义 Logger 接收的是引擎消息流因此受全局打印开关影响。以下是 日志教程 整理、与 Logger 行为直接相关的设置项目设置作用Application Run Disable stdout完全禁用标准输出日志同时影响自定义 Logger 收到的消息运行时等价属性为Engine.print_to_stdout默认true见 Engine 参考Application Run Disable stderr完全禁用标准错误日志同样影响自定义 Logger运行时等价属性为Engine.print_error_messages默认true见 Engine 参考Debug Settings stdout Verbose stdout启用 verbose 日志输出print_verbose()的消息只有开启后才会出现见 GlobalScope.print_verboseDebug Settings stdout Print FPS每秒打印帧率并在启动时打印 V-Sync 状态Debug Settings stdout Print GPU Profile每秒打印 GPU 利用率报告这些设置也可用命令行参数覆盖如--quiet、--verbose、--print-fps。内置文件日志与自定义 Logger 互补引擎自带的文件日志由以下设置控制见 ProjectSettings 参考设置键默认值说明debug/file_logging/log_pathuser://logs/godot.log桌面平台日志文件路径命令行--log-file file可覆盖且指定后自动关闭日志轮转debug/file_logging/max_log_files5保留的轮转日志文件数量上限debug/file_logging/enable_file_loggingfalse是否把所有输出与错误消息写入文件桌面平台覆盖项.pc默认true移动/Web 平台日志文件不可直接访问文件日志按会话轮转每次运行创建新日志文件旧文件被重命名为带日期的时间戳名默认最多保留 5 个。崩溃时回溯也会写入同一日志文件但回溯仅在含调试符号的自定义构建中才可用官方二进制不提供调试符号。八、典型应用场景小结综合 Logger 类参考 与 日志教程自定义 Logger 的典型用途包括游戏内控制台用_log_message捕获引擎与脚本的全部输出渲染到游戏 UI无需改动任何既有脚本远程错误上报用_log_error捕获function/file/line/rationale与script_backtraces上报到服务端便于发布后的缺陷定位与试玩阶段的质量反馈专用服务器监控把 dedicated server 导出的日志接入监控平台配合Engine.print_to_stdout、Engine.print_error_messages及application/run/flush_stdout_on_printrelease 导出下强制每次 print 冲刷 stdout便于 journald 等日志服务实时采集使用。官方还在godot-demo-projects仓库的misc/custom_logging目录提供了基于自定义 Logger 的游戏内控制台 demo可作为进阶参考。掌握Logger两个虚方法、ErrorType枚举、线程安全与防递归约束你就能把 Godot 的日志体系从黑盒文件升级为完全可控的工程化基础设施。赞分享文档教程游戏开发【免费下载链接】godot-docsGodot Engine official documentation项目地址https://gitcode.com/GitHub_Trending/go/godot-docs点击查看免费下载相关推荐Puma自定义错误日志异常分类与告警策略Puma自定义错误日志异常分类与告警策略 你是否还在为应用崩溃时难以定位问题而烦恼当用户投诉页面打不开时默认日志是否只能提供模糊的错误提示本文将带你后端网络CANN Runtime 错误上报接口Error Reporting APIs完全指南从内部错误到自定义错误码的注册与上报CANN Runtime 错误上报接口Error Reporting APIs完全指南从内部错误到自定义错误码的注册与上报 CANN Runtime 的错CANNAscend人工智能性能剖析系统编程BV日志系统结构化日志与远程错误报告BV日志系统结构化日志与远程错误报告 引言为什么需要专业的日志系统 在开发复杂的Android应用时特别是像BV这样的哔哩哔哩第三方客户端日志系统的重移动开发音视频上一篇CAI Bug Bounter 代理system_bug_bounter.md 漏洞赏金猎取系统提示词深度解析下一篇ONNX 模型仓库 DenseNet-121 全解析模型变体、输入输出协议与 INT8 量化实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考