안동민 개발노트

본문 시작

디버깅과 로그 관리

로그 카테고리·콘솔 명령·IDE 디버거·Blueprint 디버거·Visual Logger로 배포 후 문제를 추적합니다.

이전 절에서 우리는 언리얼 엔진 게임을 다양한 플랫폼에 맞게 빌드하고 패키징하는 방법에 대해 알아보았습니다.

게임이 성공적으로 배포된 후에도 개발자의 역할은 끝나지 않습니다.

게임은 실제 사용자 환경에서 다양한 문제에 직면할 수 있으며, 이러한 문제들을 식별하고 해결하는 것이 바로 디버깅(Debugging)과 로그 관리(Log Management)의 핵심입니다.

이번 절에서는 언리얼 엔진에서 제공하는 디버깅 도구와 로그 시스템을 효과적으로 활용하여 게임의 문제를 진단하고 해결하는 방법에 대해 자세히 살펴보겠습니다.


디버깅의 중요성

디버깅은 소프트웨어의 버그나 오류를 찾아내고 수정하는 과정입니다.

게임 개발에서 디버깅은 다음과 같은 이유로 매우 중요합니다.

  • 버그 수정: 예상치 못한 충돌, 비정상적인 동작, 기능 오작동 등을 해결합니다.
  • 성능 문제 진단: 프레임 드롭, 로딩 지연 등 성능 문제의 근본 원인을 파악합니다.
  • 안정성 향상: 게임이 다양한 환경에서 안정적으로 작동하도록 합니다.
  • 플레이어 경험 개선: 버그 없는 부드러운 게임 경험은 플레이어 유지에 필수적입니다.

언리얼 엔진의 주요 디버깅 도구

언리얼 엔진은 강력한 자체 디버깅 기능과 함께 Visual Studio, Xcode 등 외부 IDE와의 연동을 지원합니다.

인게임 콘솔 명령어

가장 빠르고 기본적인 디버깅 도구입니다.

콘솔이 포함된 개발 환경에서 ~ 키로 열고 명령을 입력합니다. Shipping의 기본 기능과 플랫폼별 지원 여부는 다를 수 있습니다.

  • r.SetRes [Width]x[Height]f: 해상도 변경 (예: r.SetRes 1920x1080f)
  • stat fps: 현재 프레임 속도 표시 (자세한 내용은 9장 1절 참조)
  • stat unit: CPU 및 GPU 시간 통계 표시 (자세한 내용은 9장 1절 참조)
  • stat [Category]: 특정 통계 카테고리 표시 (예: stat anim, stat gpu, stat net)
  • show [Category]: 특정 렌더링 기능 토글 (예: show collision, show postprocess, show particles)
  • toggledebugcamera: 자유롭게 이동 가능한 디버그 카메라 활성화/비활성화
  • quit: 게임 종료
  • pause: 지원되는 게임에서 일시 정지 상태를 토글합니다.
  • obj list class=[ClassName]: 특정 클래스의 모든 오브젝트 나열
  • showdebug: 현재 디버그 대상의 HUD 정보를 확인합니다. 지원 표시 항목은 게임·엔진 버전에 따라 다릅니다.
  • t.MaxFPS [FPS]: 최대 프레임 속도 제한 (예: t.MaxFPS 60)

Visual Studio / Xcode 디버거 연동

C++ 코드를 디버깅할 때 가장 강력한 도구입니다.

  • 브레이크포인트(Breakpoint): 코드의 특정 줄에 브레이크포인트를 설정하여 게임 실행을 일시 중지하고, 해당 지점에서의 변수 값, 호출 스택 등을 검사할 수 있습니다.
  • 단계별 실행: Step Over (다음 줄로), Step Into (함수 내부로), Step Out (현재 함수 빠져나오기) 기능을 사용하여 코드 실행 흐름을 추적합니다.
  • 변수 검사: Locals, Watch 창을 통해 현재 스코프의 변수 값이나 특정 변수의 값을 실시간으로 확인합니다.
  • 호출 스택(Call Stack): 현재 코드가 어떤 함수 호출 경로를 통해 실행되었는지 확인하여 버그의 근본 원인을 추적합니다.
  • 디버그 빌드: DebugGame은 게임 코드를 최적화하지 않아 소스 추적이 쉽습니다. Development·Shipping도 일치하는 심볼이 있으면 디버깅할 수 있지만 최적화로 줄 실행·변수 관찰이 달라질 수 있습니다.

블루프린트 디버거

