Metrickit

dpearson2699/swift-ios-skills/skills/metrickit

作者 dpearson26998d90fd121a26无许可证1.1K 个星标收录于 2026年10月8日更新于 2026年10月8日仓库2个月前更新

Use when collecting or analyzing production iOS or iPadOS performance telemetry with MetricKit, including iOS 27 MetricManager async metric or diagnostic reports, hang or crash triage, custom signposts, extended launch measurement, durable export, or iOS 26 MXMetricManager compatibility.

AI 生成的概览

指导使用 MetricKit 采集和分析 iOS/iPadOS 生产环境性能遥测数据,包括报告、诊断与持久化导出。

功能
该技能为使用 Apple MetricKit 框架采集 iOS 和 iPadOS 应用生产环境性能遥测数据提供实现指导。内容涵盖创建 MetricManager、消费异步指标与诊断报告序列、排查卡顿、崩溃和资源异常、使用自定义 signpost、测量扩展启动工作,以及将报告持久化导出以便后续上传。它还说明了使用 MXMetricManager 的 iOS 26 兼容路径,并指向配套参考文件以获取扩展模式。
适用场景
适用于在基于 MetricKit 构建的 iOS 或 iPadOS 应用中添加或审查生产环境性能遥测。适合处理指标或诊断报告接入、卡顿与崩溃排查、自定义 signpost 指标、扩展启动测量或报告持久化导出等工作。在需要同时维护 iOS 26 兼容分支与较新的 MetricManager API 时也适用。
运行要求
需要采用 Apple MetricKit 框架的 iOS 或 iPadOS 应用项目以及 Swift 工具链;文中描述的 iOS 27 API 属于测试版,需使用正式发布的 Xcode 27 SDK 才能编译。该技能不包含脚本,只有说明文档和一份参考文档,并假定应用自身具备持久化存储与上传机制。

MetricKit

Use MetricKit for low-overhead production telemetry that complements local Instruments and Xcode Organizer analysis. On iOS and iPadOS 27, prefer the Swift-first MetricManager report sequences. Keep MXMetricManager only in an explicit iOS 26 compatibility branch.

Beta-sensitive: The iOS/iPadOS 27 surface below is based on Apple's current beta documentation. It has not been locally compiler-verified because Xcode 27 is unavailable in this environment. Re-check the linked Apple documentation and compile with the shipping Xcode 27 SDK before release.

Load MetricKit Extended and Compatibility Patterns [blocked] when implementing durable ingestion, detailed report analysis, or the iOS 26 compatibility path.

Contents

MetricManager Setup

At app launch, create and retain one long-lived MetricManager. Start exactly one consumer task for metricReports and one for diagnosticReports.

Both properties expose nonthrowing AsyncSequence values:

  • metricReports: some AsyncSequence<MetricReport, Never>
  • diagnosticReports: some AsyncSequence<DiagnosticReport, Never>

Apple documents that concurrent consumers of one sequence can receive nondeterministic subsets. Fan out only after the single consumer receives and durably stores a report; delayed subscription can miss reports.

swift
import MetricKit
@available(iOS 27.0, *)final class MetricsService {    private let manager = MetricManager()    private var metricTask: Task<Void, Never>?    private var diagnosticTask: Task<Void, Never>?
    func start(        persistMetric: @escaping @Sendable (MetricReport) async -> Void,        persistDiagnostic: @escaping @Sendable (DiagnosticReport) async -> Void    ) {        guard metricTask == nil, diagnosticTask == nil else { return }        let manager = manager
        metricTask = Task {            for await report in manager.metricReports {                await persistMetric(report)            }        }
        diagnosticTask = Task {            for await report in manager.diagnosticReports {                await persistDiagnostic(report)            }        }    }
    deinit {        metricTask?.cancel()        diagnosticTask?.cancel()    }}

The persistence closures are application-specific. Implement them with the durable-first workflow below rather than dropping, logging only, or directly uploading each report. If state-scoped metrics are needed, construct the manager with the documented init(enabledStateReportingDomains:) initializer and the required domains.

Receiving Metric Reports

MetricReport is Codable and Sendable. It describes an interval through:

  • timeRange: DateInterval
  • optional environment metadata
  • intervalEntries for full-day and shorter interval measurements
  • stateEntries for measurements associated with application states

Metric reports normally arrive on a daily cadence. Persist the complete report before extracting individual results.

For daily analysis, read the documented fullDayEntry and switch over its MetricResult values:

swift
let entry = report.intervalEntries.fullDayEntry
for result in entry.values {    switch result {    case .hangTime(let metric):        analyzeHangTime(metric)    case .peakMemory(let metric):        analyzePeakMemory(metric)    case .timeToFirstDraw(let metric):        analyzeLaunch(metric)    case .signpostInterval(let metric):        analyzeSignpost(metric)    @unknown default:        preserveUnknownMetric(result)    }}

