티스토리 뷰

공부

MetricKit 톺아보기

Zedd0202 2021. 7. 11. 14:40
반응형

 

안녕하세요 :) Zedd입니다.

오늘은 MetricKit에 대해서 아주 간단하게..톺아보는 시간..

 

# MetricKit?

- iOS 13에서 추가된 프레임워크

- MetricKit을 사용하면 시스템에서 캡쳐한 온디바이스 앱 진단, 전력, 성능 메트릭을 수신 가능.

(등록된 앱은 하루에 최대 한 번 이전 24시간에 대한 데이터가 포함된 보고서를 수신)

얘가 뭐하는 친구냐..잘 이해가 안가면 Firebase Crashlyitics / Performance 같은 SDK라고 생각하면 된다. 

근데 이거는 Third Party임 == 추가하면 앱 실행시간, 앱 size에 영향을 준다.

근데 MetricKit은 First Party라 추가 안해도 사용이 가능한 부분인거

 

내가 뭐 import MetricKit 하고 사용하지 않아도, 이미 Apple은 MetricKit에서 생성된 보고서를 보여주고 있음.

Xcode > Window > Organizer 에서 볼 수 있다. 

Launch Time

각각 메트릭마다 디바이스별로 볼 수 있고, Typical or Top을 선택할 수 있다. 

어떤 메트릭이냐에 따라 필터의 종류가 다르다. 

런치타임 같은 경우에는 특정 버전을 선택하면, 이전 버전에 비해서 얼마나 줄었는지 / 늘었는지도 나온다. 

위의 경우에는 현재 선택한 버전이 바로 직전의 버전보다 런치타임이 50ms 줄었다는 것을 볼 수 있다. 

 

런치타임 이외에도 

Launch Time

Metrics 섹션에서는 

- 배터리 사용량 / 디스크 쓰기 / Hang Rate / 메모리 / 스크롤링 / 종료에 대한 정보를 볼 수 있다.

Reports섹션에서는

- Crashes / 디스크 쓰기 / 에너지도 볼 수 있는데, (Metrics 섹션의 디스크 쓰기와는 다른 느낌;;)

그 중에서도 Crashes는

크래쉬 로그도 나온다. 앱버전, iOS 버전, 어떤 디바이스인지도!

 

# Custom

Apple이 기본적으로 제공해주지만, 내 맘대로 좀 더 커스텀 해보고 싶다(?)고 하면 MetricKit을 직접 쓰면 된다. 

MetricKit을 사용하려면 3단계 단계가 있음.

1. MetricKit 프레임워크를 코드에 연결하고 가져온다.

2. 프레임워크와의 접점 역할을 하는 클래스인 MetricManager의 shared 인스턴스를 만든다.

3. 프레임워크에서 메트릭 수신을 시작하려면 제공된 subscriber delegate 프로토콜 구현 

 

# 코드 

import MetricKit

class AppMetrics: NSObject, MXMetricManagerSubscriber {
    
    func receiveReports() {
       let shared = MXMetricManager.shared
       shared.add(self)
    }

    func pauseReports() {
       let shared = MXMetricManager.shared
       shared.remove(self)
    }

    // Receive daily metrics.
    func didReceive(_ payloads: [MXMetricPayload]) {
       // Process metrics.
        for payload in payloads {
            print(payload.dictionaryRepresentation)
        }
    }

    // Receive diagnostics immediately when available.
    func didReceive(_ payloads: [MXDiagnosticPayload]) {
       // Process diagnostics.
        for payload in payloads {
            print(payload.dictionaryRepresentation())
        }
    }
}

뭔가 Metric을 "구독"해야하는데, 그 구독자가 내가 만든 custom subscriber class가 되는것.

shared.add(self)

그래서 metric manager의 shared 인스턴스에 내 custom subscriber를 추가해주는 것을 볼 수 있다.

아래 코드가 3번에 해당하는 "프레임워크에서 메트릭 수신을 시작하려면 제공된 subscriber delegate 프로토콜 구현"이다. 

func didReceive(_ payloads: [MXMetricPayload]) {
        for payload in payloads {
            // Do something with metricPayload.
        }
}

위 메소드를 통해 Metric Payload를 수신할 수 있다. 

 

# 시스템이 MetricKit을 통해 Payload를 집계하고 App에 전달하는 방법

OS는 앱의 성능 데이터를 수동으로 집계한다.

이 데이터는 익명화(anonymized)되며 사용자 개인정보를 보호하도록 설계되어있음.