블루프린트 스크립트 로직을 디버깅하는 데 사용됩니다.

  • 디버거 창 열기: 에디터에서 Window -> Developer Tools -> Blueprint Debugger를 선택합니다.
  • 인스턴스 선택: 게임 실행 중 블루프린트 디버거에서 디버깅할 블루프린트 인스턴스를 선택합니다.
  • 실행 흐름 추적: 블루프린트 노드가 실행될 때 시각적으로 강조 표시되어 로직 흐름을 쉽게 따라갈 수 있습니다.
  • 변수 값 확인: 노드를 클릭하거나 Details 패널을 통해 해당 노드에서 사용되는 변수들의 값을 확인합니다.
  • 브레이크포인트: 블루프린트 노드에 브레이크포인트를 설정하여 실행을 일시 중지하고 검사할 수 있습니다.

비주얼 로거 (Visual Logger)

게임 실행 중 특정 이벤트나 데이터 흐름을 시각적으로 기록하고 재생하는 도구입니다.

특히 AI 동작, 애니메이션 상태, 물리 충돌 등을 디버깅할 때 유용합니다.

  • 활성화: 에디터의 Visual Logger 창을 열고 기록을 시작합니다. 메뉴 위치는 엔진 버전에 맞춰 확인합니다.
  • 로그 기록: C++에서 UE_VLOG, UE_VLOG_SEGMENT 등의 매크로로 액터별 텍스트·도형 정보를 기록합니다. VisualLogger/VisualLogger.h와 지원 빌드 구성을 확인합니다.
  • 재생: 게임 실행이 끝난 후 비주얼 로거 창에서 기록된 세션을 로드하여 저장된 시각 로그·스냅샷을 시간순으로 확인합니다. 게임 전체 상태를 재실행하는 리플레이와는 다릅니다.

로그 시스템과 관리

로그는 게임 실행 중 발생하는 이벤트, 경고, 오류 등을 텍스트 형태로 기록하는 시스템입니다.

버그 보고서를 분석하거나 라이브 서비스 중인 게임의 문제를 진단할 때 매우 중요합니다.

로깅 매크로 (C++)

언리얼 엔진은 다양한 로깅 매크로를 제공합니다.

  • UE_LOG(LogCategory, Verbosity, Format, ...): 가장 기본적인 로깅 함수.

    • LogCategory: 로그 메시지의 카테고리. LogTemp, LogNet, LogPhysics 등 미리 정의된 카테고리가 있으며, 개발자가 직접 커스텀 카테고리를 정의할 수도 있습니다 (DEFINE_LOG_CATEGORY).
    • Verbosity: 메시지의 중요도 수준.
      • Error: 심각한 오류.
      • Warning: 잠재적인 문제.
      • Display: 사용자에게 표시될 중요한 정보.
      • Log: 일반적인 정보.
      • Verbose: 상세한 디버깅 정보.
      • VeryVerbose: 매우 상세한 디버깅 정보 (성능에 영향).
    • Format: printf 스타일의 포맷 문자열.
  • 부분 예시: AMyActor의 헤더에 BeginPlay와 프로젝트의 bool SomeCondition이 선언되어 있고, cpp가 그 헤더를 포함한 상황입니다.

    MyActor.h
    DECLARE_LOG_CATEGORY_EXTERN(LogMyActor, Log, All); // 커스텀 로그 카테고리 선언
    MyActor.cpp
    DEFINE_LOG_CATEGORY(LogMyActor); // 커스텀 로그 카테고리 정의
    
    void AMyActor::BeginPlay()
    {
        Super::BeginPlay();
        UE_LOG(LogMyActor, Log, TEXT("MyActor spawned at location: %s"), *GetActorLocation().ToString());
        if (SomeCondition)
        {
            UE_LOG(LogMyActor, Warning, TEXT("Warning: Some condition met!"));
        }
        else
        {
            UE_LOG(LogMyActor, Error, TEXT("Error: Critical condition failed!"));
        }
    }

블루프린트 로깅

블루프린트에서도 Print String 노드와 Print Text 노드를 사용하여 로그를 출력할 수 있습니다.

Print String은 화면에 디버그 텍스트를 표시하는 데도 사용됩니다.

로그 파일 위치 및 관리

  • 로그 파일 위치: 실행 환경의 Saved/Logs 경로를 확인합니다. 패키지·플랫폼·사용자 데이터 정책에 따라 설치 폴더가 아닌 사용자 데이터 영역일 수 있으며 로깅 자체가 빌드에서 활성화되어야 합니다.
  • 에디터 로그: 에디터에서 실행할 때는 [ProjectName]\Saved\Logs\에 저장됩니다.
  • 로그 레벨 조절: 콘솔에서 Log [Category] [Verbosity] 명령을 사용하여 특정 카테고리의 로그 출력 수준을 조절할 수 있습니다 (예: log LogNet Verbose - 네트워크 로그를 상세하게). 이는 config 파일(DefaultEngine.ini 등)에서도 설정할 수 있습니다.

