LoginSignup
6
6

More than 1 year has passed since last update.

iOS14で強化されたMetricKitで不具合対応に備える

Last updated at Posted at 2021-06-29

MetricKitとは

  • MXMetricPayload
    • iOS13以降対応
    • アプリの基本情報、診断、パフォーマンスを取得可能
    • 過去24時間のデータを含むレポートを最大で1日1回受信
  • MXDiagnosticPayload 
    • iOS14以降対応
    • クラッシュやユーザがアプリを利用する上での障害情報

利用用途

  • 利用者の端末情報蓄積
  • 不具合対応の情報取得

取得できるデータについて

MXMetricPayload

  • パフォーマンス
    • CPU情報
    • ディスプレイ情報
    • GPU情報
    • 位置情報
    • ネットワーク情報
  • 応答性
    • アプリの起動と再開
    • アニメーションの応答性
    • ユーザインタラクションに対する応答性
  • ストレージ
    • ディスク情報

MXDiagnosticPayload

  • クラッシュ
    • クラッシュレポート
    • CPU例外レポート
    • アプリビジーレポート
    • ディスク書き込み例外レポート

導入方法について

AppDelegate.swift
/// 1. 使用の為にimport
import MetricKit
~  ~
extension AppDelegate: UIApplicationDelegate {
~  ~
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        if #available(iOS 13.0, *) {
            /// 2.起動時に登録
            MXMetricManager.shared.add(self)
        }
~  ~
    }

    func applicationWillTerminate(_ application: UIApplication) {
        if #available(iOS 13.0, *) {
            /// 3.終了時に解除
            MXMetricManager.shared.remove(self)
        }
    }
}

extension AppDelegate: MXMetricManagerSubscriber {
    /// 4.情報を取得する(MXMetricPayload)
    @available(iOS 13.0, *)
    func didReceive(_ payloads: [MXMetricPayload]) {
        for payload in payloads {
            let json = payload.jsonRepresentation()
            let jsonString = String(data: json, encoding: .utf8) ?? .empty
            Log.info("[MXMetricPayload] \(jsonString)")
        }
    }

    /// 5.情報を取得する(MXDiagnosticPayload)
    @available(iOS 14.0, *)
    func didReceive(_ payloads: [MXDiagnosticPayload]) {
        for payload in payloads {
            let json = payload.jsonRepresentation()
            let jsonString = String(data: json, encoding: .utf8) ?? .empty
            Log.info("[MXDiagnosticPayload] \(jsonString)")
        }
    }
}

サンプルログ

MXMetricPayloadのログ

  • Xcodeのデバッグ機能を用いたログ
