MetricKit-backed post-mortem ingest for iOS.
The framework attaches an MXMetricManagerSubscriber in the NIF on
the first sweep/0 call, receives MetricKit payloads on a background
queue thereafter, and drains the bounded in-memory queue into
Mob.Defect.Capsules on Mob.Defect.Bus each time sweep/0 is
called.
Scope of a payload
MetricKit hands the OS-delivered payload to the delegate once per incident class per day (approximately — the delivery cadence is under Apple's control). Each delivery may contain one or more diagnostics of different kinds:
| MetricKit diagnostic | kind |
|---|---|
MXCrashDiagnostic | :native_crash |
MXHangDiagnostic | :anr (iOS's word is "hang"; the defect taxonomy uses ANR) |
MXCPUExceptionDiagnostic | :perf_regression |
MXDiskWriteExceptionDiagnostic | :perf_regression |
The Payload suffix belongs on the container MXDiagnosticPayload
the OS hands to didReceiveDiagnosticPayloads:, which then exposes
the individual diagnostics above.
What the delivery contract looks like from Elixir
sweep/0 is safe to call at any point; MetricKit's own delivery is
asynchronous and the queue accumulates until a caller drains it. A
typical shape:
# In your app's on_start
def on_start do
# ...
Mob.PostMortem.sweep()
endThe top-level Mob.PostMortem.sweep/0 calls into this module. Nothing
auto-runs — that is the framework-wide discipline: mob owns the format
and the bus but never becomes the collector.
Redaction
MetricKit's MXCallStackTree carries binary UUIDs, image names and
mangled symbol offsets: safe identifiers, no user data. The
capsule's fingerprint key uses just the top frame's binary name and
offset — enough to group the same crash across launches without
embedding anything that varies per crash. The full payload JSON goes
onto evidence, bounded by the capsule's existing string-truncation
rule.
Platform gating
The NIF is registered on both iOS and Android (Android returns an
empty list unconditionally — see android/jni/mob_nif.zig). This
module additionally gates on :mob_nif.platform() == :ios so a
caller on Android does no work at all, and a caller in a host test
environment where the NIF is not loaded fails gracefully.
Summary
Functions
@spec sweep() :: [Mob.Defect.Capsule.t()]
Sweep the MetricKit queue and emit a capsule for each new payload.
Returns the list of capsules emitted, in the order they were delivered by the OS. Empty on Android, on iOS < 14 (no MetricKit delivery API), and any time the queue was already empty since the last drain.