How to get process details from its PID
Categories:
Retrieving Process Details by PID in Go

Learn how to programmatically obtain comprehensive information about a running process using its Process ID (PID) in Go, covering cross-platform considerations and practical examples.
Understanding and managing running processes is a fundamental aspect of system programming. Often, you might need to inspect a process's state, resource usage, or other metadata given only its Process ID (PID). This article will guide you through obtaining process details in Go, highlighting common approaches and libraries that simplify this task across different operating systems.
The Challenge of Cross-Platform Process Information
Retrieving process details can be surprisingly complex due to the varying ways operating systems manage and expose this information. Linux systems typically rely on the /proc
filesystem, while Windows uses its own set of APIs (e.g., CreateToolhelp32Snapshot
, OpenProcess
). macOS, being Unix-like, shares some similarities with Linux but also has its unique system calls. Go's standard library offers basic process management, but for detailed information, external libraries are often necessary to abstract away these OS-specific differences.
flowchart TD A[Start with PID] --> B{Operating System?} B -->|Linux/Unix| C[Read /proc/PID/*] B -->|Windows| D[Use Windows API (e.g., `CreateToolhelp32Snapshot`)] C --> E[Parse Files (status, cmdline, etc.)] D --> F[Query Process Information] E --> G[Extract Details (Name, Memory, CPU, etc.)] F --> G G --> H[Return Process Details] H[Return Process Details] --> I[End]
Cross-platform process detail retrieval workflow
Using the shirou/gopsutil
Library
For robust and cross-platform process information retrieval in Go, the shirou/gopsutil
library is an excellent choice. It provides a unified API to access system and process metrics, abstracting away the underlying OS-specific implementations. This library is widely used and actively maintained, making it a reliable solution for most use cases.
package main
import (
"fmt"
"log"
"os"
"github.com/shirou/gopsutil/v3/process"
)
func main() {
// Example PID (replace with a real PID on your system)
// You can find a PID using `pgrep` on Linux/macOS or Task Manager on Windows
pid := int32(os.Getpid()) // Get current process's PID for demonstration
proc, err := process.NewProcess(pid)
if err != nil {
log.Fatalf("Failed to get process for PID %d: %v", pid, err)
}
// Get process name
name, err := proc.Name()
if err != nil {
log.Printf("Warning: Could not get process name for PID %d: %v", pid, err)
} else {
fmt.Printf("PID: %d\n", pid)
fmt.Printf("Name: %s\n", name)
}
// Get CPU percent
cpuPercent, err := proc.CPUPercent()
if err != nil {
log.Printf("Warning: Could not get CPU percent for PID %d: %v", pid, err)
} else {
fmt.Printf("CPU Percent: %.2f%%\n", cpuPercent)
}
// Get memory info
memInfo, err := proc.MemoryInfo()
if err != nil {
log.Printf("Warning: Could not get memory info for PID %d: %v", pid, err)
} else {
fmt.Printf("Memory RSS: %d bytes\n", memInfo.RSS)
fmt.Printf("Memory VMS: %d bytes\n", memInfo.VMS)
}
// Get command line arguments
cmdline, err := proc.Cmdline()
if err != nil {
log.Printf("Warning: Could not get command line for PID %d: %v", pid, err)
} else {
fmt.Printf("Command Line: %s\n", cmdline)
}
// Get status
status, err := proc.Status()
if err != nil {
log.Printf("Warning: Could not get status for PID %d: %v", pid, err)
} else {
fmt.Printf("Status: %s\n", status[0]) // Status can return multiple states
}
// Get creation time
createTime, err := proc.CreateTime()
if err != nil {
log.Printf("Warning: Could not get creation time for PID %d: %v", pid, err)
} else {
fmt.Printf("Create Time: %s\n", time.Unix(0, createTime*int64(time.Millisecond)))
}
// Get parent PID
ppid, err := proc.Ppid()
if err != nil {
log.Printf("Warning: Could not get parent PID for PID %d: %v", pid, err)
} else {
fmt.Printf("Parent PID: %d\n", ppid)
}
}
Go program using gopsutil
to retrieve various process details.
gopsutil
installed: go get github.com/shirou/gopsutil/v3/process
. Also, remember that some process details (like CPU usage) are cumulative and require calling the function multiple times with a delay to get a meaningful rate.Handling Permissions and Errors
Accessing process information, especially for processes owned by other users or system processes, often requires elevated privileges. On Linux, this might mean running your Go program as root or with appropriate capabilities. On Windows, running as Administrator is usually necessary. Always include robust error handling, as processes can terminate unexpectedly, or you might lack the necessary permissions to query certain details.
package main
import (
"fmt"
"log"
"os"
"github.com/shirou/gopsutil/v3/process"
)
func main() {
// Attempt to get details for a PID that might not exist or be accessible
pid := int32(99999) // A PID that is likely not running or inaccessible
proc, err := process.NewProcess(pid)
if err != nil {
// Handle cases where the process doesn't exist or access is denied
if os.IsNotExist(err) {
fmt.Printf("Error: Process with PID %d does not exist.\n", pid)
} else if os.IsPermission(err) {
fmt.Printf("Error: Permission denied to access process with PID %d. Try running as administrator/root.\n", pid)
} else {
log.Fatalf("An unexpected error occurred for PID %d: %v", pid, err)
}
return
}
// If we reach here, the process object was successfully created
name, err := proc.Name()
if err != nil {
fmt.Printf("Could not get name for PID %d: %v\n", pid, err)
} else {
fmt.Printf("Successfully accessed process %d: %s\n", pid, name)
}
}
Example of error handling for non-existent or inaccessible processes.