고급 Crashlytics 기능을 사용하여 Unity 게임의 충돌 이해

1. 소개

이 Codelab에서는 충돌과 충돌을 일으켰을 수 있는 상황에 대한 더 나은 가시성을 제공하는 Crashlytics의 고급 기능을 사용하는 방법을 알아봅니다.

샘플 게임인 MechaHamster: Level Up with Firebase Edition 에 새로운 기능을 추가하겠습니다. 이 샘플 게임은 기본 제공 Firebase 기능을 대부분 제거하여 그 자리에 Firebase의 새로운 용도를 구현할 수 있는 기회를 제공하는 기본 Firebase 게임 MechaHamster의 새 버전입니다.

게임에 디버그 메뉴를 추가하겠습니다. 이 디버그 메뉴는 개발자가 만들 메서드를 호출하고 이를 통해 Crashlytics의 다양한 기능을 실행할 수 있습니다. 이러한 방법은 사용자 정의 키, 사용자 정의 로그, 치명적이지 않은 오류 등으로 자동 충돌 보고서에 주석을 추가하는 방법을 보여줍니다.

게임을 구축한 후에는 디버그 메뉴를 사용하고 결과를 검사하여 게임이 실제로 실행되는 방식에 대해 제공되는 고유한 보기를 이해하게 됩니다.

무엇을 배울 것인가

  • Crashlytics에서 자동으로 포착하는 오류 유형입니다.
  • 의도적으로 기록될 수 있는 추가 오류입니다.
  • 오류를 더 쉽게 이해할 수 있도록 오류에 더 많은 정보를 추가하는 방법.

필요한 것

  • 다음 중 하나 또는 둘 다를 갖춘 Unity(최소 권장 버전 2019+):
    • iOS 빌드 지원
    • 안드로이드 빌드 지원
  • (Android에만 해당) Firebase CLI(충돌 보고서용 기호를 업로드하는 데 사용됨)

2. 개발 환경 설정

다음 섹션에서는 Level Up with Firebase 코드를 다운로드하고 Unity에서 여는 방법을 설명합니다.

Firebase를 사용한 레벨 업 샘플 게임은 다른 여러 Firebase + Unity Codelab에서 사용되므로 이 섹션의 작업을 이미 완료했을 수도 있습니다. 그렇다면 이 페이지의 마지막 단계인 'Unity용 Firebase SDK 추가'로 직접 이동할 수 있습니다.

코드 다운로드

명령줄에서 이 Codelab의 GitHub 저장소를 클론합니다.

git clone https://github.com/firebase/level-up-with-firebase.git

또는 git이 설치되어 있지 않은 경우 저장소를 ZIP 파일로 다운로드 할 수 있습니다.

Unity 편집기에서 Firebase를 사용하여 Level Up 열기

  1. Unity Hub를 실행하고 프로젝트 탭에서 열기 옆에 있는 드롭다운 화살표를 클릭합니다.
  2. 디스크에서 프로젝트 추가 를 클릭합니다.
  3. 코드가 포함된 디렉터리로 이동한 다음 확인 을 클릭합니다.
  4. 메시지가 표시되면 사용할 Unity 편집기 버전과 대상 플랫폼(Android 또는 iOS)을 선택합니다.
  5. 프로젝트 이름 level-up-with-firebase 를 클릭하면 해당 프로젝트가 Unity 편집기에서 열립니다.
  6. 편집기가 자동으로 열리지 않으면 Unity 편집기의 프로젝트 탭에 있는 Assets > Hamster 에서 MainGameScene 엽니다.
    ff4ea3f3c0d29379.png

Unity 설치 및 사용에 대한 자세한 내용은 Unity에서 작업을 참조하세요.

3. Unity 프로젝트에 Firebase 추가

Firebase 프로젝트 만들기

  1. Firebase 콘솔 에서 프로젝트 추가를 클릭합니다.
  2. 새 프로젝트를 생성하려면 원하는 프로젝트 이름을 입력하세요.
    또한 프로젝트 이름 아래에 표시되는 프로젝트 ID를 프로젝트 이름에 따라 설정합니다. 선택적으로 프로젝트 ID의 편집 아이콘을 클릭하여 추가로 사용자 정의할 수 있습니다.
  3. 메시지가 표시되면 Firebase 약관을 검토하고 동의하세요.
  4. 계속 을 클릭합니다.
  5. 이 프로젝트에 대해 Google Analytics 활성화 옵션을 선택한 다음 계속 을 클릭합니다.
  6. 사용할 기존 Google Analytics 계정을 선택하거나 새 계정 만들기를 선택하여 새 계정을 만듭니다.
  7. 프로젝트 생성 을 클릭합니다.
  8. 프로젝트가 생성되면 계속을 클릭합니다.

