ブログに戻る
·9分で読める·productdevbook

macOSのネットワーク使用データをエクスポートする方法

macOSのネットワーク使用データをエクスポートして分析する方法。標準コマンド、よく使うフォーマット、便利なワンライナーを紹介します。

  • Developer tools
  • macOS
  • Bandwidth
  • Tutorial

ようやくスパイクを捕まえました。3日間、自宅のインターネット使用量がランダムな時刻に跳ね上がる理由を考えていて、ようやく正しい瞬間にツールを開いて見られました。次は何をするか? このデータをライブUIから取り出して、分析できるもの、同僚と共有できるもの、サーバログと相関させられるものに入れたい。macOSネットワーク使用状況のエクスポート能力は人々が思うより重要で、macOSは見るべき場所を知っていればまともなオプションを持っています。

本稿は実用的な道筋を歩きます: 短いキャプチャ用のnettop -L、システム側ネットワーキングイベント用の統合ログ、CSV用のサンプリングスクリプト、そしてovaがディスク上にデータを保存する場所。

なぜmacOSネットワーク使用状況をエクスポートするのか

実例:

  • 異常調査 — 午前3時に2GBのアップロードを見て、夜通しのソースプロセスをグラフ化したい。
  • キャパシティ計画 — 従量制または上限付き接続(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

これは1秒間隔で600サンプル——10分のキャプチャです。各サンプルは要求した列で各アクティブプロセスをリストします。

出力は完全にCSVではありません——サンプルごとにヘッダがあり、サンプル間に空行、スペース付きプロセス名。ただ解析可能です。短いawkまたはPythonスクリプトできれいなテーブルになります。

nettopログの限界

  • 動いている間のみキャプチャ。昨日何が起きたか知りたかったなら、運がない。
  • 既定でプロセス起動以来の累積を報告。差分は自分で計算。
  • ヘルパープロセスは別行(折りたたみなし)。
  • サンプル形式はファーストクラスのCSVではない。パーサを書くつもりで。

特定の時間窓の臨時キャプチャ——「GitHubにプッシュしようとしている、その周りの5分をキャプチャしよう」——にはnettop -Lは素晴らしい。継続データには別のものが欲しい。

オプション2: 統合ログ

macOSの統合ログは、ネットワーキングを含むシステムフレームワークから構造化イベントをキャプチャします。CFNetwork(URLSession層)とNetwork.frameworkは両方、接続ライフサイクル、TLSハンドシェイク、再試行、失敗のログ行を発行します。事後にそれらを抽出できます。

直近1時間の現状を見るには:

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" — 1アプリに制限
  • eventMessage CONTAINS "443" — ログメッセージ内のテキスト検索

統合ログは量によりおよそ過去数日のシステムイベントを保持します。バイト集計用に設計されていません——イベント監査用に設計されています。ただ、「14:23にapi.example.comへの接続が失敗したか」が問いなら、統合ログは知っています。

log show vs log stream

log showは履歴ログを読みます。log streamは新しいイベントをライブで監視します。ターミナルを動かしたままイベントを見たいときにはlog streamを使います:

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

>>でファイルにパイプして回転キャプチャを追記。

オプション3: カスタムサンプリングスクリプト

プロセス別通信量のCSV出力——多くの人にとって本当の目標——が欲しいなら、20行のシェルで構築できます。アイデア: N秒ごとにポーリングし、累積バイト数を差分し、CSVを出力。

#!/usr/bin/env bash
# 素朴なプロセス別通信量サンプラ。
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を動かしてみる

一目で分かるメニューバー通信量モニター——ローカル、署名済み、約3MB。

macOS用ダウンロード

オプション4: ovaのローカルデータベース

専用通信量モニターは上のスクリプトを書く手間を省きます。ovaはSQLiteデータベースを次の場所に保持します:

~/Library/Application Support/ova/

内容はUIで見るのと同じ時系列データです: 約1Hzでサンプリングしたアプリ別の送受信バイト、ヘルパープロセスは親アプリの下に折りたたみ。ローカル、クラウド同期なし、テレメトリなし。ファイルはあなたのもの。

SQLiteなので、SQLiteを読めるものは何でも読めます: sqlite3 CLI、Pythonのsqlite3モジュール、DB Browser for SQLite、DuckDBでのクイッククエリ。次のことができます:

  • 1コマンドで履歴全体を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;

500MB超のアップロードがあったアプリ・日にフラグを立てます。一握りは正常(ネットワーク先へのTime Machine、写真同期、大きなファイル転送)。馴染みのないアプリの全リストは調査に値します。

ローカルSQLite履歴
ovaはアプリ別通信量を約1Hzでサンプリングし、~/Library/Application Support/ova/のSQLiteファイルに保存します。他のデータベースに使うのと同じツールでクエリできます。

ソースの組み合わせ

最強のワークフローは複数のソースを同時に使います。

  • ovaでバイト集計 — 何が、どのアプリで、いつ使われたか
  • 統合ログでイベント — 接続がいつ始まり、失敗し、再試行したか
  • tcpdumpで回線 — 本当に謎のとき

タイムスタンプで結合できます。ovaが3:14 AMにclouddによる200MBアップロードを示し、統合ログがclouddが何を同期していたかを示し、(パケットキャプチャを動かしていれば)tcpdumpがiCloudだったことを確認する宛先IP空間を示します。

プライバシーについて

ネットワークデータをエクスポートするものは、共有する意図のなかった情報をリークしうる。ホスト名、統合ログのパスでさえ、使うサービスを明らかにしうる。ログを同僚に送るかチャットに貼り付ける前に:

  • 自宅ネットワークを特定するIPアドレスを除く
  • 個人サービスを明らかにするホスト名を編集
  • 宣伝したくないアプリを明らかにするプロセス名を削除

これがローカル限定ツールが重要な理由でもあります。ovaはデータをどこにも送りません——ディスクに留まります。何をエクスポートするかはあなたの決定です。

まとめ

macOSネットワーク使用状況データをエクスポートするには、いくつかの妥当なパスがあります: 短いキャプチャ用のnettop -L、イベント監査用の統合ログ、完全な制御用のカスタムサンプリングスクリプト、継続的なアプリ別集計用のovaのようなローカルSQLiteベースモニター。イベントかバイトか、どのくらいの窓を気にするかで選びましょう。

継続的にキャプチャし後でクエリできる低労力のパスには、ovaをインストールしましょう——約3MB、macOS 14+、Apple SiliconとIntel、約1Hzでサンプリング。データは~/Library/Application Support/ova/ディレクトリにSQLiteで住むので、すでに知っているどの分析ツールも読めます。