|
| 1 | +.. _doc_logging: |
| 2 | + |
| 3 | +Logging |
| 4 | +======= |
| 5 | + |
| 6 | +Godot comes with several ways to organize and collect log messages. |
| 7 | + |
| 8 | +Printing messages |
| 9 | +----------------- |
| 10 | + |
| 11 | +.. seealso:: |
| 12 | + |
| 13 | + See :ref:`doc_output_panel_printing_messages` for instructions on printing |
| 14 | + messages. The printed output is generally identical to the logged output. |
| 15 | + |
| 16 | + When running a project from the editor, the editor will display logged text |
| 17 | + in the :ref:`doc_output_panel`. |
| 18 | + |
| 19 | +Project settings |
| 20 | +---------------- |
| 21 | + |
| 22 | +There are several project settings to control logging behavior in Godot: |
| 23 | + |
| 24 | +- **Application > Run > Disable stdout:** Disables logging to standard output entirely. |
| 25 | + This also affects what custom loggers receive. This can be controlled at runtime |
| 26 | + by setting :ref:`Engine.print_to_stdout <class_Engine_property_print_to_stdout>`. |
| 27 | +- **Application > Run > Disable stderr:** Disables logging to standard error entirely. |
| 28 | + This also affects what custom loggers receive. This can be controlled at runtime |
| 29 | + by setting :ref:`Engine.print_error_messages <class_Engine_property_print_error_messages>`. |
| 30 | +- **Debug > Settings > stdout > Verbose stdout:** Enables verbose logging to standard output. |
| 31 | + Prints from :ref:`print_verbose() <class_@GlobalScope_method_print_verbose>` are only |
| 32 | + visible if verbose mode is enabled. |
| 33 | +- **Debug > Settings > stdout > Print FPS:** Prints the frames per second every second, |
| 34 | + as well as the V-Sync status on startup (as it can effectively cap the maximum framerate). |
| 35 | +- **Debug > Settings > stdout > Print GPU Profile:** Prints a report of GPU utilization |
| 36 | + every second, using the same data source as the :ref:`doc_debugger_panel_visual_profiler`. |
| 37 | + |
| 38 | +Some of these project settings can also be overridden using |
| 39 | +:ref:`command line arguments <doc_command_line_tutorial>` such as ``--quiet``, |
| 40 | +``--verbose`` and ``--print-fps``. |
| 41 | + |
| 42 | +The engine's own file logging is also configurable, as described in the section below. |
| 43 | + |
| 44 | +Built-in file logging |
| 45 | +--------------------- |
| 46 | + |
| 47 | +By default, Godot writes log files in ``user://logs/godot.log`` on desktop |
| 48 | +platforms. You can change this location by modifying the |
| 49 | +``debug/file_logging/log_path`` project setting. Logs are rotated to keep older |
| 50 | +files available for inspection. Each session creates a new log file, with the |
| 51 | +old file renamed to contain the date at which it was rotated. Up to 5 log files |
| 52 | +are kept by default, which can be adjusted using the |
| 53 | +``debug/file_logging/max_log_files`` project setting. |
| 54 | + |
| 55 | +File logging can also be disabled completely using the |
| 56 | +``debug/file_logging/enable_file_logging`` project setting. |
| 57 | + |
| 58 | +When the project crashes, crash logs are written to the same file as the log |
| 59 | +file. The crash log will only contain a usable backtrace if the binary that was |
| 60 | +run contains debugging symbols, or if it can find a debug symbols file that |
| 61 | +matches the binary. Official binaries don't provide debugging symbols, so this |
| 62 | +requires a custom build to work. See |
| 63 | +:ref:`Debugging symbols <doc_introduction_to_the_buildsystem_debugging_symbols>`. |
| 64 | +for guidance on compiling binaries with debugging symbols enabled. |
| 65 | + |
| 66 | +.. note:: |
| 67 | + |
| 68 | + Log files for :ref:`print() <class_@GlobalScope_method_print>` |
| 69 | + statements are updated when standard output is *flushed* by the engine. |
| 70 | + Standard output is flushed on every print in debug builds only. In projects that |
| 71 | + are exported in release mode, standard output is only flushed when the project exits |
| 72 | + or crashes to improve performance, especially if the project is often printing |
| 73 | + text to standard output. |
| 74 | + |
| 75 | + On the other hand, the standard error stream |
| 76 | + (used by :ref:`printerr() <class_@GlobalScope_method_printerr>`, |
| 77 | + :ref:`push_error() <class_@GlobalScope_method_push_error>` and |
| 78 | + :ref:`push_warning() <class_@GlobalScope_method_push_warning>`) is always |
| 79 | + flushed on every print, even in projects exported in release mode. |
| 80 | + |
| 81 | + For some use cases like dedicated servers, it can be preferred to have release |
| 82 | + builds always flush stdout on print, so that logging services like journald can |
| 83 | + collect logs while the process is running. This can be done by enabling |
| 84 | + ``application/run/flush_stdout_on_print`` in the Project Settings. |
| 85 | + |
| 86 | +Script backtraces |
| 87 | +----------------- |
| 88 | + |
| 89 | +Since Godot 4.5, when GDScript code encounters an error, it will log a backtrace that points |
| 90 | +to the origin of the error, while also containing the call stack leading to it. This behavior |
| 91 | +is always enabled when running in the editor, or when the project is exported in debug mode. |
| 92 | + |
| 93 | +In projects exported in release mode, backtraces are disabled by default for performance reasons. |
| 94 | +You can enable them by checking **Debug > Settings > GDScript > Always Track Call Stacks** in |
| 95 | +the Project Settings. If you use a custom logging system that reports exceptions to a remote |
| 96 | +service, it's recommended to enable this to make reported errors more actionable. |
| 97 | + |
| 98 | +Crash backtraces |
| 99 | +---------------- |
| 100 | + |
| 101 | +.. warning:: |
| 102 | + |
| 103 | + Crash backtraces are only useful if they were recorded in a build that |
| 104 | + contains :ref:`debugging symbols <doc_introduction_to_the_buildsystem_debugging_symbols>`. |
| 105 | + Official Godot binaries do not contain debugging symbols, so you must compile a |
| 106 | + custom editor or export template binary to get useful crash backtraces. |
| 107 | + |
| 108 | +When the project crashes, a crash backtrace is printed to the standard error stream. This is what |
| 109 | +it can look like in a build with debug symbols: |
| 110 | + |
| 111 | +:: |
| 112 | + |
| 113 | + ================================================================ |
| 114 | + handle_crash: Program crashed with signal 4 |
| 115 | + Engine version: Godot Engine v4.5.beta.custom_build (6c9aa4c7d3b9b91cd50714c40eeb234874df7075) |
| 116 | + Dumping the backtrace. Please include this when reporting the bug to the project developer. |
| 117 | + [1] /lib64/libc.so.6(+0x1a070) [0x7f6e5e277070] (??:0) |
| 118 | + [2] godot() [0x4da3358] (/path/to/godot/core/core_bind.cpp:336 (discriminator 2)) |
| 119 | + [3] godot() [0xdf5f2f] (/path/to/godot/modules/gdscript/gdscript.h:591) |
| 120 | + [4] godot() [0xbffd46] (/path/to/godot/modules/gdscript/gdscript.cpp:2065 (discriminator 1)) |
| 121 | + [5] godot() [0x30f2ea4] (/path/to/godot/core/variant/variant.h:870) |
| 122 | + [6] godot() [0x550d4e1] (/path/to/godot/core/object/object.cpp:933) |
| 123 | + [7] godot() [0x30d996a] (/path/to/godot/scene/main/node.cpp:318 (discriminator 1)) |
| 124 | + [8] godot() [0x3131a7f] (/path/to/godot/core/templates/hash_map.h:465) |
| 125 | + [9] godot() [0x424589] (/path/to/godot/platform/linuxbsd/os_linuxbsd.cpp:970) |
| 126 | + [10] /lib64/libc.so.6(+0x3575) [0x7f6e5e260575] (??:0) |
| 127 | + [11] /lib64/libc.so.6(__libc_start_main+0x88) [0x7f6e5e260628] (??:0) |
| 128 | + [12] godot() [0x464df5] (??:?) |
| 129 | + -- END OF C++ BACKTRACE -- |
| 130 | + ================================================================ |
| 131 | + GDScript backtrace (most recent call first): |
| 132 | + [0] _ready (res://test.gd:5) |
| 133 | + -- END OF GDSCRIPT BACKTRACE -- |
| 134 | + ================================================================ |
| 135 | + |
| 136 | +On the other hand, without debug symbols, it will look like this instead: |
| 137 | + |
| 138 | +:: |
| 139 | + |
| 140 | + ================================================================ |
| 141 | + handle_crash: Program crashed with signal 4 |
| 142 | + Engine version: Godot Engine v4.5.beta.custom_build (6c9aa4c7d3b9b91cd50714c40eeb234874df7075) |
| 143 | + Dumping the backtrace. Please include this when reporting the bug to the project developer. |
| 144 | + [1] /lib64/libc.so.6(+0x1a070) [0x7fdfaf666070] (??:0) |
| 145 | + [2] godot() [0x4da3358] (??:0) |
| 146 | + [3] godot() [0xdf5f2f] (??:0) |
| 147 | + [4] godot() [0xbffd46] (??:0) |
| 148 | + [5] godot() [0x30f2ea4] (??:0) |
| 149 | + [6] godot() [0x550d4e1] (??:0) |
| 150 | + [7] godot() [0x30d996a] (??:0) |
| 151 | + [8] godot() [0x3131a7f] (??:0) |
| 152 | + [9] godot() [0x424589] (??:0) |
| 153 | + [10] /lib64/libc.so.6(+0x3575) [0x7fdfaf64f575] (??:0) |
| 154 | + [11] /lib64/libc.so.6(__libc_start_main+0x88) [0x7fdfaf64f628] (??:0) |
| 155 | + [12] godot() [0x464df5] (??:0) |
| 156 | + -- END OF C++ BACKTRACE -- |
| 157 | + ================================================================ |
| 158 | + GDScript backtrace (most recent call first): |
| 159 | + [0] _ready (res://test.gd:5) |
| 160 | + -- END OF GDSCRIPT BACKTRACE -- |
| 161 | + ================================================================ |
| 162 | + |
| 163 | +This backtrace is also logged to the file for the current session, but it is **not** |
| 164 | +visible in the editor Output panel. Since the engine's scripting system is not running |
| 165 | +anymore when the engine is crashing, it is not possible to access it from scripting in |
| 166 | +the same session. However, you can still read the crash backtrace on the next session |
| 167 | +by loading log files and searching for the crash backtrace string |
| 168 | +(``-- END OF BACKTRACE --``) using :ref:`class_FileAccess`. This allows you to access |
| 169 | +the backtrace information even after a crash, as long as the user restarts the application |
| 170 | +and file logging is enabled. |
| 171 | + |
| 172 | +You can customize the message that appears at the top of the backtrace using the |
| 173 | +**Debug > Settings > Crash Handler > Message** project setting. This can be used |
| 174 | +to point to an URL or email address that users can report issues to. |
| 175 | + |
| 176 | +Creating custom loggers |
| 177 | +----------------------- |
| 178 | + |
| 179 | +Since Godot 4.5, it is possible to create custom loggers. This custom logging can |
| 180 | +be used for many purposes: |
| 181 | + |
| 182 | +- Show an in-game console with the same messages as printed by the engine, |
| 183 | + without requiring other scripts to be modified. |
| 184 | +- Report printed errors from the player's machine to a remote server. |
| 185 | + This can make it easier for developers to fix bugs when the game is already released, |
| 186 | + or during playtesting. |
| 187 | +- Integrate a dedicated server export with monitoring platforms. |
| 188 | + |
| 189 | +A custom logger can be registered by creating a class that inherits from :ref:`class_logger`, |
| 190 | +then passing an instance of this class to :ref:`OS.add_logger <class_OS_method_add_logger>`, |
| 191 | +in a script's :ref:`_init() <class_Object_private_method__init>` method. A good place to do this |
| 192 | +is an :ref:`autoload <doc_singletons_autoload>`. |
| 193 | + |
| 194 | +The class must define two methods: :ref:`_log_message() <class_Logger_private_method__log_message>` |
| 195 | +and :ref:`_log_error() <class_Logger_private_method__log_error>`. |
| 196 | + |
| 197 | +Here is a minimal working example of a custom logger, with the script added as an autoload: |
| 198 | + |
| 199 | +.. code-block:: gdscript |
| 200 | +
|
| 201 | + extends Node |
| 202 | +
|
| 203 | + class CustomLogger extends Logger: |
| 204 | + # Note that this method is not called for messages that use |
| 205 | + # `push_error()` and `push_warning()`, even though these are printed to stderr. |
| 206 | + func _log_message(message: String, error: bool) -> void: |
| 207 | + # Do something with `message`. |
| 208 | + # `error` is `true` for messages printed to the standard error stream (stderr) with `print_error()`. |
| 209 | + pass |
| 210 | +
|
| 211 | + func _log_error( |
| 212 | + function: String, |
| 213 | + file: String, |
| 214 | + line: int, |
| 215 | + code: String, |
| 216 | + rationale: String, |
| 217 | + editor_notify: bool, |
| 218 | + error_type: int, |
| 219 | + script_backtraces: Array[ScriptBacktrace] |
| 220 | + ) -> void: |
| 221 | + # Do something with the error. The error text is in `rationale`. |
| 222 | + # See the Logger class reference for details on other parameters. |
| 223 | + pass |
| 224 | +
|
| 225 | + # Use `_init()` to initialize the logger as early as possible, which ensures that messages |
| 226 | + # printed early are taken into account. However, even when using `_init()`, the engine's own |
| 227 | + # initialization messages are not accessible. |
| 228 | + func _init() -> void: |
| 229 | + OS.add_logger(CustomLogger.new()) |
| 230 | +
|
| 231 | +Note that to avoid infinite recursion, you cannot effectively use |
| 232 | +:ref:`print() <class_@GlobalScope_method_print>` and its related methods in |
| 233 | +``_log_message()``. You also can't effectively use |
| 234 | +:ref:`push_error() <class_@GlobalScope_method_push_error>` |
| 235 | +or :ref:`push_warning() <class_@GlobalScope_method_push_warning>` in |
| 236 | +``_log_error()``. Attempting to do so will print a message to the same stream |
| 237 | +as the original message. This message is not available in the custom logger, |
| 238 | +which is what prevents infinite recursion from occurring: |
| 239 | + |
| 240 | +:: |
| 241 | + |
| 242 | + While attempting to print a message, another message was printed: |
| 243 | + ... |
| 244 | + |
| 245 | + While attempting to print an error, another error was printed: |
| 246 | + ... |
| 247 | + |
| 248 | +.. seealso:: |
| 249 | + |
| 250 | + You can find an example of an in-game console built with a custom logger in the |
| 251 | + `Custom Logging demo project <https://github.com/godotengine/godot-demo-projects/tree/master/misc/custom_logging>`__. |
0 commit comments