返回博客
·9 分钟阅读·productdevbook

如何导出 macOS 网络使用数据

如何导出和分析 macOS 网络使用数据:内置命令、常见格式与好用的一行命令。

  • Developer tools
  • macOS
  • Bandwidth
  • Tutorial

你终于抓到了那个尖峰。三天来你一直在想为什么家里互联网用量在随机时间跳,你终于在合适时刻有工具开着看到了它。然后呢?你想把这数据从实时 UI 拿出来,放进能分析、能跟同事分享、能跟服务器日志关联的东西里。导出 macOS 网络用量的能力比人们意识到的更重要,知道往哪看时 macOS 选项还不错。

这篇走一遍实操路径:短捕获用 nettop -L、系统侧网络事件用统一日志、CSV 用采样脚本,以及 ova 数据存在磁盘上的什么位置。

为什么要导出 macOS 网络用量

几个真实情况:

  • 异常调查 — 你看到凌晨 3 点 2 GB 上传,想把整夜的源进程画成图。
  • 容量规划 — 你在计费或限速连接上(Starlink Roam、酒店 Wi-Fi、移动共享网络),想知道留什么开着是安全的。
  • 性能调试 — 服务器团队在问慢请求是什么时候开始的,你想把客户端网络用量叠在他们服务器日志上。
  • 按项目带宽预算 — 你按小时给客户开账单,想做一次合理性检查,看他们的构建管线昨天上传了什么。
  • 好奇 — 你只是想看看自己的数据。

对所有这些,"打开活动监视器盯着"不够。你需要数据落到磁盘,以你能操作的格式。

选项 1:nettop 日志模式

最简单的导出路径是内置的。nettop -L <count> 在日志模式下跑 <count> 个样本,把每个样本作为一行文本输出,然后退出。配合 -J 选列、-s 设间隔,你拿到能管道到文件的干净输出。

nettop -L 600 -s 1 -P -J bytes_in,bytes_out,interface,state \
  > ~/Desktop/nettop-10min.txt

那是 600 个样本、一秒间隔——十分钟捕获。每个样本列出每个活跃进程,带你要的列。

输出不算 CSV——每个样本一个表头、样本之间空行、进程名带空格。但能解析。短的 awk 或 Python 脚本会把它变成干净的表。

nettop 日志的限制

  • 它只在跑的时候捕获。如果你想知道昨天发生了什么,没戏。
  • 它默认报告自进程启动以来的累计;增量得自己算。
  • 辅助进程显示成单独行(不归并)。
  • 样本格式不是一等公民 CSV;准备写解析器。

对特定时间窗口的临时捕获——"我马上要 push 到 GitHub,捕获前后五分钟"——nettop -L 很好。要持续数据,你想要别的。

选项 2:统一日志

macOS 的统一日志从系统框架捕获结构化事件,包括网络。CFNetwork(URLSession 层)和 Network.framework 都为连接生命周期、TLS 握手、重试和失败发出日志行。事后可以提取。

要看现在有什么,查上一小时:

log show --last 1h --predicate 'subsystem == "com.apple.CFNetwork"' \
  --info --debug

要导出到文件:

log show --last 24h --predicate 'subsystem == "com.apple.CFNetwork"' \
  --style compact > ~/Desktop/cfnetwork-day.log

有用的谓词:

  • subsystem == "com.apple.CFNetwork" — URLSession 请求、TLS、重定向
  • subsystem == "com.apple.network" — Network.framework 路径变化、连接状态
  • process == "YourApp" — 限到一个应用
  • eventMessage CONTAINS "443" — 在日志消息里做文本搜索

统一日志保留约最近几天的系统事件,看量。它不是为字节计数设计的——是为事件审计设计的。但如果你的问题是"到 api.example.com 的连接是不是 14:23 失败了",统一日志知道。

log show vs log stream

log show 读历史日志。log stream 看新事件实时。在你想留个终端跑着观察事件发生时用 log stream

log stream --predicate 'subsystem == "com.apple.network"' --level debug

>> 管道到文件做滚动捕获。

选项 3:自定义采样脚本

如果你想要按进程带宽的 CSV 输出——多数人的实际目标——20 行 shell 就能搭。思路:每 N 秒轮询、对累计字节数做差、输出 CSV。

#!/usr/bin/env bash
# Naive per-process bandwidth sampler.
INTERVAL=5
echo "timestamp,pid,process,delta_in,delta_out"
declare -A prev_in prev_out
while true; do
  ts=$(date +%s)
  while IFS=, read pid name in_bytes out_bytes; do
    pi=${prev_in[$pid]:-0}
    po=${prev_out[$pid]:-0}
    di=$((in_bytes - pi))
    do_=$((out_bytes - po))
    if (( di > 0 || do_ > 0 )); then
      echo "$ts,$pid,$name,$di,$do_"
    fi
    prev_in[$pid]=$in_bytes
    prev_out[$pid]=$out_bytes
  done < <(nettop -P -L 1 -J pid,interface,bytes_in,bytes_out 2>/dev/null \
            | awk 'NR>2 {print $2","$1","$3","$4}')
  sleep $INTERVAL