Use @unknown default so a beta or future result does not make the ingestion pipeline brittle. Preserve the raw encoded report even when the current app does not understand a result.

Receiving Diagnostic Reports

DiagnosticReport is Codable and Sendable. It contains a timeRange, required environment metadata, and one DiagnosticResult.

Diagnostics are individual, event-based reports intended for prompt delivery when MetricKit produces them. Do not assume every crash, hang, or resource event generates a report; system sampling and eligibility still apply.

After durable storage, route the result explicitly:

swift
switch report.result {case .crash(let diagnostic):    analyzeCrash(diagnostic)case .hang(let diagnostic):    analyzeHang(diagnostic)case .cpuException(let diagnostic):    analyzeCPUException(diagnostic)case .diskWriteException(let diagnostic):    analyzeDiskWrites(diagnostic)case .appLaunch(let diagnostic):    analyzeLaunch(diagnostic)case .memoryException(let diagnostic):    analyzeMemory(diagnostic)@unknown default:    preserveUnknownDiagnostic(report)}

The iOS/iPadOS 27 diagnostic types are CrashDiagnostic, HangDiagnostic, CPUExceptionDiagnostic, DiskWriteExceptionDiagnostic, AppLaunchDiagnostic, and MemoryExceptionDiagnostic. The memory-exception case is new in iOS 27.

Useful fields include:

DiagnosticImportant fields
CrashDiagnosticcallStackTree, exception type/code/reason, signal, virtual-memory region, termination category/reason
HangDiagnosticcallStackTree, hangDuration
CPUExceptionDiagnosticcallStackTree, totalCPUTime, totalSampledTime
DiskWriteExceptionDiagnosticcallStackTree, totalBytesWritten
AppLaunchDiagnosticcallStackTree, launchDuration
MemoryExceptionDiagnosticcallStackTree

Key Metric Results

Choose a small telemetry vocabulary that matches the investigation rather than exporting every result. Prioritize the relevant categories: responsiveness and terminations; runtime, CPU, memory, network, and storage; or launch, display/GPU, and custom intervals.

Aggregate by app version and environment metadata, compare distributions rather than single values, and correlate regressions with releases. Avoid treating a daily aggregate as a precise trace of one user action.

Load the Key Metric Result Catalog [blocked] when mapping exact MetricResult cases into a parser or dashboard.

Call Stack Trees

The iOS 27 CallStackTree replaces MXCallStackTree. It is Codable and Sendable and exposes:

  • forEachFrame for frame traversal
  • callStackThreads for thread-oriented analysis
  • binaryInfo for image and binary metadata

Store the complete diagnostic report before flattening or symbolication. Preserve binary identifiers and offsets so server-side symbolication can use matching archives and dSYMs.

Custom Signpost Metrics

Create an OS log through the manager, then use mxSignpost for begin/end measurement:

swift
let log = manager.logHandle(category: "ImagePipeline")
mxSignpost(.begin, log: log, name: "Decode")await decodeImage()mxSignpost(.end, log: log, name: "Decode")

MetricKit exposes the aggregate as MetricResult.signpostInterval. Do not search for a signpostMetrics array on MetricReport.

Use mxSignpost when MetricKit resource measurement is required. Apple documents that intervals created with OSSignposter and a MetricKit log handle do not populate the resource-measurement fields that mxSignpost provides.

Keep high-volume local tracing separate from the small set of stable production intervals used for MetricKit aggregation.

Durable Export and Upload

Treat report delivery as an at-least-once ingestion problem:

  1. Encode the complete MetricReport or DiagnosticReport with JSONEncoder.
  2. Atomically enqueue the bytes in an app-owned durable outbox.
  3. Record report type, schema version, app version, and a stable deduplication key.
  4. Acknowledge local processing only after the enqueue succeeds.
  5. Upload later with retry, backoff, batching, and retention limits.
  6. Mark the outbox item uploaded only after the server accepts it.
swift
let data = try JSONEncoder().encode(report)try await durableOutbox.enqueue(data, kind: .metric)

durableOutbox is an application-owned abstraction, not a MetricKit API. Do not perform a synchronous network upload inside the sequence consumer.

Durable local storage is the recovery mechanism for reports received through the modern sequences; do not make successful ingestion depend on an assumed modern backfill API.

Extended Launch Measurement

Use trackLaunchTask(id:onTrackingError:_:) on the manager for work that extends beyond time to first draw:

swift
await manager.trackLaunchTask(    id: "bootstrap-data",    onTrackingError: { error in        recordLaunchTrackingError(error)    }) {    await bootstrapApplication()}

The API is @MainActor and has synchronous and asynchronous overloads. The task closure's result and thrown error propagate to the caller; a MetricManager.LaunchTaskError is reported through onTrackingError without interrupting the tracked work. Results appear as MetricResult.extendedLaunch.