크래시 보고 (Crash Reporting)

게임이 충돌(Crash)했을 때, 언리얼 엔진은 자동으로 크래시 보고서(Crash Report)를 생성합니다.

  • 크래시 리포터: 패키지에는 Crash Report Client를 별도로 포함해야 합니다. 보고서 수신 주소와 동의·자동 전송 정책을 프로젝트에서 설정합니다. 패키지의 충돌이 자동으로 Epic에 전송된다고 가정하지 않습니다.
  • 크래시 로그 분석: 생성된 크래시 로그 파일([ProjectName]\Saved\Crashes\[Timestamp]\)에는 충돌 시점의 호출 스택(Call Stack) 정보가 포함되어 있어, Visual Studio 등에서 .pdb (Program Database) 디버깅 심볼 파일을 이용하여 충돌 지점을 정확히 찾아낼 수 있습니다.
  • 심볼 서버: Shipping 빌드와 같은 최적화된 빌드의 크래시 로그를 분석하려면, 빌드 시 생성된 디버깅 심볼(.pdb 파일)을 심볼 서버에 게시하거나 로컬에 보관해야 합니다.

실제 문제를 다룰 때는 한 도구만 보는 것보다 증상 관찰, 진단 도구 선택, 로그 수준 조정, 파일 증거 수집, 재현과 수정을 짧게 반복하는 편이 효율적입니다.


배포된 게임 디버깅 전략

패키징된 게임, 특히 최종 Shipping 빌드는 디버깅 정보가 제거되거나 최소화되어 직접적인 디버깅이 어려울 수 있습니다.

  • DebugGame 또는 Development 빌드 사용: QA나 내부 테스트 시에는 DebugGame 또는 Development 빌드를 사용하여 더 많은 디버깅 정보를 포함시키고, 필요시 원격 디버깅을 시도합니다.
  • 심볼과 진단 기능 분리: Include Debug Files는 디버그 파일 포함 설정이며 Shipping 콘솔을 켜는 옵션이 아닙니다. 필요한 진단은 개발·Test 구성 또는 지원되는 타깃 설정으로 설계합니다.
  • 원격 디버깅: 배포된 게임에 연결하여 원격으로 디버깅하는 고급 기법도 있습니다. 플랫폼이 지원하는 원격 디버거와 동일 빌드의 심볼을 사용합니다. 원격 콘텐츠 쿠킹 서버와 C++ 디버거 연결은 다른 기능입니다.
  • 플레이어 로그 파일 요청: 최종 사용자로부터 문제가 발생했을 때 로그 파일을 받아 분석하는 것이 일반적인 방법입니다. 게임 내에 로그 파일 저장 위치를 안내하는 기능을 추가할 수 있습니다.
  • 텔레메트리 시스템: 게임에 원격 분석 시스템(Telemetry)을 통합하여 게임 플레이 데이터, 성능 데이터, 오류 발생 정보 등을 수집하고 분석합니다. 이는 대규모 사용자 기반에서 버그를 예측하고 해결하는 데 매우 효과적입니다.


로깅 모범 사례

  • 의미 있는 로그 메시지: 로그 메시지는 구체적이고 유용해야 합니다. UE_LOG(LogTemp, Warning, TEXT("Error!")); 보다는 UE_LOG(LogCombat, Error, TEXT("Player %s tried to attack with no weapon equipped!"), *GetPlayerName()); 와 같이 맥락을 제공해야 합니다.
  • 적절한 Verbosity 수준 사용: Error, Warning 등 필요한 사건을 보존하도록 빌드·런타임 필터를 설정하고, Log, Display는 중요한 정보에 사용하며, Verbose, VeryVerbose는 개발/디버깅 중에만 활성화하고 릴리스 빌드에서는 비활성화하여 성능 오버헤드를 줄입니다.
  • 과도한 로깅 피하기: 매 프레임 발생하는 루프나 빈번한 함수에서 무분별한 로깅은 성능 저하를 유발할 수 있습니다. 꼭 필요한 경우에만 로그를 남깁니다.
  • 커스텀 로그 카테고리: 게임의 주요 시스템(AI, UI, Network, SaveGame 등)별로 커스텀 로그 카테고리를 정의하여 로그를 체계적으로 관리하고 필터링하기 쉽게 만듭니다.

재현할 빌드·맵·입력 순서와 같은 빌드의 심볼을 함께 보관합니다. 로그에는 필요한 객체·상태·세션 단서를 남기되 비밀번호·토큰 등 민감한 값은 출력하지 않습니다.