macbook-metrics-setup について
macbook-metrics-setupは、Macの指標を長期にわたりローカルで収集する仕組みの構築方法を説明します。低負荷でシステムをサンプリングしてSQLiteに保存し、launchdによる定期実行と、プライベートGitHubリポジトリへのバックアップを扱います。
主な機能
- 01毎分のシステム指標収集
- 02測定データのSQLite保存
- 03collect、doctor、reportコマンド
- 04launchdによる収集の定期実行
- 05プライベートGitHubリポジトリへのDBバックアップ
活用シーン
- 01Macのシステムリソース変化の長期記録
- 02収集処理とサンプラーの動作確認
- 03指定期間の指標概要の確認
- 04DBスナップショットのプライベートリポジトリへの保存
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ davidondrej/ skills --skill macbook-metrics-setupインストール後、Claude Code で/macbook-metrics-setupを入力して読み込まれたか確認します。
詳細
MacBook メトリクスのセットアップ
自分で完全に管理できる、低オーバーヘッドで長期運用可能な Mac メトリクスコレクターの構築方法です。 クラウドもテレメトリーもアカウントも不要です。必要なのは、1 つのバイナリ、1 つの SQLite ファイル、2 つの launchd ジョブ、1 つのプライベート GitHub リポジトリだけです。
基本方針(構築前にお読みください)
- ローカルのみで、決定論的です。 コレクターはネットワークへの 呼び出しを一切行わず、LLM を使用せず、分析データも送信しません。誰でも コードを読んで、何が書き込まれるかを正確に把握できる必要があります。
- データはリポジトリの外部にある
~/Library/Application Support/<project>/に保存します。再インストールや git 操作によって測定データが変更されることはありません。 - 低オーバーヘッドは必須要件です。 サンプルは 1 分に 1 回、リリースビルド、
LowPriorityIOを使用します。モニター自体が負荷の原因になってはいけません。 - 文書化されていない読み取り値は nullable のままにし、エラーを明示します。 GPU 使用率と SMC 温度の読み取りには、macOS のアップデートで動作しなくなる可能性のあるプライベートインターフェースを 使用します。値は nullable な列に保存し、エラーを表面化させてください。 値を捏造してはいけません。
- 決定事項は記録します。 アーキテクチャ上の選択はすべて
docs/adr/に ADR として記録し、 スキーマの変更はすべてdocs/database/に番号付きの SQL ファイルとして記録します。 エージェントと人間は、契約として ADR に従います。 - プロセス単位のトラッキングはオプトインです。 システム全体の収集を デフォルトとします。特定のアプリ(例:Electron IDE)の監視は、独自の ADR を通じてのみ追加する、 分離された別のコレクターです。
リポジトリ構成
Sources/<ProjectLib>/ # samplers, SQLite storage, report generation
Sources/<project-cli>/ # thin CLI: collect | doctor | report
launchd/ # plist templates with __PLACEHOLDER__ tokens
scripts/ # install.sh, uninstall.sh, sync.sh
docs/adr/ # numbered architecture decision records
docs/database/ # numbered SQL migrations
backups/ # git-tracked SQLite snapshots (written by sync)
Swift + SwiftPM が自然な選択です(ネイティブの IOKit/Mach API を使い、依存関係がゼロです)が、 このアーキテクチャはコンパイル言語であればどれでも利用できます。
データ収集
- システム全体の CPU 使用率、GPU 使用率、メモリ(使用量/ワイヤード/圧縮済み/ メモリプレッシャー)、スワップ、ディスク容量と IO のバイト数/操作数カウンター、 ネットワークのバイト数/パケット数カウンター、バッテリー、サーマル状態、温度、ファン回転数をサンプリングします。
- OS の累積カウンター(ディスク/ネットワーク)は、インターバルごとの差分として保存します。
- 1 分に 1 行を SQLite に書き込みます(WAL モード)。1 年でも約 50 万行にすぎません。 長期間のレポートを高速化するには、15 分単位のロールアップテーブルを追加します。
- CLI の動詞:
collect(サンプルを 1 回取得して終了)、doctor(現在の読み取り値を表示し、 サンプラーの故障時には明示的に失敗)、report --hours N(テキストの概要)。
2 つの launchd ジョブ
どちらも ~/Library/LaunchAgents/ にあるユーザー用 LaunchAgent です。root も
デーモンも不要です。テンプレートはリポジトリに保存し、install.sh でプレースホルダーを埋めます。
1. コレクター — 60 秒ごとに collect を指定してバイナリを実行します:
RunAtLoad true、StartInterval 60、ProcessType Background、
LowPriorityIO true を設定し、標準出力/標準エラーを ~/Library/Logs/<project>/ に出力します。
プロセスは 1 秒未満で実行を終えて終了します。スケジューラーは launchd です
(launchctl list で PID が -、ステータスが 0 と表示されていれば正常です)。
2. GitHub 同期 — 3 時間ごとに scripts/sync.sh を実行します
(StartInterval 10800)。このスクリプトは次の処理を行います:
# snapshot safely while the DB is live, then normalize for git
sqlite3 "$db_path" ".backup '$tmp'"
sqlite3 "$tmp" 'PRAGMA journal_mode=DELETE;' # fold WAL into one file
mv -f "$tmp" backups/metrics.sqlite3
# commit ONLY the backups path, skip if unchanged, push to a PRIVATE repo
git add backups && git commit -m "Backup metrics database $(date '+%Y-%m-%d %H:%M')" -- backups
git push origin HEAD
稼働中の WAL データベースを cp でコピーしてはいけません。必ず sqlite3 .backup を使用してください。
メトリクスから日々の活動パターンが分かるため、リポジトリはプライベートに保ってください。
install.sh のパターン
swift build -c release
# run the binary from Application Support, NOT the repo build dir,
# so rebuilds/branch switches never break the running job
install -m 755 .build/release/<project> "$data_dir/bin/"
install -m 644 launchd/<label>.plist ~/Library/LaunchAgents/
sed -i '' -e "s|__EXECUTABLE__|$binary|" ... "$agent_path" # fill placeholders
plutil -lint "$agent_path" # validate before loading
launchctl bootout "gui/$UID" "$agent_path" 2>/dev/null || true # idempotent reinstall
launchctl bootstrap "gui/$UID" "$agent_path"
uninstall.sh はその逆を行います。両方のエージェントを bootout し、plist を削除します。
com.<yourname>.<project> のようなリバース DNS 形式のラベルを使用してください。
インストールの確認
launchctl list | grep <project> # exit status 0 = last run OK
sqlite3 "$db" "SELECT datetime(MAX(timestamp),'unixepoch','localtime') FROM raw_samples;"
# must be under a minute old; also run the doctor verb
サンプルの取得が止まった場合は、まず ~/Library/Logs/<project>/stderr.log を確認してください。
オプション:分離されたアプリ単位のモニター
アプリを 1 つ(例:メモリリークのある Electron IDE)監視する場合は、独自のスキーマ、インストールスクリプト、
ADR を備えた、別のオプトイン型コレクターを追加します。バンドルパスでアプリのプロセスを特定し
(名前の部分一致では特定しないでください)、proc_pid_rusage/proc_pidinfo でプロセス単位の
CPU/RSS/ディスク IO を読み取ります。低コストで、root も不要です。
また、ループ内で ps を起動してはいけません。それ自体が既知の遅延原因です。