Firebase에 앱 등록

  1. Firebase 콘솔 의 프로젝트 개요 페이지 중앙에서 Unity 아이콘을 클릭하여 설정 워크플로를 시작하거나 이미 Firebase 프로젝트에 앱을 추가한 경우 앱 추가를 클릭하여 플랫폼 옵션을 표시합니다.
  2. Apple(iOS) 및 Android 빌드 대상을 모두 등록하려면 선택합니다.
  3. Unity 프로젝트의 플랫폼별 ID를 입력하세요. 이 Codelab에서는 다음을 입력합니다.
    • Apple(iOS)의 경우 : iOS 번들 ID 필드에 com.google.firebase.level-up 입력합니다.
    • Android의 경우 : Android 패키지 이름 필드에 com.google.firebase.level_up 입력합니다.
  4. (선택 사항) Unity 프로젝트의 플랫폼별 닉네임을 입력합니다.
  5. 앱 등록을 클릭한 후 구성 파일 다운로드 섹션으로 진행합니다.

Firebase 구성 파일 추가

Register app 을 클릭하면 두 개의 구성 파일(각 빌드 대상당 하나의 구성 파일)을 다운로드하라는 메시지가 표시됩니다. Firebase에 연결하려면 Unity 프로젝트에 이러한 파일에 Firebase 메타데이터가 필요합니다.

  1. 사용 가능한 두 구성 파일을 모두 다운로드합니다.
    • Apple(iOS)의 경우 : GoogleService-Info.plist를 다운로드하세요.
    • Android의 경우 : google-services.json을 다운로드하세요.
  2. Unity 프로젝트의 프로젝트 창을 연 다음 두 구성 파일을 모두 Assets 폴더로 이동합니다.
  3. Firebase 콘솔로 돌아가 설정 워크플로에서 다음을 클릭하고 Unity용 Firebase SDK 추가를 진행합니다.

Unity용 Firebase SDK 추가

  1. Firebase 콘솔에서 Firebase Unity SDK 다운로드를 클릭합니다.
  2. 편리한 곳에 SDK의 압축을 풉니다.
  3. 열려 있는 Unity 프로젝트에서 Assets > Import Package > Custom Package 로 이동합니다.
  4. 패키지 가져오기 대화 상자에서 압축을 푼 SDK가 포함된 디렉터리로 이동하여 FirebaseAnalytics.unitypackage 선택한 다음 열기를 클릭합니다.
  5. 나타나는 Unity 패키지 가져오기 대화 상자에서 가져오기 를 클릭합니다.
  6. FirebaseCrashlytics.unitypackage 가져오려면 이전 단계를 반복하세요.
  7. Firebase 콘솔로 돌아가 설정 워크플로에서 다음 을 클릭합니다.

Unity 프로젝트에 Firebase SDK를 추가하는 방법에 대한 자세한 내용은 추가 Unity 설치 옵션을 참조하세요.

4. Unity 프로젝트에서 Crashlytics 설정

Unity 프로젝트에서 Crashlytics를 사용하려면 몇 가지 설정 단계를 더 수행해야 합니다. 물론 SDK를 초기화해야 합니다. 그러나 또한 Firebase 콘솔에서 기호화된 스택 추적을 볼 수 있도록 기호를 업로드해야 하며, Firebase가 충돌 이벤트를 수신하는지 확인하기 위해 강제로 테스트 충돌을 실행해야 합니다.

Crashlytics SDK 초기화

  1. Assets/Hamster/Scripts/MainGame.cs 에 다음 using 문을 추가합니다.
    using Firebase.Crashlytics;
    using Firebase.Extensions;
    
    첫 번째 모듈을 사용하면 Crashlytics SDK의 메서드를 사용할 수 있고 두 번째 모듈 에는 C# Tasks API 에 대한 일부 확장이 포함되어 있습니다. 두 개의 using 문이 모두 없으면 다음 코드는 작동하지 않습니다.
  2. 여전히 MainGame.cs 에서 초기화 InitializeFirebaseAndStartGame() 을 호출하여 기존 Start() 메서드에 Firebase 초기화를 추가합니다.
    void Start()
    {
      Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
      InitializeFirebaseAndStartGame();
    }
    
  3. 그리고 다시 MainGame.cs 에서 InitializeFirebaseAndStartGame() 찾아 앱 변수를 선언한 다음 다음과 같이 메서드 구현을 덮어씁니다.
    public Firebase.FirebaseApp app = null;
    
    // Begins the firebase initialization process and afterwards, opens the main menu.
    private void InitializeFirebaseAndStartGame()
    {
      Firebase.FirebaseApp.CheckAndFixDependenciesAsync()
      .ContinueWithOnMainThread(
        previousTask => 
        {
          var dependencyStatus = previousTask.Result;
          if (dependencyStatus == Firebase.DependencyStatus.Available) {
            // Create and hold a reference to your FirebaseApp,
            app = Firebase.FirebaseApp.DefaultInstance;
            // Set the recommended Crashlytics uncaught exception behavior.
            Crashlytics.ReportUncaughtExceptionsAsFatal = true;
            InitializeCommonDataAndStartGame();
          } else {
            UnityEngine.Debug.LogError(
              $"Could not resolve all Firebase dependencies: {dependencyStatus}\n" +
              "Firebase Unity SDK is not safe to use here");
          }
        });
    }
    

