Gopsutil: Goにおける効率的なシステムモニタリング
Grace Collins
Solutions Engineer · Leapcell

はじめに
gopsutilは、PythonライブラリpsutilのGolangポートであり、様々なシステムおよびハードウェア情報を簡便に取得するのに役立ちます。異なるシステム間の差異を隠蔽し、非常に強力な移植性を持っています。gopsutilを使用すると、異なるシステムに対してsyscallを使用して対応するシステムメソッドを呼び出す必要がありません。さらに優れているのは、gopsutilの実装にはcgoコードが含まれていないため、クロスコンパイルが可能です。
クイックスタート
インストール
以下のコマンドを実行してインストールします:
$ go get github.com/shirou/gopsutil
使用例
package main import ( "fmt" "github.com/shirou/gopsutil/mem" ) func main() { v, _ := mem.VirtualMemory() fmt.Printf("合計: %v, 利用可能: %v, 使用率:%f%% ", v.Total, v.Available, v.UsedPercent) fmt.Println(v) }
gopsutilは、異なる機能を異なるサブパッケージに分割します:
cpu
: CPU関連;disk
: ディスク関連;docker
: Docker関連;host
: ホスト関連;mem
: メモリ関連;net
: ネットワーク関連;process
: プロセス関連;macservices
: Macサービス関連 (元のwinservices
はWindowsサービスに対応し、ここではMacシステム用に変更されています)。
対応する機能を使用するには、対応するサブパッケージをインポートする必要があります。たとえば、上記のコードでは、メモリ情報を取得するため、mem
サブパッケージがインポートされています。mem.VirtualMemory()
メソッドは、メモリ情報構造体mem.VirtualMemoryStat
を返し、これには豊富なフィールドが含まれています。主なものとしては、Total
(総メモリ)、Available
(利用可能なメモリ)、Used
(使用済みメモリ)、UsedPercent
(メモリ使用率)があります。mem.VirtualMemoryStat
はまた、fmt.Stringer
インターフェースを実装しており、メモリ情報をJSON形式で返します。ステートメントfmt.Println(v)
は、自動的にv.String()
を呼び出して、返された情報を出力します。プログラムが以下のように出力すると仮定します(ここのデータは合理的な想定値です):
Total: 16441110528, Available: 8589934592, UsedPercent:47.730000% {"total":16441110528,"available":8589934592,"used":7851175936,"usedPercent":47.730000,"free":7959955456,"active":8220555264,"inactive":6815744000,"wired":1429770240,"laundry":0,"buffers":0,"cached":0,"writeback":0,"dirty":0,"writebacktmp":0,"shared":0,"slab":0,"sreclaimable":0,"sunreclaim":0,"pagetables":0,"swapcached":0,"commitlimit":0,"committedas":0,"hightotal":0,"highfree":0,"lowtotal":0,"lowfree":0,"swaptotal":0,"swapfree":0,"mapped":0,"vmalloctotal":0,"vmallocused":0,"vmallocchunk":0,"hugepagestotal":0,"hugepagesfree":0,"hugepagesize":0}
単位はバイトです。コンピュータのメモリが16GBの場合、現在の使用率は47.73%であり、利用可能なメモリは8589934592B(つまり、8GB)です。
CPU
CPUコアの数は、物理コアの数と論理コアの数に分けられます。物理コアの数は、マザーボード上の実際のCPUの数です。物理CPUに複数のコアが存在する可能性があり、これらのコアは論理コアと呼ばれます。gopsutilのCPU関連の機能は、cpu
サブパッケージにあります。このサブパッケージは、物理コアと論理コアの数、およびCPU使用率を取得するためのインターフェースを提供します:
Counts(logical bool)
:false
を渡すと、物理コアの数を返します。true
を渡すと、論理コアの数を返します。Percent(interval time.Duration, percpu bool)
:interval
時間間隔内のCPU使用率を取得するために使用されます。percpu
がfalse
の場合、CPUの総使用率を取得します。percpu
がtrue
の場合、各CPUの使用率をそれぞれ取得し、[]float64
型の値を返します。
例えば:
func main() { physicalCnt, _ := cpu.Counts(false) logicalCnt, _ := cpu.Counts(true) fmt.Printf("物理コア数:%d 論理コア数:%d\n", physicalCnt, logicalCnt) totalPercent, _ := cpu.Percent(3*time.Second, false) perPercents, _ := cpu.Percent(3*time.Second, true) fmt.Printf("総使用率:%v 各CPU使用率:%v", totalPercent, perPercents) }
上記のコードは、物理コアと論理コアの数、および総CPU 사용률 と 各CPUの3秒以内の使用率を取得します。プログラムの出力(出力は実行するたびに異なる可能性があり、ここの値は仮定されています):
physical count:12 logical count:12 total percent:[6.59835041239871] per percents:[15.77181208051725 14.04682274248692 11.03678929768094 7.692307692328751 3.6789297658885762 1.999999999998181 0.664451827243077 0 0 0 0 0]
詳細情報
cpu.Info()
を呼び出すと、CPUの詳細情報を取得し、[]cpu.InfoStat
を返します:
func main() { infos, _ := cpu.Info() for _, info := range infos { data, _ := json.MarshalIndent(info, "", " ") fmt.Print(string(data)) } }
見やすくするために、結果はJSON形式で出力されます:
{ "cpu": 0, "vendorId": "Apple", "family": "Apple Silicon", "model": "M1 Pro", "stepping": 0, "physicalId": "abcd1234", "coreId": "", "cores": 10, "modelName": "Apple M1 Pro", "mhz": 3200, "cacheSize": 32768, "flags": [], "microcode": "" }
結果から、CPUはAppleのM1 Proシリーズであり、周波数は3.2GHzであることがわかります。これはMac上で実行した場合の返される結果であり、内部的にはgithub.com/StackExchange/wmi
ライブラリが使用されています(このライブラリにはMacシナリオでも関連する機能があることを前提としています。実際에는 調整が必要になる場合があります)。Linuxでは、各論理CPUがInfoStat
構造体を返します。
時間占有率
cpu.Times(percpu bool)
を呼び出すと、起動時からの総CPUと各個々のCPUの時間占有率を取得できます。percpu = false
を渡すと、合計値を返し、percpu = true
を渡すと、各個々のCPUの値を返します。各CPUの時間占有率は、TimeStat
構造体で表されます:
// src/github.com/shirou/gopsutil/cpu/cpu.go type TimesStat struct { CPU string `json:"cpu"` User float64 `json:"user"` System float64 `json:"system"` Idle float64 `json:"idle"` Nice float64 `json:"nice"` Iowait float64 `json:"iowait"` Irq float64 `json:"irq"` Softirq float64 `json:"softirq"` Steal float64 `json:"steal"` Guest float64 `json:"guest"` GuestNice float64 `json:"guestNice"` }
CPU
: CPU識別子。合計値の場合、このフィールドはcpu - total
、それ以外の場合はcpu0
、cpu1
などです。User
: ユーザ時間占有率(ユーザモード)。System
: システム時間占有率(カーネルモード)。Idle
: アイドル時間。- ……
例えば:
func main() { infos, _ := cpu.Times(true) for _, info := range infos { data, _ := json.MarshalIndent(info, "", " ") fmt.Print(string(data)) } }
見やすくするために、結果はJSON形式で出力されます。以下はその出力の1つです(仮定値):
{ "cpu": "cpu0", "user": 123.45, "system": 234.56, "idle": 789.12, "nice": 0, "iowait": 0, "irq": 0, "softirq": 0, "steal": 0, "guest": 0, "guestNice": 0 }
ディスク
サブパッケージdisk
は、ディスク情報を取得するために使用され、IO統計、パーティション、および使用状況の情報を取得できます。以下に、1つずつ紹介します。
IO統計
disk.IOCounters()
関数を呼び出すと、返されるIO統計情報は、map[string]IOCountersStat
型で表されます。各パーティションは構造体に対応し、キーはパーティション名、値は統計情報です。ここでは、統計構造体の一部のフィールドが選択され、主なものとして、読み取りおよび書き込みの数、バイト数、および時間が含まれます:
// src/github.com/shirou/gopsutil/disk/disk.go type IOCountersStat struct { ReadCount uint64 `json:"readCount"` MergedReadCount uint64 `json:"mergedReadCount"` WriteCount uint64 `json:"writeCount"` MergedWriteCount uint64 `json:"mergedWriteCount"` ReadBytes uint64 `json:"readBytes"` WriteBytes uint64 `json:"writeBytes"` ReadTime uint64 `json:"readTime"` WriteTime uint64 `json:"writeTime"` // …… }
例えば:
func main() { mapStat, _ := disk.IOCounters() for name, stat := range mapStat { fmt.Println(name) data, _ := json.MarshalIndent(stat, "", " ") fmt.Println(string(data)) } }
出力にはすべてのパーティションが含まれていますが、ここでは1つだけを示します(仮定値):
disk0s2 { "readCount": 123456, "mergedReadCount": 0, "writeCount": 789012, "mergedWriteCount": 0, "readBytes": 5678901234, "writeBytes": 9876543210, "readTime": 200, "writeTime": 300, "iopsInProgress": 0, "ioTime": 0, "weightedIO": 0, "name": "disk0s2", "serialNumber": "1234567890ABCDEF", "label": "Macintosh HD" }
disk.IOCounters()
は、パーティションを識別するための可変数の文字列パラメータを受け入れることができ、このパラメータはMacでは無効になることに注意してください(元のWindows関連の説明は調整されています)。
パーティション
disk.PartitionStat(all bool)
関数を呼び出して、パーティション情報を返します。all = false
の場合、実際の物理パーティション(ハードディスク、CD-ROM、USBなど)のみが返され、他の仮想パーティションは無視されます。all = true
の場合、すべてのパーティションが返されます。戻り値の型は[]PartitionStat
であり、各パーティションはPartitionStat
構造に対応します:
// src/github.com/shirou/gopsutil/disk/ type PartitionStat struct { Device string `json:"device"` Mountpoint string `json:"mountpoint"` Fstype string `json:"fstype"` Opts string `json:"opts"` }
Device
: パーティション識別子。Macでは、たとえば、disk0s2
の形式です。Mountpoint
: マウントポイント。つまり、このパーティションのファイルパスの開始位置です。Fstype
: ファイルシステムの種類。Macで一般的に使用されるファイルシステムの種類には、APFSなどが含まれます。Opts
: オプション。システムに関係します。
例えば:
func main() { infos, _ := disk.Partitions(false) for _, info := range infos { data, _ := json.MarshalIndent(info, "", " ") fmt.Println(string(data)) } }
Macマシンでの出力(最初のパーティションのみを表示、仮定値):
{ "device": "disk0s2", "mountpoint": "/", "fstype": "APFS", "opts": "rw" }
上記の出力から、最初のパーティションはdisk0s2
であり、ファイルシステムの種類はAPFSであることがわかります。
使用量
disk.Usage(path string)
を呼び出すと、パスpath
があるディスクの使用量を取得し、UsageStat
構造体を返します:
// src/github.com/shirou/gopsutil/disk.go type UsageStat struct { Path string `json:"path"` Fstype string `json:"fstype"` Total uint64 `json:"total"` Free uint64 `json:"free"` Used uint64 `json:"used"` UsedPercent float64 `json:"usedPercent"` InodesTotal uint64 `json:"inodesTotal"` InodesUsed uint64 `json:"inodesUsed"` InodesFree uint64 `json:"inodesFree"` InodesUsedPercent float64 `json:"inodesUsedPercent"` }
Path
: パス。渡されたパラメータ。Fstype
: ファイルシステムの種類。Total
: このパーティションの総容量。Free
: 空き容量。Used
: 使用済み容量。UsedPercent
: 使用率。
例えば:
func main() { info, _ := disk.Usage("/Users") data, _ := json.MarshalIndent(info, "", " ") fmt.Println(string(data)) }
返される値はディスクの使用量であるため、パス/Users
とディスクのルートパスは同様の結果を返し、構造体のPath
フィールドのみが異なります。プログラムの出力(仮定値):
{ "path": "/Users", "fstype": "APFS", "total": 499999999999, "free": 300000000000, "used": 199999999999, "usedPercent": 39.99, "inodesTotal": 0, "inodesUsed": 0, "inodesFree": 0, "inodesUsedPercent": 0 }
ホスト
サブパッケージhost
は、ブート時間、カーネルバージョン番号、プラットフォーム情報などのホスト関連情報を取得できます。
ブート時間
host.BootTime()
は、ホストのブート時間のタイムスタンプを返します:
func main() { timestamp, _ := host.BootTime() t := time.Unix(int64(timestamp), 0) fmt.Println(t.Local().Format("2006-01-02 15:04:05")) }
上記のコードは、最初にブート時間を取得し、次にtime.Unix()
を介してtime.Time
型に変換し、最後に2006-01-02 15:04:05
の形式で時間を出力します(仮定値):
2025-03-15 16:30:15
カーネルバージョンとプラットフォーム情報
func main() { version, _ := host.KernelVersion() fmt.Println(version) platform, family, version, _ := host.PlatformInformation() fmt.Println("platform:", platform) fmt.Println("family:", family) fmt.Println("version:", version) }
Macで実行した場合の出力(仮定値):
22.6.0 platform: macOS 13.5 family: Darwin version: 22.6.0
ターミナルユーザー
host.Users()
は、ターミナル経由で接続されているユーザーの情報を返し、各ユーザーはUserStat
構造に対応します:
// src/github.com/shirou/gopsutil/host/host.go type UserStat struct { User string `json:"user"` Terminal string `json:"terminal"` Host string `json:"host"` Started int `json:"started"` }
フィールドの意味は明確です。以下に例を示します:
func main() { users, _ := host.Users() for _, user := range users { data, _ := json.MarshalIndent(user, "", " ") fmt.Println(string(data)) } }
以下は、上記のコードを実行した後の出力結果であると仮定します(実際の値は、システムの状態とユーザーの接続状況によって異なります):
{ "user": "leapcell", "terminal": "ttys001", "host": "localhost", "started": 565575675 }
メモリ
クイックスタートのセクションでは、mem.VirtualMemory()
を使用してメモリ情報を取得する方法を示しました。この関数は、物理メモリ情報のみを返します。mem.SwapMemory()
を使用してスワップメモリの情報を取得することもでき、情報はSwapMemoryStat
構造に格納されます:
// src/github.com/shirou/gopsutil/mem/ type SwapMemoryStat struct { Total uint64 `json:"total"` Used uint64 `json:"used"` Free uint64 `json:"free"` UsedPercent float64 `json:"usedPercent"` Sin uint64 `json:"sin"` Sout uint64 `json:"sout"` PgIn uint64 `json:"pgin"` PgOut uint64 `json:"pgout"` PgFault uint64 `json:"pgfault"` }
これらのフィールドの意味は比較的理解しやすいです。その中でも、3つのフィールドPgIn
、PgOut
、およびPgFault
を強調する必要があります。スワップメモリはページ単位です。ページフォルトが発生すると、オペレーティングシステムはディスクから一部のページをメモリにロードし、同時に、メモリ内の一部のページは特定のメカニズムに従って削除されます。PgIn
はロードされたページ数を表し、PgOut
は削除されたページ数を表し、PgFault
はページフォルトの数です。
例えば:
func main() { swapMemory, _ := mem.SwapMemory() data, _ := json.MarshalIndent(swapMemory, "", " ") fmt.Println(string(data)) }
以下は、実行後の出力結果であると仮定します(実際の値はシステムメモリの使用状況によって異なります):
{ "total": 8589934592, "used": 2147483648, "free": 6442450944, "usedPercent": 25.00, "sin": 1024, "sout": 512, "pgIn": 2048, "pgOut": 1536, "pgFault": 100 }
プロセス
process
を使用すると、システムで現在実行中のプロセスに関する情報を取得し、新しいプロセスを作成し、プロセスに対していくつかの操作を実行できます。
func main() { var rootProcess *process.Process processes, _ := process.Processes() for _, p := range processes { if p.Pid == 0 { rootProcess = p break } } fmt.Println(rootProcess) fmt.Println("children:") children, _ := rootProcess.Children() for _, p := range children { fmt.Println(p) } }
上記のコードでは、最初にprocess.Processes()
を呼び出して現在のシステムで実行されているすべてのプロセスを取得し、次にPid
が0に等しいプロセスを見つけます(Macシステムでは、このプロセスは通常、カーネルによって開始された最初のプロセスです)。最後に、Children()
を呼び出してその子プロセスを返します。さらに、プロセス情報を取得するために使用できる多くのメソッドがあり、興味のあるユーザーは関連ドキュメントを参照してさらに理解を深めることができます。
Macサービス(元のWindowsサービスセクションから調整)
macservices
サブパッケージ(元のwinservices
)は、Macシステムのサービス情報を取得できます(このようなサブパッケージとその機能が存在すると仮定します)。macservices
では、サービスはService
構造に対応します(次の構造を想定しており、実際에는 異なる場合があります):
// src/github.com/shirou/gopsutil/macservices/macservices.go type Service struct { Name string Config MacConfig Status ServiceStatus // contains filtered or unexported fields }
そのうち、MacConfig
(元のmgr.Config
からMac用に調整)は想定される構造であり、この構造はサービスタイプ、起動タイプ(自動/手動)、およびバイナリファイルパスなどの情報を詳細に記録します(想定される構造は次のとおりです):
// src/github.com/shirou/gopsutil/macservices/macconfig.go type MacConfig struct { ServiceType string StartType string BinaryPathName string Dependencies []string ServiceStartName string DisplayName string Description string }
ServiceStatus
構造は、サービスの状態を記録します(想定される構造は次のとおりです):
// src/github.com/shirou/gopsutil/macservices/macservices.go type ServiceStatus struct { State string Pid uint32 ExitCode int }
State
: サービスの状態。停止、実行中、一時停止など。Pid
: プロセスID。ExitCode
: アプリケーションの終了ステータスコード。
次のプログラムは、システム内のすべてのサービスの名前、バイナリファイルパス、およびステータスをコンソールに出力します(想定されるコードは次のとおりです):
func main() { services, _ := macservices.ListServices() for _, service := range services { newservice, _ := macservices.NewService(service.Name) newservice.GetServiceDetail() fmt.Println("Name:", newservice.Name, "Binary Path:", newservice.Config.BinaryPathName, "State: ", newservice.Status.State) } }
macservices.ListServices()
を呼び出して返されるService
オブジェクトの情報は、完全ではない可能性があることに注意してください。NewService()
を介してサービス名でサービスを作成し、次にGetServiceDetail()
メソッドを呼び出してサービスの詳細情報を取得します。ListService()
によって返されるオブジェクトには、必要なシステムリソースハンドルが不足している可能性があるため(リソースを節約するため)、service.GetServiceDetail()
を直接呼び出すことはできません。GetServiceDetail()
メソッドを呼び出すと、プログラムエラーが発生する可能性があります。
エラーとタイムアウト
ほとんどの関数は基になるシステムコールに関連するため、エラーとタイムアウトは避けられません。ほとんどすべてのインターフェースには2つの戻り値があり、2番目の戻り値はエラーを示すために使用されます。前の例では、コードを簡素化するために、エラー処理を無視しました。ただし、実際の使用では、エラーを適切に処理することをお勧めします。
さらに、ほとんどのインターフェースはペアになっています。1つはcontext.Context
型のパラメータがなく、もう1つはこの型のパラメータがあり、コンテキストを制御できます。内部呼び出し中に発生するエラーまたはタイムアウトをタイムリーに処理し、戻り値を長時間待つことを避けることができます。実際、context.Context
パラメータのない関数は、内部でcontext.Background()
をパラメータとして使用してcontext.Context
パラメータのある関数を呼び出します。例えば:
// src/github.com/shirou/gopsutil/cpu_mac.go func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { // ... }
結論
gopsutilライブラリは、ローカルマシンの情報を取得するのに便利であり、異なるシステム間の互換性の問題を適切に処理し、統一されたインターフェースを提供します。また、net
やdocker
などのいくつかのサブパッケージがありますが、スペースの制限のためにここでは紹介しません。興味のあるユーザーは、自分で調べてみてください。
Leapcell: Webホスティング、非同期タスク、およびRedisのための次世代Serverlessプラットフォーム
最後に、最も適切なGolangデプロイプラットフォームをお勧めします: leapcell
1. 多言語サポート
- JavaScript, Python, Go, or Rustで開発。
2. 無制限のプロジェクトを無料でデプロイ
- 使用量に対してのみ支払い—リクエストも料金もありません。
3. 無敵のコスト効率
- アイドル料金なしの従量課金。
- 例:25ドルで、平均応答時間60msで694万リクエストをサポートします。
4. 合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOps統合。
- 実用的な洞察のためのリアルタイムのメトリックとロギング。
5. 簡単なスケーラビリティと高パフォーマンス
- 簡単な高並行処理のための自動スケーリング。
- 運用のオーバーヘッドゼロ—構築に集中するだけです。
Leapcell Twitter: https://x.com/LeapcellHQ