Ведение журнала
Godot предлагает несколько способов организации и сбора сообщений журнала.
Печать сообщений
См. также
Инструкции по печати сообщений см. в документе Печать сообщений. Вывод на печать, как правило, идентичен выводу, зафиксированному в журнале.
При запуске проекта из редактора редактор отобразит зарегистрированный текст в Панель вывода.
Настройки проекта
Для управления поведением логирования в Godot существует несколько настроек проекта:
Приложение > Выполнить > Отключить stdout: Полностью отключает запись журнала в стандартный вывод. Это также влияет на то, что получают пользовательские средства регистрации. Это можно контролировать во время выполнения, установив Engine.print_to_stdout.
Приложение > Выполнить > Отключить stderr: Полностью отключает запись в стандартный поток ошибок. Это также влияет на то, что получают пользовательские средства ведения журнала. Это можно контролировать во время выполнения, установив Engine.print_error_messages.
Отладка > Настройки > stdout > Подробный stdout: Включает подробное протоколирование в стандартный вывод. Вывод из print_verbose() отображается только при включенном режиме подробного вывода.
Отладка > Настройки > stdout > Печать FPS: Выводит количество кадров в секунду каждую секунду, а также состояние вертикальной синхронизации при запуске (поскольку это может эффективно ограничить максимальную частоту кадров).
Отладка > Настройки > stdout > Печать профиля GPU: Печатает отчет об использовании GPU каждую секунду, используя тот же источник данных, что и Visual Profiler.
Некоторые из этих настроек проекта также можно переопределить с помощью аргументов командной строки, таких как --quiet, --verbose и --print-fps.
Также можно настроить собственное ведение журнала файлов движка, как описано в разделе ниже.
Встроенное ведение журнала файлов
По умолчанию Godot записывает файлы журналов в user://logs/godot.log на настольных платформах. Вы можете изменить это местоположение, изменив настройку проекта debug/file_logging/log_path. Журналы ротируются, чтобы старые файлы были доступны для проверки. Каждый сеанс создает новый файл журнала, при этом старый файл переименовывается, чтобы содержать дату его ротации. По умолчанию сохраняется до 5 файлов журнала, это количество можно изменить с помощью настройки проекта debug/file_logging/max_log_files.
Ведение журнала файлов также можно полностью отключить с помощью настройки проекта debug/file_logging/enable_file_logging.
При сбое проекта журналы сбоев записываются в тот же файл, что и файл журнала. Журнал сбоев будет содержать пригодную для использования обратную трассировку только в том случае, если запущенный исполняемый файл содержит отладочные символы или если программа сможет найти файл отладочных символов, соответствующий исполняемому файлу. Официальные исполняемые файлы не предоставляют отладочные символы, поэтому для работы требуется специальная сборка. Инструкции по компиляции исполняемых файлов с включёнными отладочными символами см. в разделе Debugging symbols.
Примечание
Файлы журналов для операторов print() обновляются при очистке стандартного вывода движком. Стандартный вывод очищается при каждой печати только в отладочных сборках. В проектах, экспортированных в режиме выпуска, стандартный вывод очищается только при завершении проекта или его сбое для повышения производительности, особенно если проект часто выводит текст в стандартный вывод.
С другой стороны, стандартный поток ошибок (используемый printerr(), push_error() и push_warning()) всегда очищается при каждой печати, даже в проектах, экспортированных в режиме выпуска.
Для некоторых случаев использования, например, для выделенных серверов, может быть предпочтительнее, чтобы сборки релиза всегда очищали stdout при печати, чтобы службы журналирования, такие как journald, могли собирать журналы во время выполнения процесса. Это можно сделать, включив application/run/flush_stdout_on_print в Project Settings.
Обратная трассировка скрипта
Начиная с Godot 4.5, при возникновении ошибки в коде GDScript регистрируется обратная трассировка, указывающая на источник ошибки, а также содержащая стек вызовов, приведших к ней. Это поведение всегда включено при запуске в редакторе или при экспорте проекта в режиме отладки.
В проектах, экспортированных в режиме релиза, обратные трассировки по умолчанию отключены из соображений производительности. Вы можете включить их, установив флажок Отладка > Настройки > GDScript > Всегда отслеживать стеки вызовов в настройках проекта. Если вы используете собственную систему журналирования, которая сообщает об исключениях удалённой службе, рекомендуется включить её, чтобы сделать сообщаемые об ошибках более оперативными.
Следы сбоев
Предупреждение
Трассировки сбоев полезны только в том случае, если они были записаны в сборке, содержащей отладочные символы. Официальные двоичные файлы 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 --
================================================================
Эта трассировка также регистрируется в файле текущего сеанса, но не отображается на панели вывода редактора. Поскольку система скриптов движка не работает во время сбоя, доступ к ней из скриптов в том же сеансе невозможен. Тем не менее, вы можете прочитать трассировку сбоя в следующем сеансе, загрузив файлы журналов и выполнив поиск строки трассировки сбоя (Program crashed with signal) с помощью FileAccess. Это позволяет получить доступ к информации трассировки даже после сбоя, если пользователь перезапустит проект и включено ведение журнала файла:
# 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))
Вы можете настроить сообщение, отображаемое в верхней части трассировки, с помощью параметра проекта Отладка > Настройки > Обработчик сбоев > Сообщение. Его можно использовать для указания URL-адреса или адреса электронной почты, по которому пользователи могут сообщать о проблемах.
Создание пользовательских регистраторов
Начиная с версии Godot 4.5, появилась возможность создавать собственные логгеры. Эти пользовательские логгеры можно использовать для различных целей:
Показывать игровую консоль с теми же сообщениями, которые выводит движок, без необходимости изменения других скриптов.
Передавайте сообщения об ошибках печати с компьютера игрока на удалённый сервер. Это может облегчить разработчикам исправление ошибок после выхода игры или во время её тестирования.
Интегрируйте выделенный серверный экспорт с платформами мониторинга.
Пользовательский регистратор можно зарегистрировать, создав класс, наследующий от Logger, и передав экземпляр этого класса методу OS.add_logger в методе _init() скрипта. Хорошим местом для этого является метод autoload.
Класс должен определять два метода: _log_message() и _log_error().
Вот минимальный рабочий пример пользовательского регистратора со скриптом, добавленным в качестве автозагрузки:
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())
Обратите внимание, что для предотвращения бесконечной рекурсии невозможно эффективно использовать print() и связанные с ним методы в _log_message(). Также невозможно эффективно использовать push_error() или push_warning() в _log_error(). Попытка сделать это приведёт к выводу сообщения в тот же поток, что и исходное сообщение. Это сообщение недоступно в пользовательском логгере, что и предотвращает возникновение бесконечной рекурсии:
While attempting to print a message, another message was printed:
...
While attempting to print an error, another error was printed:
...
См. также
Пример игровой консоли, созданной с помощью пользовательского регистратора, можно найти в демонстрационном проекте Custom Logging.