여기에 초기화 로직을 배치하면 Firebase 종속성이 초기화되기 전에 플레이어 상호작용이 방지됩니다.

처리되지 않은 예외를 치명적인 것으로 보고할 때의 이점과 효과는 Crashlytics FAQ 에서 논의됩니다.

프로젝트 빌드 및 기호 업로드

iOS 앱과 Android 앱에서는 심볼을 만들고 업로드하는 단계가 다릅니다.

iOS+(애플 플랫폼)

  1. 빌드 설정 대화 상자에서 프로젝트를 Xcode 작업 공간으로 내보냅니다.
  2. 앱을 빌드하세요.
    Apple 플랫폼의 경우 Firebase Unity 편집기 플러그인은 각 빌드에 대해 Crashlytics 호환 기호 파일을 생성하고 Firebase 서버에 업로드하도록 Xcode 프로젝트를 자동으로 구성합니다. Crashlytics 대시보드에서 기호화된 스택 추적을 보려면 이 기호 정보가 필요합니다.

기계적 인조 인간

  1. (각 빌드가 아닌 초기 설정 중에만) 빌드를 설정합니다.
    1. 프로젝트 디렉터리의 루트(예: Assets 디렉터리의 형제)에 Builds 라는 새 폴더를 만든 다음 Android 라는 하위 폴더를 만듭니다.
    2. 파일 > 빌드 설정 > 플레이어 설정 > 구성 에서 스크립팅 백엔드를 IL2CPP로 설정합니다.
      • IL2CPP는 일반적으로 빌드 크기를 줄이고 성능을 향상시킵니다.
      • IL2CPP는 iOS에서 유일하게 사용할 수 있는 옵션이기도 하며 여기에서 이 옵션을 선택하면 두 플랫폼의 패리티가 향상되고 두 플랫폼 간의 디버깅 차이점이 더 간단해집니다(둘 다 빌드하려는 경우).
  2. 앱을 빌드하세요. 파일 > 빌드 설정 에서 다음을 완료합니다.
    1. Create Symbols.zip이 선택되어 있는지 확인하십시오(또는 드롭다운이 표시되는 경우 디버깅 선택).
    2. Unity Editor에서 방금 만든 Builds/Android 하위 폴더로 APK를 직접 빌드하세요.
  3. 빌드가 완료되면 Crashlytics 호환 기호 파일을 생성하여 Firebase 서버에 업로드해야 합니다. Crashlytics 대시보드에서 네이티브 라이브러리 충돌에 대한 기호화된 스택 추적을 보려면 이 기호 정보가 필요합니다.

    다음 Firebase CLI 명령어
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    를 실행하여 이 기호 파일을 생성하고 업로드합니다.
    • FIREBASE_APP_ID : Firebase Android 앱 ID(패키지 이름 아님) 이전에 다운로드한 google-services.json 파일에서 이 값을 찾으세요. mobilesdk_app_id 값입니다.
      예 Firebase Android 앱 ID: 1:567383003300:android:17104a2ced0c9b9b
    • PATH/TO/SYMBOLS : 빌드가 완료될 때 Builds/Android 디렉터리에 생성된 압축된 기호 파일의 경로입니다(예: Builds/Android/myapp-1.0-v100.symbols.zip ).

강제로 테스트 충돌을 발생시켜 설정을 완료하세요.

Crashlytics 설정을 완료하고 Firebase 콘솔의 Crashlytics 대시보드에서 초기 데이터를 보려면 강제로 테스트 충돌을 발생시켜야 합니다.

  1. MainGameSceneHierarchy 편집기에서 EmptyObject GameObject 찾고 여기에 다음 스크립트를 추가한 후 장면을 저장합니다. 이 스크립트는 앱을 실행한 후 몇 초 후에 테스트 충돌을 발생시킵니다.
    using System;
    using UnityEngine;
    
    public class CrashlyticsTester : MonoBehaviour {
        // Update is called once per frame
        void Update()
        {
            // Tests your Crashlytics implementation by
            // throwing an exception every 60 frames.
            // You should see reports in the Firebase console
            // a few minutes after running your app with this method.
            if(Time.frameCount >0 && (Time.frameCount%60) == 0)
            {
                throw new System.Exception("Test exception; please ignore");
            }
        }
    }
    
  2. 빌드가 완료된 후 앱을 빌드하고 기호 정보를 업로드하세요.
    • iOS : Firebase Unity 편집기 플러그인은 기호 파일을 업로드하도록 Xcode 프로젝트를 자동으로 구성합니다.
    • Android : Firebase CLI crashlytics:symbols:upload 명령을 실행하여 기호 파일을 업로드합니다.
  3. 앱을 실행하세요. 앱이 실행되면 기기 로그를 확인하고 CrashlyticsTester 에서 예외가 트리거될 때까지 기다립니다.
    • iOS : Xcode 하단 창에서 로그를 봅니다.
    • Android : 터미널에서 adb logcat 명령을 실행하여 로그를 봅니다.
  4. 예외를 보려면 Crashlytics 대시보드를 방문하세요. 대시보드 하단의 문제 표에서 확인할 수 있습니다. Codelab 후반부에서 이러한 보고서를 탐색하는 방법을 자세히 알아봅니다.
  5. 이벤트가 Crashlytics에 업로드되었음을 확인한 후에는 이벤트를 연결한 빈 개체 GameObject 선택하고 CrashlyticsTester 구성 요소만 제거한 다음 장면을 저장하여 원래 상태로 복원합니다.

