Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

디버깅

Godot에는 로그 메시지를 구성하고 수집하는 여러 가지 방법이 있습니다.

메시지 출력하기

더 보기

메시지 인쇄에 대한 지침은 :ref:`doc_output_panel_printing_messages`를 참조하세요. 인쇄된 출력은 일반적으로 기록된 출력과 동일합니다.

편집기에서 프로젝트를 실행할 때 assert 오류가 발생하면 프로젝트가 일시 정지됩니다.

프로젝트 설정

Godot의 로깅 동작을 제어하기 위한 여러 프로젝트 설정이 있습니다:

  • 응용 프로그램 > 실행 > stdout 비활성화: 표준 출력에 대한 로깅을 완전히 비활성화합니다. 이는 사용자 정의 로거가 수신하는 내용에도 영향을 미칩니다. 이는 :ref:`Engine.print_to_stdout <class_Engine_property_print_to_stdout>`을 설정하여 런타임에 제어할 수 있습니다.

  • 응용 프로그램 > 실행 > stderr 비활성화: 표준 오류에 대한 로깅을 완전히 비활성화합니다. 이는 사용자 정의 로거가 수신하는 내용에도 영향을 미칩니다. 이는 :ref:`Engine.print_error_messages <class_Engine_property_print_error_messages>`를 설정하여 런타임에 제어할 수 있습니다.

  • 디버그 > 설정 > stdout > Verbose stdout: 표준 출력에 대한 자세한 로깅을 활성화합니다. :ref:`print_verbose() <class_@GlobalScope_method_print_verbose>`의 인쇄는 상세 모드가 활성화된 경우에만 표시됩니다.

  • 디버그 > 설정 > stdout > FPS 인쇄: 매초마다 초당 프레임 수와 시작 시 V-Sync 상태를 인쇄합니다(최대 프레임 속도를 효과적으로 제한할 수 있으므로).

  • 디버그 > 설정 > stdout > GPU 프로필 인쇄: :ref:`doc_debugger_panel_visual_profiler`와 동일한 데이터 소스를 사용하여 매초마다 GPU 활용 보고서를 인쇄합니다.

이러한 프로젝트 설정 중 일부는 명령줄 인수 <doc_command_line_tutorial>`(예: `--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 프로젝트 설정을 사용하여 파일 로깅을 완전히 비활성화할 수도 있습니다.

프로젝트가 충돌하면 충돌 로그가 로그 파일과 동일한 파일에 기록됩니다. 충돌 로그에는 실행된 바이너리에 디버깅 기호가 포함되어 있거나 바이너리와 일치하는 디버그 기호 파일을 찾을 수 있는 경우에만 사용 가능한 역추적이 포함됩니다. 공식 바이너리는 디버깅 기호를 제공하지 않으므로 이를 작동하려면 사용자 지정 빌드가 필요합니다. 디버깅 기호가 활성화된 바이너리 컴파일에 대한 지침은 :ref:`디버깅 기호 <doc_introduction_to_the_buildsystem_debugging_symbols>`을 참조하세요.

참고

print() 문의 로그 파일은 표준 출력이 엔진에 의해 *플러시*될 때 업데이트됩니다. 디버그 빌드에서만 모든 인쇄에서 표준 출력이 플러시됩니다. 릴리스 모드로 내보낸 프로젝트에서는 성능 향상을 위해 프로젝트가 종료되거나 충돌할 때만 표준 출력이 플러시됩니다. 특히 프로젝트가 텍스트를 표준 출력으로 자주 인쇄하는 경우에는 더욱 그렇습니다.

반면, 표준 오류 스트림(printerr(), push_error() 및 :ref:`push_warning() <class_@GlobalScope_method_push_warning>`에서 사용됨)은 다음과 같습니다. 릴리스 모드에서 내보낸 프로젝트에서도 항상 모든 인쇄에서 플러시됩니다.