MXMetricPayload.log
{
  "locationActivityMetrics" : {
    "cumulativeBestAccuracyForNavigationTime" : "20秒",
    "cumulativeBestAccuracyTime" : "30秒",
    "cumulativeHundredMetersAccuracyTime" : "30秒",
    "cumulativeNearestTenMetersAccuracyTime" : "30秒",
    "cumulativeKilometerAccuracyTime" : "20秒",
    "cumulativeThreeKilometersAccuracyTime" : "20秒"
  },
  "cellularConditionMetrics" : {
    "cellConditionTime" : {
      "histogramNumBuckets" : 3,
      "histogramValue" : {
        "0" : {
          "bucketCount" : 20,
          "bucketStart" : "1 bars",
          "bucketEnd" : "1 bars"
        },
        "1" : {
          "bucketCount" : 30,
          "bucketStart" : "2 bars",
          "bucketEnd" : "2 bars"
        },
        "2" : {
          "bucketCount" : 50,
          "bucketStart" : "3 bars",
          "bucketEnd" : "3 bars"
        }
      }
    }
  },
  "metaData" : {
    "appBuildVersion" : "53",
    "osVersion" : "iPhone OS 14.1 (18A8395)",
    "regionFormat" : "JP",
    "platformArchitecture" : "arm64e",
    "deviceType" : "iPhone13,4"
  },
  "gpuMetrics" : {
    "cumulativeGPUTime" : "20秒"
  },
  "memoryMetrics" : {
    "peakMemoryUsage" : "200,000 kB",
    "averageSuspendedMemory" : {
      "averageValue" : "100,000 kB",
      "standardDeviation" : 0,
      "sampleCount" : 500
    }
  },
  "applicationExitMetrics" : {
    "backgroundExitData" : {
      "cumulativeAppWatchdogExitCount" : 1,
      "cumulativeMemoryResourceLimitExitCount" : 1,
      "cumulativeBackgroundURLSessionCompletionTimeoutExitCount" : 1,
      "cumulativeBackgroundFetchCompletionTimeoutExitCount" : 1,
      "cumulativeAbnormalExitCount" : 1,
      "cumulativeSuspendedWithLockedFileExitCount" : 1,
      "cumulativeIllegalInstructionExitCount" : 1,
      "cumulativeMemoryPressureExitCount" : 1,
      "cumulativeBadAccessExitCount" : 1,
      "cumulativeCPUResourceLimitExitCount" : 1,
      "cumulativeBackgroundTaskAssertionTimeoutExitCount" : 1,
      "cumulativeNormalAppExitCount" : 1
    },
    "foregroundExitData" : {
      "cumulativeBadAccessExitCount" : 1,
      "cumulativeAbnormalExitCount" : 1,
      "cumulativeMemoryResourceLimitExitCount" : 1,
      "cumulativeNormalAppExitCount" : 1,
      "cumulativeCPUResourceLimitExitCount" : 1,
      "cumulativeIllegalInstructionExitCount" : 1,
      "cumulativeAppWatchdogExitCount" : 1
    }
  },
  "displayMetrics" : {
    "averagePixelLuminance" : {
      "averageValue" : "50 apl",
      "standardDeviation" : 0,
      "sampleCount" : 500
    }
  },
  "signpostMetrics" : [
    {
      "signpostIntervalData" : {
        "histogrammedSignpostDurations" : {
          "histogramNumBuckets" : 3,
          "histogramValue" : {
            "0" : {
              "bucketCount" : 50,
              "bucketStart" : "0 ms",
              "bucketEnd" : "100 ms"
            },
            "1" : {
              "bucketCount" : 60,
              "bucketStart" : "100 ms",
              "bucketEnd" : "400 ms"
            },
            "2" : {
              "bucketCount" : 30,
              "bucketStart" : "400 ms",
              "bucketEnd" : "700 ms"
            }
          }
        },
        "signpostCumulativeCPUTime" : "30,000 ms",
        "signpostAverageMemory" : "100,000 kB",
        "signpostCumulativeLogicalWrites" : "600 kB"
      },
      "signpostCategory" : "TestSignpostCategory1",
      "signpostName" : "TestSignpostName1",
      "totalSignpostCount" : 30
    },
    {
      "signpostIntervalData" : {
        "histogrammedSignpostDurations" : {
          "histogramNumBuckets" : 3,
          "histogramValue" : {
            "0" : {
              "bucketCount" : 60,
              "bucketStart" : "0 ms",
              "bucketEnd" : "200 ms"
            },
            "1" : {
              "bucketCount" : 70,
              "bucketStart" : "201 ms",
              "bucketEnd" : "300 ms"
            },
            "2" : {
              "bucketCount" : 80,
              "bucketStart" : "301 ms",
              "bucketEnd" : "500 ms"
            }
          }
        },
        "signpostCumulativeCPUTime" : "50,000 ms",
        "signpostAverageMemory" : "60,000 kB",
        "signpostCumulativeLogicalWrites" : "700 kB"
      },
      "signpostCategory" : "TestSignpostCategory2",
      "signpostName" : "TestSignpostName2",
      "totalSignpostCount" : 40
    }
  ],
  "cpuMetrics" : {
    "cumulativeCPUTime" : "100秒",
    "cumulativeCPUInstructions" : "100 kiloinstructions"
  },
  "networkTransferMetrics" : {
    "cumulativeCellularDownload" : "80,000 kB",
    "cumulativeWifiDownload" : "60,000 kB",
    "cumulativeCellularUpload" : "70,000 kB",
    "cumulativeWifiUpload" : "50,000 kB"
  },
  "diskIOMetrics" : {
    "cumulativeLogicalWrites" : "1,300 kB"
  },
  "applicationLaunchMetrics" : {
    "histogrammedTimeToFirstDrawKey" : {
      "histogramNumBuckets" : 3,
      "histogramValue" : {
        "0" : {
          "bucketCount" : 50,
          "bucketStart" : "1,000 ms",
          "bucketEnd" : "1,010 ms"
        },
        "1" : {
          "bucketCount" : 60,
          "bucketStart" : "2,000 ms",
          "bucketEnd" : "2,010 ms"
        },
        "2" : {
          "bucketCount" : 30,
          "bucketStart" : "3,000 ms",
          "bucketEnd" : "3,010 ms"
        }
      }
    },
    "histogrammedResumeTime" : {
      "histogramNumBuckets" : 3,
      "histogramValue" : {
        "0" : {
          "bucketCount" : 60,
          "bucketStart" : "200 ms",
          "bucketEnd" : "210 ms"
        },
        "1" : {
          "bucketCount" : 70,
          "bucketStart" : "300 ms",
          "bucketEnd" : "310 ms"
        },
        "2" : {
          "bucketCount" : 80,
          "bucketStart" : "500 ms",
          "bucketEnd" : "510 ms"
        }
      }
    }
  },
  "applicationTimeMetrics" : {
    "cumulativeForegroundTime" : "700秒",
    "cumulativeBackgroundTime" : "40秒",
    "cumulativeBackgroundAudioTime" : "30秒",
    "cumulativeBackgroundLocationTime" : "30秒"
  },
  "timeStampEnd" : "2021-06-21 14:59:00 +0000",
  "animationMetrics" : {
    "scrollHitchTimeRatio" : "1,000 ms per s"
  },
  "applicationResponsivenessMetrics" : {
    "histogrammedAppHangTime" : {
      "histogramNumBuckets" : 3,
      "histogramValue" : {
        "0" : {
          "bucketCount" : 50,
          "bucketStart" : "0 ms",
          "bucketEnd" : "100 ms"
        },
        "1" : {
          "bucketCount" : 60,
          "bucketStart" : "100 ms",
          "bucketEnd" : "400 ms"
        },
        "2" : {
          "bucketCount" : 30,
          "bucketStart" : "400 ms",
          "bucketEnd" : "700 ms"
        }
      }
    }
  },
  "appVersion" : "9.3.3",
  "timeStampBegin" : "2021-06-20 15:00:00 +0000"
}

参考

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6