Mob.PostMortem (mob v0.9.7)

Copy Markdown View Source

Collect the post-mortems the OS and the BEAM leave behind when a process dies, and put them onto Mob.Defect.Bus as capsules.

Three sources, each in its own submodule:

  • Mob.PostMortem.BeamCrashDump — erl_crash.dump files (BEAM). Scans configured paths, reads a bounded 8 KB header, dedups by sha256, emits :beam_crash capsules.
  • Mob.PostMortem.IOS — MetricKit payloads (crash / hang / launch / CPU / memory / disk). Attaches an MXMetricManagerSubscriber lazily on first sweep, buffers OS-delivered payloads in a bounded native queue, emits :native_crash / :anr / :perf_regression capsules on drain.
  • Mob.PostMortem.Android — ApplicationExitInfo history (ANR, crash, OOM, user kill). Pulls the OS-held exit-reason list on demand (API 30+), filters against a persistent marker so the OS hands each exit over once, emits :native_crash / :anr / :oom / :user_kill capsules.

Both native drains are destructive, so Mob.PostMortem.Journal keeps what they returned and every sweep emits it again, across boots, until it has been observed on the bus.

Nothing here runs automatically. An app opts in by calling Mob.PostMortem.sweep/0 from its on_start, and a developer or CI calls the same function from an IEx session (there is no dedicated Mix task — the whole surface is one function). That matches the discipline the Mob.Defect subsystem enforces: mob owns the format and the bus but never becomes the collector.

Idempotence

sweep/0 is safe to call as many times as you like. Each artifact has a sha256 id, and Mob.PostMortem.Registry records ids that have already emitted; a subsequent sweep finds them seen and does nothing. The dump stays on disk — nothing here deletes or moves a file — so offline inspection still works. See the registry's moduledoc for why the seen-set does not persist across BEAM restarts (a fresh BEAM sweeps back into a fresh bus, on purpose), and the journal's for why native entries are re-emitted until observed.

Return value

sweep/0 and sweep/1 return the capsules that were emitted this call, in the order they were emitted. That is what a caller drop-in in on_start normally ignores; a test or a CLI wants it.

Summary

Functions

Sweep every source using its default paths.

Sweep every source, with beam_paths added to the BEAM-crash-dump scanner's default paths.

Functions

sweep()

@spec sweep() :: [Mob.Defect.Capsule.t()]

Sweep every source using its default paths.

Equivalent to sweep([]) — each source module supplies its own defaults (see BeamCrashDump.default_paths/0; iOS and Android draw from their platform native APIs when linked).

sweep(beam_paths)

@spec sweep([Path.t()]) :: [Mob.Defect.Capsule.t()]

Sweep every source, with beam_paths added to the BEAM-crash-dump scanner's default paths.

A caller with dumps somewhere unusual (a CI artifact directory, a scratchpad) passes them here — they merge with the defaults rather than replacing them, so passing an empty list is equivalent to sweep/0.