하루가 끝나면 해당 데이터는 MetricKit Playload로 번들링된다.

MetricKit Playload에는 launch times, CPU 시간, 메모리 등을 비롯한 다양한 데이터가 포함되어있음. 

 

# 테스트

// AppDelegate 
let metric = AppMetrics() // ✅

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
    	.....
        metric.receiveReports() // ✅
        return true
    }

AppDelegate쪽에 위에서 만든 AppMetrics 인스턴스를 만들고 리포트를 받겠다는 메소드 호출. 

receiveReports는 결국

shared.add(self)

이거 호출하는 거임 

 

빌드 후, Xcode의 Debug > Simulate MetricKit Payloads를 누르면 콘솔에 

오른쪽 그림과 같은 것들이 뜬다. 

Debug가 아닌 Release configuration에서는 Simulate MetricKit Payloads가 비활성화 되어있으니 참고! 

 

# 의문

Launch Time

Organizer에 "이미" 너무너무 잘 나와있는데,

MetricKit을 import하여 json을 받고 

[AnyHashable("crashDiagnostics"): <__NSArrayM 0x283764390>(
{
    callStackTree =     {
        callStackPerThread = 1;
        callStacks =         (
                        {
                callStackRootFrames =                 (
                                        {
                        address = 74565;
                        binaryName = testBinaryName;
                        binaryUUID = "BE6FD323-B011-4E67-925B-A60362A1ADFA";
                        offsetIntoBinaryTextSegment = 123;
                        sampleCount = 20;
                    }
                );
                threadAttributed = 1;
            }
        );
    };
    diagnosticMetaData =     {
        appBuildVersion = 1;
        appVersion = "1.0";
        deviceType = "iPhone13,3";
        exceptionCode = 0;
        exceptionType = 1;
        osVersion = "iPhone OS 14.4 (18D52)";
        platformArchitecture = arm64e;
        regionFormat = GB;
        signal = 11;
        terminationReason = "Namespace SIGNAL, Code 0xb";
        virtualMemoryRegionInfo = "0 is not in any region.  Bytes before following region: 4000000000 REGION TYPE                      START - END             [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL UNUSED SPACE AT START ---> __TEXT                 0000000000000000-0000000000000000 [   32K] r-x/r-x SM=COW  ...pp/Test";
    };
    version = "1.0.0";
}

이런 데이터를 로컬에 저장 or 서버에 보내서 기록해야하는 니즈(?)를 잘 모르겠다.

raywenderlich의 MetricKit 글을 보면, 

As you can see, this app is live and has real data to explore right in Xcode. This is because Apple presents most metrics data for free. However, importing the MetricKit framework means you can leverage this data further and link it with your own metrics. It also means you have greater flexibility on how it’s displayed if your server powers custom visualizations.

MetricKit을 import하면 이 데이터를 더 활용하고, 나만의 metric과 연결할 수 있다.
또한 서버가 커스텀 visualizations을 지원하는 경우, 표시 방법에 대해 더 큰 유연성을 가질 수 있다. 

라고 하는데....

1. 이미 Xcode가 너무 잘 보여주고 있고,

2. 나만의 metric과 어떤식으로 연결해야할지 감이 잘 안옴

3. 왜 이걸 import해서 로컬 or 서버에 기록 및 Readable하게 데이터 가공처리해야하는지 

아직까진 잘 모르겠다. 

뭔가 좋은 사례가 있으면 좋을텐데.. 

 

Xcode에서 보여주지 않는 메트릭도 있는 것 같다. 예를들어

MXLocationActivityMetric  

MXAppResponsivenessMetric

MXAnimationMetric

MXNetworkTransferMetric 

이런것들..?

이런 Metric을 분석하고 싶다면 추가하는게 맞는 듯....? 

 

뭔가 WWDC세션, 글들이 MetricKit으로 이런것들을 할 수 있어!!!!에 집중되어있고,

Raw Data를 어떤식으로 가공하여 어떤식으로 보여주는건지..? 이런것들이 생략되어 있어 아쉽다.

물론 이런 Raw Data를 너네가 보고싶은대로 custom해봐~~가 의도겠지만...

반응형

'공부' 카테고리의 다른 글

IDFA 관련 기록  (0) 2021.08.01
WWDC 21 ) Meet TextKit 2  (2) 2021.07.18
WWDC 21 ) Meet the UIKit button system  (3) 2021.07.04
WWDC 21 ) Adjust Your Layout with Keyboard Layout Guide  (2) 2021.06.18
HIG ) Inclusion  (1) 2021.06.12