Use stable LaunchTaskID values and track only launch-critical work.

iOS 26 Compatibility

For an app that still deploys to iOS 26, use an availability boundary:

  • iOS/iPadOS 27: use MetricManager and consume both async report sequences.
  • iOS/iPadOS 26 and earlier supported releases: use MXMetricManager.shared, an MXMetricManagerSubscriber, and the legacy payload callbacks.

The legacy APIs remain the only documented branch with pastPayloads and pastDiagnosticPayloads. MXMetricManager is deprecated in iOS 27, so isolate it behind availability checks rather than mixing legacy payloads into the modern pipeline.

Load iOS 26 Compatibility [blocked] for the full subscriber, legacy signpost, past-payload, and extended-launch patterns.

Xcode Organizer

Use Xcode Organizer to inspect Apple-aggregated production metrics, hangs, crashes, and regressions before building a custom backend. Use direct MetricKit ingestion when the product needs custom correlation, retention, alerting, or integration with an existing observability system.

Do not expect development-device runs to reproduce the population, cadence, or aggregation of production reports.

Scope Boundaries

TaskUse instead
Reproduce a problem locally or record a detailed tracedebugging-instruments
Diagnose retained objects or memory graph pathsios-memgraph-analysis
Tune SwiftUI invalidation, identity, or scrolling codeswiftui-performance
Study structured EnergyKit impact dataenergykit
Design general logging and os_signpost strategyswift-logging

MetricKit identifies production symptoms and trends. Route the actual code fix to the skill that owns the affected subsystem.

Common Mistakes

MistakeCorrection
Uploading directly in the sequence loopEncode and enqueue locally first; upload asynchronously later.
Assuming every diagnostic event produces a reportTreat diagnostics as sampled, system-produced evidence.
Looking for pastPayloads on MetricManagerKeep legacy backfill only in the iOS 26 MXMetricManager branch.
Parsing only known enum casesPreserve the raw report and use @unknown default.
Using MXMetricManager.makeLogHandle in the iOS 27 branchUse manager.logHandle(category:).
Using paired extend/finish launch calls in the iOS 27 branchUse trackLaunchTask.
Treating MetricKit aggregates as local tracesReproduce with Instruments and signposts.

Review Checklist

  • The iOS 27 branch starts at launch with one retained MetricManager and one consumer per report sequence.
  • Every report is encoded and durably enqueued before analysis or upload.
  • Diagnostic and metric switches use @unknown default.
  • Unknown raw reports remain recoverable.
  • Symbolication metadata and matching dSYMs are retained.
  • Custom intervals use manager.logHandle(category:) and mxSignpost.
  • Extended launch work uses trackLaunchTask.
  • The iOS 26 MXMetricManager path is isolated behind availability checks.
  • Production aggregates lead to a local Instruments investigation when appropriate.
  • iOS 27 beta APIs have been rechecked and compiled with the shipping Xcode 27 SDK.

References

来源与署名

来源:dpearson2699/swift-ios-skills位于skills/metrickit提交8d90fd1

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架

更多来自 dpearson2699/swift-ios-skills 的技能

Widgetkit

dpearson2699

指导实现、审查和改进 iOS、iPadOS、watchOS 与 CarPlay 上的 WidgetKit 小组件和控制项。

Software Development1.1K2个月前更新

Weatherkit

dpearson2699

指导 iOS 开发者使用 WeatherService 获取 WeatherKit 预报、警报与署名信息。

Software Development1.1K2个月前更新

Vision Framework

dpearson2699

Implement computer vision features including text recognition (OCR), face detection, barcode scanning, image segmentation, object tracking, and document scanning in iOS apps. Covers both the modern Swift-native Vision API (iOS 18+) and legacy VNRequest patterns, VisionKit DataScannerViewController for live camera scanning, and CoreMLRequest/VNCoreMLRequest for custom model inference. Use when adding OCR, barcode scanning, face detection, or custom Core ML model inference with Vision.

待分类1.1K2个月前更新

Tipkit

dpearson2699

Implement and review Apple TipKit feature-discovery UI for iOS 17+ apps. Use when adding or auditing in-app tips, contextual help, coach marks, Tip, TipView, popoverTip, rules, events, actions, display frequency, testing overrides, reusable tip identifiers, or iOS 18+ TipGroup and CloudKit tip sync; avoid for generic SwiftUI navigation or layout outside tip presentation.

待分类1.1K2个月前更新

Tabletopkit

dpearson2699

指导使用 TabletopKit 在 visionOS 上构建多人空间桌游,涵盖棋具、座位、动作与 RealityKit 渲染。

Software Development1.1K2个月前更新

Swiftui Webkit

dpearson2699

指导在 iOS 26 及更高版本的 SwiftUI 应用中使用 WebKit for SwiftUI 嵌入和控制网页内容。

Software Development1.1K2个月前更新