Leapcell: The Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis
はじめに
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("Total: %v, Available: %v, UsedPercent:%f%%\n", 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の数です。1つの物理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("physical count:%d logical count:%d\n", physicalCnt, logicalCnt)
totalPercent, _ := cpu.Percent(3*time.Second, false)
perPercents, _ := cpu.Percent(3*time.Second, true)
fmt.Printf("total percent:%v per percents:%v", totalPercent, perPercents)
}
上記のコードは、物理コアと論理コアの数、および3秒間の全体のCPU使用率とそれぞれのCPUの使用率を取得しています。プログラムの出力(出力は実行ごとに異なる場合があり、ここでの値は想定値です):
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統計情報、パーティション、使用率情報を取得できます。以下は、それぞれの説明です。
IO統計情報
disk.IOCounters()
関数を呼び出すと、返されるIO統計情報はmap[string]IOCountersStat
型で表されます。各パーティションは1つの構造体に対応しており、キーはパーティション名で、値は統計情報です。ここでは、統計構造体のいくつかのフィールドを選択しています。主に読み取りと書き込みの回数、バイト数、時間が含まれます:
// 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
で、各パーティションは1つの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"`
}
これらのフィールドの意味は比較的わかりやすいです。特に、PgIn
、PgOut
、PgFault
の3つのフィールドについて強調します。スワップメモリはページ単位です。ページエラーが発生すると、オペレーティングシステムはディスクからいくつかのページをメモリに読み込み、同時にメモリ内のいくつかのページを特定のメカニズムに基づいて排除します。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
では、1つのサービスは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()
メソッドを呼び出してサービスの詳細情報を取得します。service.GetServiceDetail()
を直接呼び出すことはできません。なぜなら、ListService()
によって返されるオブジェクトには必要なシステムリソースハンドルが欠けている可能性があるからです(リソースを節約するため)。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: The Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis
最後に、最適なGolangデプロイメントプラットフォームをおすすめします:leapcell
1. 多言語対応
- JavaScript、Python、Go、またはRustで開発できます。
2. 無制限のプロジェクトを無料でデプロイ
- 利用量に応じて課金 — リクエストがなければ料金はかかりません。
3. 圧倒的なコスト効率
- 従量課金制で、アイドル時の料金はかかりません。
- 例:25ドルで平均応答時間60msで694万回のリクエストをサポートできます。
4. 効率的な開発者体験
- 直感的なUIで簡単にセットアップできます。
- 完全自動化されたCI/CDパイプラインとGitOps統合。
- アクション可能な洞察を得るためのリアルタイムメトリクスとロギング。
5. 簡単なスケーラビリティと高いパフォーマンス
- 高い同時接続性を簡単に処理するための自動スケーリング。
- オペレーションのオーバーヘッドはゼロ — 構築に集中できます。
LeapcellのTwitter: https://x.com/LeapcellHQ