Monitor network I/O

Chalk can also record networking state at the time of the report. Let’s set up a heartbeat report that tracks network state.

cat << EOF > networkconfig.c4m
# Turn on heartbeating.
exec.heartbeat.run: true
exec.heartbeat.rate: <<2 seconds>>

# Which Chalk keys we want to track here.
report_template network_focus {
  key._OP_TCP_SOCKET_INFO.use                 = true
  key._OP_UDP_SOCKET_INFO.use                 = true
  key._OP_IPV4_ROUTES.use                     = true
  key._OP_IPV6_ROUTES.use                     = true
  key._OP_IPV4_INTERFACES.use                 = true
  key._OP_ARP_TABLE.use                       = true
  key._PROCESS_PID.use                        = true
  key._TIMESTAMP.use                          = true
}

# Tell heartbeating to use this report.
outconf.heartbeat.report_template: "network_focus"
EOF

Now load the configuration into Chalk.

chalk load networkconfig.c4m

Note: Chalk configuration is immutable. If you ever want to edit a config you need to pass --replace to chalk load.

Now let’s archive 100kB of the Hacker News website and report on it with Chalk.

$ chalk exec -- wget --mirror --continue --wait 1 --directory-prefix . --quota=100k https://news.ycombinator.com
--2026-03-30 16:57:43--  https://news.ycombinator.com/
Resolving news.ycombinator.com (news.ycombinator.com)... 209.216.230.207, 2606:7100:1:67::26
Connecting to news.ycombinator.com (news.ycombinator.com)|209.216.230.207|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘./news.ycombinator.com/index.html’

news.ycombinator.com/index.html             [ <=>                                                                           ]  34.46K  --.-KB/s    in 0.09s

Last-modified header missing -- time-stamps turned off.
2026-03-30 16:57:43 (394 KB/s) - ‘./news.ycombinator.com/index.html’ saved [35288]

... Output truncated ...

FINISHED --2026-03-30 16:57:50--
Total wall clock time: 7.6s
Downloaded: 7 files, 129K in 0.3s (494 KB/s)
Download quota of 100K EXCEEDED!

Finally let’s query the JSON Chalk logs to find any network activity connected to non-local IP addresses, and the time where we observed the connection (not necessarily the time when the connection happened).

$ cat ~/.local/chalk/chalk.log | jq -rs '.[][] | . as $entry |
  $entry._OP_TCP_SOCKET_INFO[]?
  | select(
      .[4] == "ESTABLISHED" and
      (.[2] | test("^127\\.|^192\\.168\\.|^10\\.|^172\\.(1[6-9]|2[0-9]|3[0-1])\\.") | not)
    )
  | "Connected to \(.[2]) at \($entry._TIMESTAMP / 1000 | strftime("%Y-%m-%d %H:%M:%S UTC"))"
'
Connected to 209.216.230.207 at 2026-03-30 16:57:43 UTC
Connected to 209.216.230.207 at 2026-03-30 16:57:45 UTC
Connected to 209.216.230.207 at 2026-03-30 16:57:47 UTC
Connected to 209.216.230.207 at 2026-03-30 16:57:49 UTC

And if we weren’t aware what was running (because we generically wrapped all user execution in chalk exec) we could grab that IP and figure out who it is.

$ dig -x 209.216.230.207 +short
news.ycombinator.com.

On this page