icon안동민 개발노트

크래시 리포팅 및 분석


 언리얼 엔진 게임의 안정성을 유지하기 위해서는 효과적인 크래시 리포팅 및 분석 시스템이 필수적입니다.

 이 절에서는 크래시를 효과적으로 리포팅하고 분석하는 방법을 살펴보겠습니다.

언리얼 엔진의 내장 크래시 리포팅 시스템 설정

 언리얼 엔진은 기본적으로 크래시 리포팅 시스템을 제공합니다. 이를 활성화하고 설정하는 방법은 다음과 같습니다.

  1. 프로젝트 설정에서 "Analytics" 섹션으로 이동
  2. "Enable Auto Send" 옵션 활성화
  3. DefaultEngine.ini 파일에 다음 설정 추가
[CrashReportClient]
CrashReportClientVersion=1.0
DataRouterUrl="https://your-crash-server.com/api/crash"

커스텀 크래시 핸들러 구현

 보다 세밀한 제어를 위해 커스텀 크래시 핸들러를 구현할 수 있습니다.

##include "CoreMinimal.h"
##include "GenericPlatform/GenericPlatformCrashContext.h"
 
class FMyCustomCrashHandler : public FGenericCrashContext
{
public:
    static void Initialize()
    {
        FGenericCrashContext::SetHandlerInstance(new FMyCustomCrashHandler());
    }
 
    virtual void CaptureCustomContext(FCrashContext& OutContext) override
    {
        // 추가 정보 캡처
        OutContext.AddContext("CustomData", "SomeValue");
    }
};
 
// 게임 모듈 초기화 시 호출
void FMyGameModule::StartupModule()
{
    FMyCustomCrashHandler::Initialize();
}

크래시 덤프 생성 및 수집 프로세스

 크래시 덤프 생성을 위한 설정

  1. 프로젝트 설정에서 "Engine - Debugging" 섹션으로 이동
  2. "Create Crash Dump" 옵션 활성화

 크래시 덤프 수집 프로세스 구현

void CollectCrashDumps()
{
    FString CrashDumpPath = FPaths::ProjectSavedDir() / TEXT("Crashes");
    TArray<FString> CrashDumpFiles;
    IFileManager::Get().FindFiles(CrashDumpFiles, *CrashDumpPath, TEXT("*.dmp"));
 
    for (const FString& DumpFile : CrashDumpFiles)
    {
        // 덤프 파일 처리 및 업로드
        UploadCrashDump(DumpFile);
    }
}

크래시 로그 해석 방법

 크래시 로그 해석을 위한 기본 단계

  1. 크래시 발생 위치 식별
  2. 콜 스택 분석
  3. 오류 메시지 및 예외 코드 확인

 예시 코드

void AnalyzeCrashLog(const FString& LogContent)
{
    TArray<FString> LogLines;
    LogContent.ParseIntoArrayLines(LogLines);
 
    for (const FString& Line : LogLines)
    {
        if (Line.Contains("Exception"))
        {
            UE_LOG(LogTemp, Error, TEXT("Exception found: %s"), *Line);
        }
        else if (Line.Contains("CallStack"))
        {
            UE_LOG(LogTemp, Warning, TEXT("Call stack: %s"), *Line);
        }
    }
}

심볼 파일 관리

 심볼 파일은 크래시 분석에 중요합니다.

  1. 빌드 시 심볼 파일(.pdb) 생성 확인
  2. 심볼 서버 설정 및 관리
  3. 버전별 심볼 파일 보관

주요 크래시 원인 분석 기법

  1. 패턴 인식 : 자주 발생하는 크래시 패턴 식별
  2. 재현 가능한 테스트 케이스 작성
  3. 정적 분석 도구 활용

원격 크래시 리포팅 시스템 구축

 원격 크래시 리포팅 시스템 구현 예시

class FCrashReporter
{
public:
    static void SendCrashReport(const FString& CrashDumpPath)
    {
        FHttpRequestRef Request = FHttpModule::Get().CreateRequest();
        Request->SetURL("https://your-crash-server.com/api/crash");
        Request->SetVerb("POST");
        Request->SetHeader("Content-Type", "application/octet-stream");
 
        TArray<uint8> FileData;
        FFileHelper::LoadFileToArray(FileData, *CrashDumpPath);
        Request->SetContent(FileData);
 
        Request->OnProcessRequestComplete().BindLambda([](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bSuccess)
        {
            if (bSuccess && Response.IsValid())
            {
                UE_LOG(LogTemp, Log, TEXT("Crash report sent successfully"));
            }
        });
 
        Request->ProcessRequest();
    }
};

