Как получить информацию о процессе по его PID в Go
Использование пакета github.com/mitchellh/go-ps для получения информации о процессе
В Go нет встроенной стандартной библиотеки для получения детальной информации о процессе по PID, но существует отличное стороннее решение — пакет go-ps от Mitchell Hashimoto. Этот пакет предоставляет кроссплатформенный API (Linux, macOS, Windows) для работы с процессами.
Установка пакета:
go get github.com/mitchellh/go-ps
Основной интерфейс пакета — функция ps.FindProcess(pid int), которая возвращает структуру Process с базовой информацией: PID, PPID (родительский PID) и имя процесса. Если процесс не найден, возвращается nil.
Пример получения имени процесса по PID:
package main
import (
"fmt"
"os"
"strconv"
"github.com/mitchellh/go-ps"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Использование: go run main.go <PID>")
return
}
pid, err := strconv.Atoi(os.Args[1])
if err != nil {
fmt.Printf("Ошибка: PID должен быть числом, получено: %s\n", os.Args[1])
return
}
process, err := ps.FindProcess(pid)
if err != nil {
fmt.Printf("Ошибка при поиске процесса: %v\n", err)
return
}
if process == nil {
fmt.Printf("Процесс с PID %d не найден\n", pid)
return
}
fmt.Printf("PID: %d\n", process.Pid())
fmt.Printf("PPID: %d\n", process.PPid())
fmt.Printf("Имя: %s\n", process.Executable())
}
Как получить больше информации (статус, память, время работы)
Пакет go-ps предоставляет только базовую информацию. Для получения расширенных данных (статус, использование памяти, время работы) вам потребуется комбинировать его с чтением /proc/[PID]/status под Linux. Вот пример:
package main
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"github.com/mitchellh/go-ps"
)
type ProcessInfo struct {
PID int
PPID int
Name string
Status string
Memory string
Uptime string
}
func getProcessDetails(pid int) (*ProcessInfo, error) {
// Получаем базовую информацию через go-ps
process, err := ps.FindProcess(pid)
if err != nil {
return nil, fmt.Errorf("не удалось найти процесс: %v", err)
}
if process == nil {
return nil, fmt.Errorf("процесс с PID %d не найден", pid)
}
info := &ProcessInfo{
PID: process.Pid(),
PPID: process.PPid(),
Name: process.Executable(),
}
// Читаем /proc/[PID]/status для расширенной информации
data, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
if err != nil {
// На Windows или macOS это не сработает — возвращаем базовую информацию
return info, nil
}
lines := strings.Split(string(data), "\n")
for _, line := range lines {
switch {
case strings.HasPrefix(line, "State:"):
info.Status = strings.TrimSpace(strings.TrimPrefix(line, "State:"))
case strings.HasPrefix(line, "VmRSS:"):
info.Memory = strings.TrimSpace(strings.TrimPrefix(line, "VmRSS:"))
}
}
return info, nil
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Использование: go run main.go <PID>")
return
}
pid, _ := strconv.Atoi(os.Args[1])
info, err := getProcessDetails(pid)
if err != nil {
fmt.Printf("Ошибка: %v\n", err)
return
}
fmt.Printf("=== Информация о процессе PID %d ===\n", info.PID)
fmt.Printf("Имя: %s\n", info.Name)
fmt.Printf("Родительский PID: %d\n", info.PPID)
fmt.Printf("Статус: %s\n", info.Status)
fmt.Printf("Память (RSS): %s\n", info.Memory)
}
Кроссплатформенное решение с shirou/gopsutil
Если вам нужно больше данных и полная кроссплатформенность, рекомендую пакет github.com/shirou/gopsutil. Он предоставляет структурированный доступ к информации о процессах на Linux, macOS, Windows и FreeBSD.
Установка: go get github.com/shirou/gopsutil/v3/process
package main
import (
"fmt"
"os"
"strconv"
"github.com/shirou/gopsutil/v3/process"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Использование: go run main.go <PID>")
return
}
pid, _ := strconv.Atoi(os.Args[1])
p, err := process.NewProcess(int32(pid))
if err != nil {
fmt.Printf("Ошибка: %v\n", err)
return
}
name, _ := p.Name()
status, _ := p.Status()
memInfo, _ := p.MemoryInfo()
createTime, _ := p.CreateTime()
exe, _ := p.Exe()
fmt.Printf("Имя: %s\n", name)
fmt.Printf("Статус: %s\n", status)
fmt.Printf("Исполняемый файл: %s\n", exe)
fmt.Printf("Память RSS: %d байт\n", memInfo.RSS)
fmt.Printf("Время запуска: %d (unix timestamp)\n", createTime)
}
Этот пакет работает на всех основных ОС и предоставляет десятки метрик: CPU, память, сеть, открытые файлы и т.д.
Заключение
- Для простых задач (имя и PID) — используйте
go-ps. - Для расширенной информации под Linux — комбинируйте
go-psс чтением/proc/[PID]/status. - Для полноценного кроссплатформенного решения — используйте
gopsutil. Это самый мощный и документированный вариант.
Альтернативный подход: прямой парсинг /proc/[PID] с помощью os.ReadFile
Если вы не хотите подключать сторонние зависимости и работаете только под Linux, можно обойтись стандартными средствами Go, написав небольшую обертку для парсинга файлов в /proc. Это даст полный контроль и отсутствие внешних библиотек.
Вот пример получения статуса процесса без сторонних пакетов:
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
type ProcStatus struct {
Pid int
Name string
State string
VmSize string
VmRSS string
}
func ReadProcStatus(pid int) (*ProcStatus, error) {
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/status", pid))
if err != nil {
return nil, err
}
ps := &ProcStatus{Pid: pid}
lines := strings.Split(string(data), "\n")
for _, line := range lines {
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
switch key {
case "Name":
ps.Name = value
case "State":
ps.State = value
case "VmSize":
ps Ответов пока нет.
Войдите чтобы оставить ответ
Блоги