전용 서버와 같은 일부 사용 사례의 경우 릴리스 빌드에서 인쇄 시 항상 stdout을 플러시하여 저널d와 같은 로깅 서비스가 프로세스가 실행되는 동안 로그를 수집할 수 있도록 하는 것이 더 나을 수 있습니다. 이는 프로젝트 설정에서 ``application/run/flush_stdout_on_print``를 활성화하여 수행할 수 있습니다.

스크립트 코드

Godot 4.5부터 GDScript 코드에 오류가 발생하면 오류의 원인을 가리키는 역추적을 기록하는 동시에 오류로 이어지는 호출 스택도 포함합니다. 이 동작은 편집기에서 실행하거나 프로젝트를 디버그 모드로 내보낼 때 항상 활성화됩니다.

릴리스 모드로 내보낸 프로젝트에서는 성능상의 이유로 역추적이 기본적으로 비활성화됩니다. 프로젝트 설정에서 **디버그 > 설정 > GDScript > 항상 호출 스택 추적**을 확인하여 활성화할 수 있습니다. 원격 서비스에 예외를 보고하는 사용자 지정 로깅 시스템을 사용하는 경우 보고된 오류에 대한 조치를 더 쉽게 만들기 위해 이를 활성화하는 것이 좋습니다.

충돌 역추적

경고

크래시 역추적은 :ref:`디버깅 기호 <doc_introduction_to_the_buildsystem_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 --
================================================================

이 역추적은 현재 세션의 파일에도 기록되지만 편집기 출력 패널에는 표시되지 않습니다. 엔진 충돌이 발생하면 엔진의 스크립팅 시스템이 더 이상 실행되지 않으므로 동일한 세션의 스크립팅에서 액세스할 수 없습니다. 그러나 로그 파일을 로드하고 class_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))

디버그 > 설정 > 크래시 처리기 > 메시지 프로젝트 설정을 사용하여 역추적 상단에 표시되는 메시지를 사용자 정의할 수 있습니다. 이는 사용자가 문제를 보고할 수 있는 URL이나 이메일 주소를 가리키는 데 사용될 수 있습니다.

커스텀 로거 만들기

Godot 4.5부터 사용자 정의 로거를 생성하는 것이 가능합니다. 이 사용자 정의 로깅은 다양한 목적으로 사용될 수 있습니다.

  • 다른 스크립트를 수정할 필요 없이 엔진에서 인쇄한 것과 동일한 메시지가 포함된 게임 내 콘솔을 표시합니다.

  • 플레이어의 컴퓨터에서 원격 서버로 인쇄된 오류를 보고합니다. 이를 통해 개발자는 게임이 이미 출시되었거나 플레이 테스트 중에 버그를 더 쉽게 수정할 수 있습니다.

  • 데디케이티드 서버 내보내기를 모니터링 플랫폼과 통합합니다.

class_logger`에서 상속되는 클래스를 생성한 다음 스크립트의 :ref:`_init() 메서드에서 이 클래스의 인스턴스를 :ref:`OS.add_logger <class_OS_method_add_logger>`에 전달하여 사용자 지정 로거를 등록할 수 있습니다. 이를 수행하기에 좋은 곳은 :ref:`autoload <doc_singletons_autoload>`입니다.

클래스는 _log_message() 및 :ref:`_log_error() <class_Logger_private_method__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())

무한 재귀를 피하기 위해 ``_log_message()``에서는 print() 및 관련 메서드를 효과적으로 사용할 수 없습니다. 또한 ``_log_error()``에서는 push_error() 또는 :ref:`push_warning() <class_@GlobalScope_method_push_warning>`을 효과적으로 사용할 수 없습니다. 그렇게 하려고 시도하면 원본 메시지와 동일한 스트림에 메시지가 인쇄됩니다. 이 메시지는 사용자 정의 로거에서 사용할 수 없으므로 무한 재귀가 발생하는 것을 방지합니다.

While attempting to print a message, another message was printed:
...

While attempting to print an error, another error was printed:
...

더 보기

이 문서 외에 여러가지 Godot 데모 프로젝트들도 살펴보면 좋습니다.