5. 디버그 메뉴 활성화 및 이해

지금까지 Unity 프로젝트에 Crashlytics를 추가하고 설정을 완료했으며 Crashlytics SDK가 Firebase에 이벤트를 업로드하는 것을 확인했습니다. 이제 Unity 프로젝트에서 게임에서 고급 Crashlytics 기능을 사용하는 방법을 보여주는 메뉴를 만듭니다. Firebase Unity로 레벨업 프로젝트에는 표시하고 해당 기능을 작성할 수 있는 숨겨진 디버그 메뉴가 이미 있습니다.

디버그 메뉴 활성화

디버그 메뉴에 액세스하는 버튼이 Unity 프로젝트에 있지만 현재 활성화되어 있지 않습니다. MainMenu 프리팹에서 액세스하려면 버튼을 활성화해야 합니다.

  1. Unity 에디터에서 MainMenu 라는 프리팹을 엽니다. 4148538cbe9f36c5.png
  2. 프리팹 계층 구조에서 DebugMenuButton 이라는 비활성화된 하위 개체를 찾아 선택합니다. 816f8f9366280f6c.png
  3. DebugMenuButton 포함하는 텍스트 필드 왼쪽 상단에 있는 상자를 선택하여 DebugMenuButton 을 활성화합니다. 8a8089d2b4886da2.png
  4. 프리팹을 저장합니다.
  5. 편집기나 장치에서 게임을 실행하세요. 이제 메뉴에 접근할 수 있습니다.

디버그 메뉴의 메서드 본문을 미리 보고 이해합니다.

이 Codelab의 뒷부분에서는 사전 구성된 일부 디버그 Crashlytics 메서드에 대한 메서드 본문을 작성합니다. 하지만 Level Up with Firebase Unity 프로젝트에서는 메서드가 DebugMenu.cs 에서 정의되고 호출됩니다.

이러한 메서드 중 일부는 Crashlytics 메서드를 호출하고 오류를 발생시키지만 Crashlytics에서 이러한 오류를 포착하는 기능은 해당 메서드를 먼저 호출하는 것에 달려 있지 않습니다. 오히려 자동으로 오류를 포착하여 생성된 충돌 보고서는 이러한 방법으로 추가된 정보를 통해 향상됩니다.

DebugMenu.cs 열고 다음 메서드를 찾습니다.

Crashlytics 문제를 생성하고 주석을 추가하는 방법:

  • CrashNow
  • LogNonfatalError
  • LogStringsAndCrashNow
  • SetAndOverwriteCustomKeyThenCrash
  • SetLogsAndKeysBeforeANR

디버깅에 도움이 되도록 Analytics 이벤트를 기록하는 방법:

  • LogProgressEventWithStringLiterals
  • LogIntScoreWithBuiltInEventAndParams

이 Codelab의 이후 단계에서는 이러한 메서드를 구현하고 게임 개발에서 발생할 수 있는 특정 상황을 해결하는 데 어떻게 도움이 되는지 알아봅니다.

6. 개발 중 충돌 보고서 전달 보장

이러한 디버그 방법을 구현하고 충돌 보고서에 어떤 영향을 미치는지 확인하기 전에 이벤트가 Crashlytics에 보고되는 방식을 이해해야 합니다.