크래시 데이터의 효과적인 분류 및 우선순위 지정 전략

  1. 발생 빈도에 따른 분류
  2. 영향 범위에 따른 우선순위 지정
  3. 플랫폼 및 하드웨어 특성 고려

크래시 재현 및 디버깅 프로세스

  1. 크래시 로그 및 덤프 분석
  2. 유사한 환경 설정
  3. 디버거 연결 및 단계별 실행

메모리 관련 크래시 처리

 메모리 관련 크래시 예방 및 처리

void* FMyMemoryManager::Malloc(SIZE_T Count, uint32 Alignment)
{
    void* Ptr = FMemory::Malloc(Count, Alignment);
    if (Ptr == nullptr)
    {
        // 메모리 할당 실패 처리
        UE_LOG(LogTemp, Fatal, TEXT("Memory allocation failed for size %d"), Count);
    }
    return Ptr;
}

스레드 안전성 문제 해결

 스레드 안전성 확보를 위한 방법

FCriticalSection CriticalSection;
 
void ThreadSafeFunction()
{
    FScopeLock Lock(&CriticalSection);
    // 스레드 안전한 코드
}

플랫폼 특정 크래시 처리

 플랫폼별 크래시 처리 예시

##if PLATFORM_WINDOWS
    // Windows 특정 크래시 처리
##elif PLATFORM_ANDROID
    // Android 특정 크래시 처리
##elif PLATFORM_IOS
    // iOS 특정 크래시 처리
##endif

개인정보 보호 및 법적 문제 고려사항

 크래시 리포팅 시스템 구현 시 고려해야 할 사항

  1. 사용자 동의 획득
  2. 개인 식별 정보 최소화
  3. 데이터 암호화 및 보안 전송
  4. 데이터 보관 기간 설정

 예시 코드

bool ShouldSendCrashReport()
{
    bool bHasUserConsent = false;
    GConfig->GetBool(TEXT("/Script/MyGame.MyGameSettings"), TEXT("bUserConsentForCrashReporting"), bHasUserConsent, GGameIni);
    return bHasUserConsent;
}
 
void SendCrashReportWithPrivacyConsideration(const FString& CrashDumpPath)
{
    if (ShouldSendCrashReport())
    {
        // 개인 정보 제거
        FString SanitizedCrashDump = SanitizeCrashDump(CrashDumpPath);
        // 암호화된 전송
        SendEncryptedCrashReport(SanitizedCrashDump);
    }
}

 효과적인 크래시 리포팅 및 분석 시스템은 게임의 안정성과 품질을 크게 향상시킬 수 있습니다. 언리얼 엔진의 내장 시스템을 활용하거나 커스텀 솔루션을 개발하여 프로젝트의 요구사항에 맞는 최적의 시스템을 구축할 수 있습니다.

 크래시 덤프 생성 및 수집, 로그 해석, 심볼 파일 관리는 효과적인 크래시 분석의 기본입니다. 이를 통해 크래시의 근본 원인을 신속하게 파악하고 해결할 수 있습니다.

 원격 크래시 리포팅 시스템을 구축하면 실제 사용자 환경에서 발생하는 문제를 효과적으로 추적할 수 있습니다. 크래시 데이터의 적절한 분류와 우선순위 지정은 한정된 리소스로 최대의 효과를 얻는 데 도움이 됩니다.

 메모리 관련 크래시, 스레드 안전성 문제, 플랫폼 특정 크래시 등 다양한 유형의 크래시에 대한 이해와 대응 방법을 숙지하는 것이 중요합니다. 각 유형별로 적절한 예방 및 처리 전략을 수립해야 합니다.

 마지막으로, 크래시 리포팅 시스템 구현 시 개인정보 보호와 법적 문제를 반드시 고려해야 합니다. 사용자의 동의를 얻고, 필요 최소한의 정보만을 수집하며, 데이터의 안전한 처리와 보관을 보장해야 합니다.

 이러한 종합적인 접근을 통해 효과적인 크래시 리포팅 및 분석 시스템을 구축함으로써, 게임의 안정성을 높이고 사용자 경험을 개선할 수 있습니다.