done

这是个草图——生产代码会处理进程退出、辅助进程归并、日志轮转,以及 nettop 输出格式难解析的事实——但它展示了形态。你采样、做差、输出 CSV。如果想让它在睡眠后还活着,在 caffeinate 下跑或作为 launchd 代理。

看 ova 实战

一眼可瞄的菜单栏带宽监控——本地、签名、约 3 MB。

下载 macOS 版

选项 4:ova 的本地数据库

一个专用带宽监控让你免于写上面那种脚本。ova 把 SQLite 数据库放在:

~/Library/Application Support/ova/

内容是你在 UI 里看到的同一份时序数据:每个应用的入字节和出字节,约 1 Hz 采样,辅助进程归并到父应用下。本地,无云同步,无遥测。你拥有这个文件。

因为是 SQLite,任何能读 SQLite 的东西都能读:sqlite3 CLI、Python 的 sqlite3 模块、DB Browser for SQLite,或在 DuckDB 里快速一查。你可以:

  • 一条命令导出整个历史到 CSV
  • 跑聚合("这周哪个应用用了最多带宽,按小时")
  • 跟你自己的日志连接(构建管线、服务器访问日志、日历事件)
  • 备份到你常规备份目标

sqlite3 导到 CSV 的典型例子:

sqlite3 -header -csv \
  ~/Library/Application\ Support/ova/<file>.sqlite \
  "SELECT timestamp, app, bytes_in, bytes_out FROM samples \
   WHERE timestamp > strftime('%s','now','-7 days') \
   ORDER BY timestamp" > ~/Desktop/last-week.csv

实操配方、连接和隐私

一旦你有了 CSV——从任何源——几个查询就值回成本。

按周前列应用

SELECT app,
       SUM(bytes_in) / (1024*1024) AS mb_down,
       SUM(bytes_out) / (1024*1024) AS mb_up
  FROM samples
 WHERE timestamp > strftime('%s','now','-7 days')
 GROUP BY app
 ORDER BY (mb_down + mb_up) DESC
 LIMIT 20;

几乎总是讲一个清楚的故事。浏览器在顶、同步应用在中、系统服务在底。

按小时热图

SELECT strftime('%H', timestamp, 'unixepoch', 'localtime') AS hour,
       SUM(bytes_in + bytes_out) / (1024*1024) AS mb
  FROM samples
 WHERE timestamp > strftime('%s','now','-30 days')
 GROUP BY hour
 ORDER BY hour;

显示你的流量何时尖峰。多数人是早 9、下午 1、下午 4,加上一个夜里云同步的长尾。

异常检测

SELECT app,
       date(timestamp, 'unixepoch', 'localtime') AS day,
       SUM(bytes_out) / (1024*1024) AS mb_up
  FROM samples
 GROUP BY app, day
HAVING mb_up > 500
 ORDER BY mb_up DESC;

标记任何上传超过 500 MB 的应用-日。少数是正常的(到网络目标的 Time Machine、照片同步、大文件传输)。一整列不熟悉的应用值得调查。

本地 SQLite 历史
ova 约 1 Hz 采样按应用带宽,并存在 ~/Library/Application Support/ova/ 的 SQLite 文件里。你可以用任何其他数据库会用的同一些工具查询它。

组合源

最强的工作流同时用多个源。

  • ova 做字节计数 — 谁用了多少、什么应用、什么时候
  • 统一日志做事件 — 连接什么时候开始、失败、重试
  • tcpdump 看线 — 真正神秘的时候

你可以按时间戳连接它们。如果 ova 显示 cloudd 在 3:14 AM 上传 200 MB,统一日志显示 cloudd 在同步什么,并且(如果你有抓包跑着)tcpdump 显示目的 IP 段确认是 iCloud。

关于隐私的一点

任何导出网络数据的东西都可能泄漏你不想分享的信息。主机名,甚至统一日志里的路径,都可能透露你用什么服务。在把日志发给同事或粘进聊天前:

  • 如果 IP 地址会标识你家网络,去掉
  • 涂掉透露个人服务的主机名
  • 移除透露你不想宣传的应用的进程名

这也是为什么纯本地工具重要。ova 不把你数据送去任何地方——它待在你磁盘上。你导出什么是你的决定。

收尾

要导出 macOS 网络用量数据你有几条合理路径:短捕获用 nettop -L、事件审计用统一日志、要完全控制的话自定义采样脚本,以及像 ova 这种本地 SQLite 撑腰的监控做持续按应用计数。按你需要事件还是字节、以及你在乎多长一个窗口来选。

要低成本路径持续捕获并允许你后续查询,装 ova——约 3 MB,macOS 14+,Apple Silicon 和 Intel,约 1 Hz 采样。数据住在你 ~/Library/Application Support/ova/ 目录的 SQLite 里,所以任何你已经会的分析工具都能读它。