installLogTap

suspend fun installLogTap(loom: Loom, exporter: WarpLogRecordExporter, scope: CoroutineScope, config: LogTapConfig = LogTapConfig(), admission: LogTapAdmission = LogTapAdmission.Open): LogTapHost

Install an opt-in log tap on this device and start offering captured logs for extraction. A no-op until called — kuilt never opens a log session implicitly.

Hosts a session on loom and continuously offers exporter's log buffer for replication to any peer that joins. The tap is fabric-agnostic: pass a loopback WebSocket Loom for a simulator/CI puller (the default and safest choice — it binds only the local loopback interface), or a LAN/peer-to-peer Loom to reach a real device. Discovery and admission are the Loom's concern, not the tap's.

Parameters

loom

the fabric to host the session on. Bind it to loopback by default.

exporter

the device's captured-log buffer to offer.

scope

the scope the host's replicator runs in. Closing the returned host (or cancelling this scope) stops the tap.

config

tap tuning; the defaults suit a developer turning the tap on to debug.

admission

how peers are admitted. The default LogTapAdmission.Open keeps the loopback-safe ungated behaviour; pass LogTapAdmission.Verify to require a join code before a peer can pull (see installLogTapJoining for the device-joins topology).

Samples

// The device's captured-log buffer — the same one installLogCapture fills.
val exporter = WarpLogRecordExporter(
    replica = ReplicaId("device-uuid-abc123"),
    store = InMemoryDurableStore(),
)

// The fabric the two peers meet over. An in-memory/loopback Loom is the
// simulator-and-CI case; swap it for a LAN (mDNS + WebSocket) or peer-to-peer
// (Multipeer) Loom to reach a real phone — the tap code below is unchanged.
val loom = InMemoryLoom()

// On the device: turn the opt-in tap on. It does nothing until called and is
// loopback-bound by default. Hold the host; close it to stop offering logs.
val host = installLogTap(loom, exporter, scope)

// In the test / CI harness: join the same session and pull the backlog —
// every line the device captured, in the device's order, with no duplicates.
val client = LogTapClient(loom.join(InMemoryTag("puller")), scope)
val logs: List<LogRecord> = client.pull()

// Release both replicators when finished.
client.close()
host.close()
return logs