Unity 프로젝트의 경우 게임의 충돌 및 예외 이벤트가 즉시 디스크에 기록됩니다. 게임을 충돌시키지 않는 포착되지 않은 예외(예: 게임 로직에서 포착되지 않은 C# 예외)의 경우 Unity 프로젝트에서 Crashlytics를 초기화하는 곳에서 Crashlytics.ReportUncaughtExceptionsAsFatal 속성을 true 로 설정하여 Crashlytics SDK가 이를 치명적인 이벤트로 보고하도록 할 수 있습니다. . 이러한 이벤트는 최종 사용자가 게임을 다시 시작할 필요 없이 실시간으로 Crashlytics에 보고됩니다. 기본 충돌은 항상 치명적인 이벤트로 보고되고 최종 사용자가 게임을 다시 시작할 때 함께 전송됩니다.

또한 다양한 런타임 환경에서 Crashlytics 정보를 Firebase로 전송하는 방법에는 다음과 같은 작지만 중요한 차이점이 있다는 점에 유의하세요.

iOS 시뮬레이터:

  • Crashlytics 정보는 시뮬레이터에서 Xcode를 분리한 경우에만 보고됩니다. Xcode가 첨부되면 업스트림에서 오류를 포착하여 정보 전달을 방해합니다.

모바일 실제 장치(Android 및 iOS):

  • Android 관련: ANR은 Android 11 이상에서만 보고됩니다. ANR 및 치명적이지 않은 이벤트는 다음 실행 시 보고됩니다.

유니티 에디터:

CrashNow() 에서 버튼을 터치하여 게임 충돌을 테스트하세요.

Crashlytics가 게임에 설정되면 Crashlytics SDK는 충돌 및 포착되지 않은 예외를 자동으로 기록하고 분석을 위해 Firebase에 업로드합니다. 그리고 보고서는 Firebase 콘솔의 Crashlytics 대시보드 에 표시됩니다.

  1. 이것이 실제로 자동임을 입증하려면: DebugMenu.cs 열고
    void CrashNow()
    {
        TestCrash();
    }
    
    과 같이 CrashNow() 메서드를 덮어씁니다.
  2. 앱을 빌드하세요.
  3. (Android만 해당) 다음 Firebase CLI 명령어
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    실행하여 기호를 업로드하세요.
  4. 지금 충돌 버튼을 탭하고 이 Codelab의 다음 단계로 진행하여 충돌 보고서를 보고 해석하는 방법을 알아보세요.

7. Firebase 콘솔의 문제 보고서 이해

충돌 보고서를 볼 때 이를 최대한 활용하는 방법에 대해 알아야 할 사항이 조금 더 있습니다. 작성하는 각 방법은 Crashlytics 보고서에 다양한 유형의 정보를 추가하는 방법을 보여줍니다.

  1. 지금 충돌 버튼을 누른 다음 앱을 다시 시작하세요.
  2. Crashlytics 대시보드 로 이동합니다. Crashlytics가 근본 원인이 모두 동일한 이벤트를 '문제'로 그룹화하는 대시보드 하단의 문제 표까지 아래로 스크롤합니다.
  3. 문제 표에 나열된 새 문제를 클릭합니다. 이렇게 하면 Firebase로 전송된 각 개별 이벤트에 대한 이벤트 요약이 표시됩니다.

    다음 화면 캡처와 같은 내용이 표시되어야 합니다. 이벤트 요약에는 충돌을 일으킨 호출의 스택 추적이 어떻게 눈에 띄게 표시되는지 확인하세요. 40c96abe7f90c3aa.png

추가 메타데이터

또 다른 유용한 탭은 Unity Metadata 탭입니다. 이 섹션에서는 물리적 기능, CPU 모델/사양, 모든 종류의 GPU 지표를 포함하여 이벤트가 발생한 장치의 속성에 대해 알려줍니다.

다음은 이 탭의 정보가 유용할 수 있는 예입니다.
게임이 특정 모양을 구현하기 위해 셰이더를 많이 사용하지만 모든 휴대폰에 이 기능을 렌더링할 수 있는 GPU가 있는 것은 아니라고 상상해 보세요. Unity 메타데이터 탭의 정보는 자동으로 사용 가능하게 하거나 완전히 비활성화할 기능을 결정할 때 앱에서 테스트해야 하는 하드웨어에 대한 더 나은 아이디어를 제공할 수 있습니다.

실제 사용되는 Android 기기는 엄청나게 다양하기 때문에 기기 에 버그나 충돌이 절대 발생하지 않을 수도 있지만, 이는 사용자 기기의 특정 '핫스팟'을 더 잘 이해하는 데 도움이 됩니다.

41d8d7feaa87454d.png

8. 예외 발생, 포착 및 기록

개발자로서 코드에서 런타임 예외를 적절하게 포착하고 처리하더라도 해당 예외가 어떤 상황에서 발생했는지 알아두는 것이 좋습니다. Crashlytics.LogException Firebase 콘솔에서 문제를 추가로 디버깅할 수 있도록 Firebase에 예외 이벤트를 보내는 정확한 목적으로 사용될 수 있습니다.

  1. Assets/Hamster/Scripts/States/DebugMenu.cs 에서 using 문에 다음을 추가합니다.
    // Import Firebase
    using Firebase.Crashlytics;
    
  2. 여전히 DebugMenu.cs 에서 LogNonfatalError() 다음과 같이 덮어씁니다:
    void LogNonfatalError()
    {
        try
        {
            throw new System.Exception($"Test exception thrown in {nameof(LogNonfatalError)}");
        }
        catch(System.Exception exception)
        {
            Crashlytics.LogException(exception);
        }
    }
    
  3. 앱을 빌드하세요.
  4. (Android만 해당) 다음 Firebase CLI 명령어
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    실행하여 기호를 업로드하세요.
  5. 치명적이지 않은 오류 기록 버튼을 누른 다음 앱을 다시 시작하세요.
  6. Crashlytics 대시보드 로 이동하면 이 Codelab의 마지막 단계에서 본 것과 비슷한 내용이 표시됩니다.
  7. 하지만 이번에는 방금 기록한 오류와 같은 치명적이지 않은 오류만 볼 수 있도록 이벤트 유형 필터를 치명적 이지 않은 오류로 제한하세요.
    a39ea8d9944cbbd9.png

9. 프로그램 실행 흐름을 더 잘 이해하기 위해 Crashlytics에 문자열을 기록합니다.

세션당 수천 번은 아니더라도 여러 경로에서 호출되는 코드 줄이 갑자기 예외나 충돌을 생성할 수 있는 이유를 알아내려고 시도해 본 적이 있습니까? IDE에서 코드를 단계별로 실행하고 값을 더 자세히 살펴보는 것이 좋을 수도 있지만, 이것이 극히 소수의 사용자에게만 발생한다면 어떻게 될까요? 더 나쁜 것은, 무엇을 하든 이 충돌을 재현할 수 없다면 어떻게 하시겠습니까?

이와 같은 상황에서는 어떤 맥락을 갖는 것이 세상을 변화시킬 수 있습니다. Crashlytics.Log 사용하면 필요한 컨텍스트를 작성할 수 있습니다. 이 메시지를 미래의 자신에게 앞으로 일어날 일에 대한 힌트로 생각하십시오.

로그는 다양한 방식으로 사용될 수 있지만 일반적으로 통화 순서 및/또는 부재가 매우 중요한 정보인 상황을 기록하는 데 가장 유용합니다.

  1. Assets/Hamster/Scripts/States/DebugMenu.cs 에서 LogStringsAndCrashNow() 다음과 같이 덮어씁니다:
    void LogStringsAndCrashNow()
    {
        Crashlytics.Log($"This is the first of two descriptive strings in {nameof(LogStringsAndCrashNow)}");
        const bool RUN_OPTIONAL_PATH = false;
        if(RUN_OPTIONAL_PATH)
        {
            Crashlytics.Log(" As it stands, this log should not appear in your records because it will never be called.");
        }
        else
        {
            Crashlytics.Log(" A log that will simply inform you which path of logic was taken. Akin to print debugging.");
        }
        Crashlytics.Log($"This is the second of two descriptive strings in {nameof(LogStringsAndCrashNow)}");
        TestCrash();
    }
    
  2. 앱을 빌드하세요.
  3. (Android만 해당) 다음 Firebase CLI 명령어
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    실행하여 기호를 업로드합니다.
  4. 로그 문자열 및 지금 충돌 버튼을 누른 다음 앱을 다시 시작하세요.
  5. Crashlytics 대시보드 로 돌아가서 문제 표에 나열된 최신 문제를 클릭하세요. 이번에도 이전 문제와 비슷한 내용이 표시되어야 합니다.
    7aabe103b8589cc7.png
  6. 그러나 이벤트 요약 내에서 로그 탭을 클릭하면 다음과 같은 보기가 표시됩니다.
    4e27aa407b7571cf.png

10. 사용자 정의 키 작성 및 덮어쓰기

소수의 값이나 구성으로 설정된 변수에 해당하는 충돌을 더 잘 이해하고 싶다고 가정해 보겠습니다. 언제든지 보고 있는 변수와 가능한 값의 조합을 기반으로 필터링할 수 있으면 좋을 것입니다.

임의 문자열을 기록하는 것 외에도 Crashlytics는 프로그램이 충돌할 때 정확한 상태를 아는 것이 유용한 경우 또 다른 형태의 디버깅, 즉 맞춤 키를 제공합니다.

이는 세션에 대해 설정할 수 있는 키-값 쌍입니다. 누적되고 순전히 추가되는 로그와 달리 키는 변수나 조건의 가장 최근 상태만 반영하도록 덮어쓸 수 있습니다.

이러한 키는 프로그램의 마지막으로 기록된 상태에 대한 원장일 뿐만 아니라 Crashlytics 문제에 대한 강력한 필터로 사용될 수 있습니다.

  1. Assets/Hamster/Scripts/States/DebugMenu.cs 에서 다음과 같이 SetAndOverwriteCustomKeyThenCrash() 덮어씁니다:
    void SetAndOverwriteCustomKeyThenCrash()
    {
        const string CURRENT_TIME_KEY = "Current Time";
        System.TimeSpan currentTime = System.DateTime.Now.TimeOfDay;
        Crashlytics.SetCustomKey(
            CURRENT_TIME_KEY,
            DayDivision.GetPartOfDay(currentTime).ToString() // Values must be strings
            );
    
        // Time Passes
        currentTime += DayDivision.DURATION_THAT_ENSURES_PHASE_CHANGE;
    
        Crashlytics.SetCustomKey(
            CURRENT_TIME_KEY,
            DayDivision.GetPartOfDay(currentTime).ToString()
            );
        TestCrash();
    }
    
  2. 앱을 빌드하세요.
  3. (Android만 해당) 다음 Firebase CLI 명령어
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    실행하여 기호를 업로드하세요.
  4. 사용자 정의 키 및 충돌 설정 버튼을 누른 다음 앱을 다시 시작하세요.
  5. Crashlytics 대시보드 로 돌아가서 문제 표에 나열된 최신 문제를 클릭하세요. 이번에도 이전 문제와 비슷한 내용이 표시되어야 합니다.
  6. 하지만 이번에는 이벤트 요약 에서 탭을 클릭하여 Current Time 포함한 키 값을 볼 수 있습니다.
    7dbe1eb00566af98.png

사용자 정의 로그 대신 사용자 정의 키를 사용하려는 이유는 무엇입니까?

  • 로그는 순차 데이터를 저장하는 데 적합하지만 최신 값만 원하는 경우에는 사용자 지정 키가 더 좋습니다.
  • Firebase 콘솔에서는 문제 테이블 검색창의 키 값을 기준으로 문제를 쉽게 필터링할 수 있습니다.

그러나 로그와 유사하게 사용자 정의 키에는 제한이 있습니다. Crashlytics는 최대 64개의 키-값 쌍을 지원합니다. 이 임계값에 도달한 후에는 추가 값이 저장되지 않습니다. 각 키-값 쌍의 크기는 최대 1KB입니다.

11. (Android만 해당) 맞춤 키와 로그를 사용하여 ANR을 이해하고 진단합니다.

Android 개발자가 디버깅하기 가장 어려운 문제 중 하나는 ANR( 애플리케이션 응답 없음 ) 오류입니다. ANR은 앱이 5초 이상 입력에 응답하지 못할 때 발생합니다. 이런 일이 발생하면 앱이 정지되었거나 매우 느리게 진행되고 있음을 의미합니다. 사용자에게 대화 상자가 표시되며 "대기" 또는 "앱 닫기"를 선택할 수 있습니다.

ANR은 좋지 않은 사용자 경험이며 (위 ANR 링크에서 언급한 바와 같이) Google Play 스토어에서 앱 검색 가능성에 영향을 미칠 수 있습니다. 복잡하고 다양한 휴대폰 모델에서 동작이 크게 다른 멀티스레드 코드로 인해 발생하는 경우가 많기 때문에 디버깅하는 동안 ANR을 재현하는 것은 거의 불가능하지는 않더라도 매우 어려운 경우가 많습니다. 따라서 분석적이고 연역적으로 접근하는 것이 일반적으로 최선의 접근 방식입니다.

이 방법에서는 Crashlytics.LogException , Crashlytics.LogCrashlytics.SetCustomKey 의 조합을 사용하여 자동 문제 로깅을 보완하고 추가 정보를 제공합니다.

  1. Assets/Hamster/Scripts/States/DebugMenu.cs 에서 다음과 같이 SetLogsAndKeysBeforeANR() 덮어씁니다:
    void SetLogsAndKeysBeforeANR()
    {
        System.Action<string,long> WaitAndRecord =
        (string methodName, long targetCallLength)=>
        {
            System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
            const string CURRENT_FUNCTION = "Current Async Function";
    
            // Initialize key and start timing
            Crashlytics.SetCustomKey(CURRENT_FUNCTION, methodName);
            stopWatch.Start();
    
            // The actual (simulated) work being timed.
            BusyWaitSimulator.WaitOnSimulatedBlockingWork(targetCallLength);
    
            // Stop timing
            stopWatch.Stop();
    
            if(stopWatch.ElapsedMilliseconds>=BusyWaitSimulator.EXTREME_DURATION_MILLIS)
            {
              Crashlytics.Log($"'{methodName}' is long enough to cause an ANR.");
            }
            else if(stopWatch.ElapsedMilliseconds>=BusyWaitSimulator.SEVERE_DURATION_MILLIS)
            {
              Crashlytics.Log($"'{methodName}' is long enough it may cause an ANR");
            }
        };
    
        WaitAndRecord("DoSafeWork",1000L);
        WaitAndRecord("DoSevereWork",BusyWaitSimulator.SEVERE_DURATION_MILLIS);
        WaitAndRecord("DoExtremeWork",2*BusyWaitSimulator.EXTREME_DURATION_MILLIS);
    }
    
  2. 앱을 빌드하세요.
  3. 다음 Firebase CLI 명령어
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    실행하여 기호를 업로드하세요.
  4. Set Logs And Keys → ANR 버튼을 탭한 후 앱을 다시 시작하세요.
  5. Crashlytics 대시보드 로 돌아가서 문제 표에서 새 문제를 클릭하여 이벤트 요약을 확인합니다. 통화가 제대로 진행되면 다음과 같은 내용이 표시됩니다.
    876c3cff7037bd07.png

    보시다시피 Firebase는 앱이 ANR을 트리거한 주요 원인으로 스레드의 바쁜 대기를 정확히 지적했습니다.
  6. 이벤트 요약로그 탭에 있는 로그를 보면 완료로 기록된 마지막 메소드가 DoSevereWork 임을 알 수 있습니다.
    5a4bec1cf06f6984.png

    이와 대조적으로 시작으로 나열된 마지막 메서드는 DoExtremeWork 입니다. 이는 이 메서드 중에 ANR이 발생했으며 DoExtremeWork 기록하기 전에 게임이 종료되었음을 나타냅니다.

    89d86d5f598ecf3a.png

왜 이런 일을 하는가?

  • ANR을 재현하는 것은 엄청나게 어렵기 때문에 코드 영역과 측정 항목에 대한 풍부한 정보를 얻을 수 있는 것은 연역적으로 이를 찾는 데 매우 중요합니다.
  • 사용자 정의 키에 저장된 정보를 통해 이제 실행하는 데 가장 오랜 시간이 걸리는 비동기 스레드와 ANR을 트리거할 위험이 있는 스레드를 알 수 있습니다. 이러한 종류의 관련 논리 및 숫자 데이터는 코드에서 최적화가 가장 필요한 위치를 보여줍니다.

12. 보고서를 더욱 풍부하게 하기 위한 분석 이벤트 삽입

다음 메소드는 디버그 메뉴에서도 호출할 수 있지만 자체적으로 문제를 생성하는 대신 Google Analytics를 또 다른 정보 소스로 사용하여 게임 작동을 더 잘 이해합니다.

이 Codelab에서 작성한 다른 방법과 달리 이러한 방법은 다른 방법과 조합하여 사용해야 합니다. 다른 메서드 중 하나를 실행하기 전에 원하는 임의의 순서로 이러한 메서드를 호출합니다(디버그 메뉴에서 해당 버튼을 눌러). 그런 다음 특정 Crashlytics 문제에 대한 정보를 검토하면 정렬된 Analytics 이벤트 로그가 표시됩니다. 이 데이터는 앱을 계측한 방식에 따라 프로그램 흐름이나 사용자 입력의 조합을 더 잘 이해하기 위해 게임에서 사용할 수 있습니다.

  1. Assets/Hamster/Scripts/States/DebugMenu.cs 에서 다음 메서드의 기존 구현을 덮어씁니다:
    public void LogProgressEventWithStringLiterals()
    {
          Firebase.Analytics.FirebaseAnalytics.LogEvent("progress", "percent", 0.4f);
    }
    
    public void LogIntScoreWithBuiltInEventAndParams()
    {
          Firebase.Analytics.FirebaseAnalytics
            .LogEvent(
              Firebase.Analytics.FirebaseAnalytics.EventPostScore,
              Firebase.Analytics.FirebaseAnalytics.ParameterScore,
              42
            );
    }
    
  2. 게임을 빌드하고 배포한 다음 디버그 메뉴 로 들어갑니다.
  3. (Android만 해당) 다음 Firebase CLI 명령어
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    실행하여 기호를 업로드합니다.
  4. 위 기능을 호출하려면 다음 버튼 중 하나 이상을 한 번 이상 누르세요.
    • 로그 문자열 이벤트
    • 로그인 이벤트
  5. 지금 충돌 버튼을 누릅니다.
  6. 게임을 다시 시작하여 충돌 이벤트를 Firebase에 업로드하세요.
  7. 다양한 임의 시퀀스의 Analytics 이벤트를 기록한 다음 게임에서 Crashlytics가 보고서를 생성하는 이벤트를 생성하도록 하면 다음과 같이 Crashlytics 이벤트 요약로그 탭에 해당 이벤트가 추가됩니다.
    d3b16d78f76bfb04.png

13. 앞으로

이를 통해 자동으로 생성된 충돌 보고서를 보완할 수 있는 더 나은 이론적 기반을 갖게 됩니다. 이 새로운 정보를 통해 현재 상태, 과거 이벤트 기록, 기존 Google Analytics 이벤트를 사용하여 결과를 가져온 이벤트 및 논리의 순서를 더욱 효과적으로 분석할 수 있습니다.

앱이 Android 11(API 수준 30) 이상을 타겟팅하는 경우 use-after-freeheap-buffer-overflow 오버플로 버그와 같은 기본 메모리 오류로 인한 충돌을 디버깅하는 데 유용한 기본 메모리 할당자 기능인 GWP-ASan을 통합하는 것이 좋습니다. 이 디버깅 기능을 활용하려면 GWP-ASan을 명시적으로 사용 설정하세요 .

다음 단계

원격 구성 Codelab을 사용하여 Unity 게임 계측 으로 진행하여 Unity에서 원격 구성 및 A/B 테스트를 사용하는 방법을 알아보세요.