Reference · Logging & telemetry
Logging & telemetry
SecVF exposes seven distinct log surfaces, each with its own format and audience. This page documents each one — what data lands there, how to access it, retention semantics, and how to script against it.
On this page
- The log surface map
- Security Logs window (⌘⇧1)
- Network Logs window (⌘⇧2)
- Switch Statistics window (⌘⇧3)
- ISO Cache Audit window (⌘⇧4)
- Packet Analysis window (⌘⇧P)
- On-disk: security-YYYY-MM-DD.log
- On-disk: error-audit.log
- On-disk: per-VM start logs
- On-disk: network-YYYY-MM-DD.log
- AI sandbox session audit log
- Severity ladder
- Shipping logs to a SIEM
The log surface map
┌─ In-app windows ──────────────────────────────────┐ ┌─ On-disk (~/.avf/logs/) ─────────────┐
│ Security Logs ⌘⇧1 │ │ security-YYYY-MM-DD.log (JSONL) │
│ Network Logs ⌘⇧2 │ │ error-audit.log (JSONL) │
│ Switch Statistics ⌘⇧3 │ │ network-YYYY-MM-DD.log (text) │
│ ISO Cache Audit ⌘⇧4 │ │ <vm-name>-start-<ts>.log (text) │
│ Packet Analysis ⌘⇧P → its own page │ │ AISandbox/sessions/<…>/audit.log │
└───────────────────────────────────────────────────┘ └──────────────────────────────────────┘
Two rules to keep in mind:
- The windows are live views of the on-disk logs (with formatting + filters). Quitting SecVF doesn't lose anything — re-open and the windows replay from disk.
- On-disk logs are append-only. SecVF never truncates. To rotate, move the file aside — a fresh one is created on next write.
Security Logs window (⌘⇧1)
What it shows
Every event from VMSecurityMonitor, the in-process observer that watches filesystem deltas, resource pressure, and VM lifecycle events. One row per event.
Columns
| Column | Detail |
|---|---|
| Time | Local timestamp, millisecond precision. |
| Severity | INFO / WARNING / CRITICAL / EMERGENCY — color-coded. |
| VM | The VM the event relates to, or (host) for app-level events. |
| Subsystem | e.g. vm-lifecycle, fsevents, iso-cache, network-switch, ai-sandbox. |
| Event | Dotted-namespace event name: boot.requested, file.appeared, checksum.mismatch, etc. |
| Detail | Free-form, often containing paths or counts. |
Filters
The top bar accepts:
- Severity floor — hide everything below the chosen level.
- VM filter — show only events for one VM.
- Subsystem filter — drill into a category.
- Text search — substring match across all columns.
Export
Right-click → Export selection as JSONL. Useful for filing a bug report or shipping to a SIEM.
Network Logs window (⌘⇧2)
What it shows
Every connection observed on the VirtualNetworkSwitch — not full packet decode, just connection-level summaries. Useful for "what talked to what" without the volume of packet capture.
Per-row data
- Time first seen / last seen
- Source VM (or external)
- Destination VM (or external)
- Protocol (TCP/UDP/ICMP)
- Source port, destination port
- Bytes / packets sent and received
- State (NEW, ESTABLISHED, CLOSED, RESET, TIMEOUT)
When to use vs Packet Analysis
Network Logs is your summary view — answers "did anything weird happen this hour?". Packet Analysis is your microscope — answers "what was in that one suspicious frame?". Use Network Logs to find candidates, Packet Analysis to investigate them.
Switch Statistics window (⌘⇧3)
What it shows
Live operational view of the virtual switch. No history — these are real-time gauges.
Panels
- Throughput counters — frames forwarded, broadcast, dropped; bytes RX/TX. Updated every second.
- Port table — each connected VM with its assigned port, MAC address, RX/TX byte counters.
- MAC learning table — every MAC the switch has learned, mapped to its port, with last-seen age.
- Security alerts — backpressure events, anomalous MAC moves, dropped-frame floods.
Drop-rate alerts
If Packets Dropped > 0, the capture queue is saturating. This isn't catastrophic — frames are tagged dropped in the security log — but it means tighten the BPF filter or raise the buffer size (see Packet analysis § performance).
ISO Cache Audit window (⌘⇧4)
What it shows
Every ISO download SecVF has performed, with full provenance. One row per file.
Per-row data
| Column | Detail |
|---|---|
| Distro / Version | What was downloaded (Kali 2024.4, Ubuntu 24.04, etc.). |
| URL | Full source URL — verify against the pinned mirror in distros.json. |
| Host | Hostname (must be in the allowlist; rejections also logged here). |
| SHA-256 (expected) | From the upstream checksum file. |
| SHA-256 (actual) | Computed locally. Must match. |
| Result | ✓ verified, ✗ mismatch (file deleted), ⚠ skipped (already cached). |
| Bytes / Duration | For perf monitoring. |
| When | Timestamp. |
This is your provenance audit. If you ever need to prove "the ISO we built that VM from was the legitimate one," this window has the receipt.
Packet Analysis window (⌘⇧P)
Documented in detail on its own page. Briefly: the most-used analysis surface — live capture, Wireshark display filters, protocol stats, hex view, PCAP export.
On-disk: ~/.avf/logs/security-YYYY-MM-DD.log
Format
JSON Lines (one event per line). The Security Logs window reads from this file; you can read it directly with tail -F for live, or jq for offline analysis.
{"ts":"2026-05-10T14:32:01.234Z","severity":"INFO","subsystem":"iso-cache","event":"download.started","vm":null,"data":{"url":"https://cdimage.debian.org/...","host":"cdimage.debian.org"}}
{"ts":"2026-05-10T14:32:45.890Z","severity":"INFO","subsystem":"iso-cache","event":"download.verified","vm":null,"data":{"file":"debian-12.iso","sha256":"abc..."}}
{"ts":"2026-05-10T14:33:02.115Z","severity":"WARNING","subsystem":"network","event":"switch.drop","vm":"ubuntu-malware","data":{"reason":"queue-saturation","drop_count":17}}
{"ts":"2026-05-10T14:33:30.601Z","severity":"CRITICAL","subsystem":"iso-cache","event":"checksum.mismatch","vm":null,"data":{"file":"untrusted.iso","expected":"...","got":"..."}}
Rotation
One file per local day. No automatic deletion — files accumulate. Rotate or archive yours periodically.
Useful queries
# Today's critical events
jq -c 'select(.severity == "CRITICAL" or .severity == "EMERGENCY")' \
~/.avf/logs/security-$(date +%F).log
# All events for one VM, last 7 days, by severity
jq -c "select(.vm == \"kali-router\")" ~/.avf/logs/security-*.log \
| jq -s 'group_by(.severity) | map({severity: .[0].severity, count: length})'
# Top subsystems by event volume today
jq -r '.subsystem' ~/.avf/logs/security-$(date +%F).log \
| sort | uniq -c | sort -rn
On-disk: ~/.avf/logs/error-audit.log
Format
JSON Lines, append-only, no rotation (deliberately — it should be a complete error history).
{"ts":"2026-05-10T14:00:01Z","category":"vm-config","code":"missing-disk-image","message":"Disk.img not found in bundle","recovery":"Try recreating the VM, or restore from a snapshot","stack":"..."}
{"ts":"2026-05-10T14:01:43Z","category":"network","code":"interface-bind-failed","message":"vmnet attach refused","recovery":"Check System Settings → Network → Firewall isn't blocking SecVF","stack":"..."}
What's in here that's not in the security log
Typed errors with localized recovery suggestions. The security log is event-oriented; this log is error-oriented. They overlap (some events are errors) but they're not the same — investigate both when something breaks.
Categories
Eleven categories defined in SecVFError.swift. Most common when triaging:
vm-config— bad metadata.json, bundle structure issuesvm-start— boot failed, entitlement, missing IPSWnetwork— switch issues, vmnet failuresiso-cache— download failures, hash mismatchespermission— entitlement / sandbox failuresfilesystem— write failures, disk full
On-disk: per-VM start logs
Path
~/.avf/logs/<vm-name>-start-<YYYYMMDD-HHMMSS>.log
What it is
Captured stdout + stderr from the subprocess SecVF spawned for that VM start. When start fails fast — entitlement issue, missing file, VZ error before the framework's own logging kicks in — this is where the real reason hides.
Format
Plain text. Each line a stdout/stderr fragment, with a leading subsystem prefix where SecVF wrote it itself.
When to read
- A specific VM consistently fails to start while others succeed
- The Security Logs window says
vm-start failedbut the audit log doesn't have the underlying reason - You need to know what VZ said in the seconds before the error
On-disk: ~/.avf/logs/network-YYYY-MM-DD.log
Format
Human-readable text, one connection event per line. Daily-rotated.
2026-05-10T14:32:01.234Z [switch] port=2 vm=ubuntu-malware mac=52:54:00:d4:e5:f6 NEW tcp 10.0.100.42:38122 -> 10.0.100.1:53
2026-05-10T14:32:01.298Z [switch] port=2 vm=ubuntu-malware ESTABLISHED tcp 10.0.100.42:38122 -> 10.0.100.1:53 (12 packets, 1.4 KB)
2026-05-10T14:32:15.901Z [switch] port=2 vm=ubuntu-malware CLOSED tcp 10.0.100.42:38122 -> 10.0.100.1:53 (after 14.6s)
This file backs the Network Logs window. Tail it for live view from the terminal: tail -F ~/.avf/logs/network-$(date +%F).log.
AI sandbox session audit log
Path
~/.avf/AISandbox/sessions/<session-id>.bundle/audit.log
Per-session
Each ephemeral session has its own audit log. Lives inside the session's bundle — destroyed with the bundle. To keep a session's log past destruction, export it via secvf vm exec <session> -- 'cat /var/db/secvf-audit.log' > ./saved.log before destroy.
What's in it
session.cloned— APFS clonefile() result, time taken, source base bundle hashsession.booted— VZ boot time, VM peer info (vsock CID)vsock.exec— every command run viasession.run(), with start/end timestamps and exit codefs.share.mounted— VirtioFS share attached- DTrace probe output (selectively) — major file activity, process exec
session.destroyed— bundle removal, divergent-block count for telemetry
Format
JSON Lines, same schema as the host security log.
Severity ladder
| Level | Meaning | Where it lands | Default visibility |
|---|---|---|---|
| INFO | Normal operation, worth recording. | security-*.log only. | Hidden from the window unless floor lowered. |
| WARNING | Unexpected but recoverable. | security-*.log + window. | Visible. |
| CRITICAL | Something broke. Needs attention. | security-*.log + window + system sound. | Visible, color-coded. |
| EMERGENCY | Security boundary violated. | everywhere + Dock badge + system sound. | Cannot be hidden. |
The window's default filter is WARNING and above. Drop the floor to see INFO if you're debugging.
Shipping logs to a SIEM
All the on-disk JSONL files are SIEM-friendly. Three patterns:
Tail-and-forward
# Simplest. Use whichever forwarder your SIEM supports.
tail -F ~/.avf/logs/security-*.log | jq -c . \
| curl -X POST --data-binary @- https://siem.example.com/secvf
Vector / Fluent Bit
# Vector config snippet (vector.toml)
[sources.secvf_security]
type = "file"
include = ["/Users/me/.avf/logs/security-*.log"]
read_from = "end"
[sinks.siem]
type = "http"
inputs = ["secvf_security"]
uri = "https://siem.example.com/ingest"
encoding.codec = "json"
OSLog bridge
If your fleet uses macOS's unified logging system, every SecVF event is also published to os_log under the subsystem com.DaxxSec.SecVF. Standard log stream / log show works:
log stream --predicate 'subsystem == "com.DaxxSec.SecVF"' --info
log show --predicate 'subsystem == "com.DaxxSec.SecVF"' --last 24h --info
Pipe that into your enterprise logging agent (Datadog, Splunk, Crowdstrike, etc.) and SecVF events show up alongside everything else macOS knows about.