Skip to main content

Overview

Starting from v3.23.6, gopsutil supports passing configuration through Go’s context.Context. This allows you to:
  • Set custom paths for system directories
  • Control operation timeouts and cancellation
  • Pass configuration without global state
  • Maintain thread-safe, concurrent operations
Every function in gopsutil has a WithContext variant (e.g., VirtualMemory() and VirtualMemoryWithContext()).

Basic Context Usage

All WithContext functions accept a context.Context as their first parameter:
package main

import (
    "context"
    "fmt"
    "github.com/shirou/gopsutil/v4/mem"
)

func main() {
    ctx := context.Background()
    v, err := mem.VirtualMemoryWithContext(ctx)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Total: %v, Used: %.2f%%\n", v.Total, v.UsedPercent)
}

Configuring Paths via Context

Context-based path configuration is particularly useful in containerized environments where system directories may be mounted at non-standard locations.
You can override system directory paths by passing an EnvMap in the context:
import (
    "context"
    "github.com/shirou/gopsutil/v4/common"
    "github.com/shirou/gopsutil/v4/mem"
)

ctx := context.WithValue(
    context.Background(),
    common.EnvKey,
    common.EnvMap{
        common.HostProcEnvKey: "/myproc",
    },
)

v, err := mem.VirtualMemoryWithContext(ctx)

Available Environment Keys

The following environment keys can be configured via context:
KeyDefaultDescription
HostProcEnvKey/procLinux proc filesystem
HostSysEnvKey/sysLinux sys filesystem
HostEtcEnvKey/etcSystem configuration directory
HostVarEnvKey/varVariable data directory
HostRunEnvKey/runRuntime data directory
HostDevEnvKey/devDevice filesystem
HostRootEnvKey/Root filesystem
HostProcMountinfo(empty)Override for /proc/N/mountinfo
These keys are primarily used on Linux systems. On other platforms, they may have limited or no effect.

Priority Order

When resolving configuration values, gopsutil follows this priority order:
1

Context Values (Highest Priority)

Values set in context.Context via common.EnvMap take precedence over all other sources.
ctx := context.WithValue(context.Background(), 
    common.EnvKey, 
    common.EnvMap{common.HostProcEnvKey: "/custom/proc"},
)
// Uses /custom/proc
2

Environment Variables

If not set in context, gopsutil checks environment variables like HOST_PROC.
export HOST_PROC=/host/proc
# Uses /host/proc if not overridden by context
3

Default Values (Lowest Priority)

If neither context nor environment variables are set, gopsutil uses platform defaults.
// Uses /proc on Linux by default
v, _ := mem.VirtualMemory()

Timeout and Cancellation

Use Go’s context features to implement timeouts and cancellation:
import (
    "context"
    "time"
    "github.com/shirou/gopsutil/v4/process"
)

// Set a 5-second timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

processes, err := process.ProcessesWithContext(ctx)
if err != nil {
    if ctx.Err() == context.DeadlineExceeded {
        fmt.Println("Operation timed out")
    }
}

Practical Examples

Monitoring from Kubernetes Sidecar

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/shirou/gopsutil/v4/common"
    "github.com/shirou/gopsutil/v4/cpu"
    "github.com/shirou/gopsutil/v4/mem"
)

func main() {
    // Host system mounted at /host in the container
    ctx := context.WithValue(
        context.Background(),
        common.EnvKey,
        common.EnvMap{
            common.HostProcEnvKey: "/host/proc",
            common.HostSysEnvKey:  "/host/sys",
        },
    )

    for {
        // Get host CPU usage
        cpuPercent, _ := cpu.PercentWithContext(ctx, time.Second, false)
        fmt.Printf("Host CPU: %.2f%%\n", cpuPercent[0])

        // Get host memory usage
        memInfo, _ := mem.VirtualMemoryWithContext(ctx)
        fmt.Printf("Host Memory: %.2f%%\n", memInfo.UsedPercent)

        time.Sleep(10 * time.Second)
    }
}

Testing with Custom Paths

package mypackage

import (
    "context"
    "testing"

    "github.com/shirou/gopsutil/v4/common"
    "github.com/shirou/gopsutil/v4/host"
)

func TestHostInfo(t *testing.T) {
    // Use test fixtures
    ctx := context.WithValue(
        context.Background(),
        common.EnvKey,
        common.EnvMap{
            common.HostProcEnvKey: "./testdata/proc",
            common.HostSysEnvKey:  "./testdata/sys",
            common.HostEtcEnvKey:  "./testdata/etc",
        },
    )

    info, err := host.InfoWithContext(ctx)
    if err != nil {
        t.Fatalf("Failed to get host info: %v", err)
    }

    // Assertions
    if info.Platform != "ubuntu" {
        t.Errorf("Expected ubuntu, got %s", info.Platform)
    }
}

Concurrent Operations with Shared Context

package main

import (
    "context"
    "fmt"
    "sync"

    "github.com/shirou/gopsutil/v4/cpu"
    "github.com/shirou/gopsutil/v4/disk"
    "github.com/shirou/gopsutil/v4/mem"
    "github.com/shirou/gopsutil/v4/net"
)

type SystemStats struct {
    CPU  []float64
    Mem  float64
    Disk float64
    Net  uint64
}

func getSystemStats(ctx context.Context) (*SystemStats, error) {
    var (
        stats SystemStats
        wg    sync.WaitGroup
        mu    sync.Mutex
        errs  []error
    )

    // CPU
    wg.Add(1)
    go func() {
        defer wg.Done()
        cpu, err := cpu.PercentWithContext(ctx, 0, true)
        mu.Lock()
        defer mu.Unlock()
        if err != nil {
            errs = append(errs, err)
        } else {
            stats.CPU = cpu
        }
    }()

    // Memory
    wg.Add(1)
    go func() {
        defer wg.Done()
        mem, err := mem.VirtualMemoryWithContext(ctx)
        mu.Lock()
        defer mu.Unlock()
        if err != nil {
            errs = append(errs, err)
        } else {
            stats.Mem = mem.UsedPercent
        }
    }()

    // Disk
    wg.Add(1)
    go func() {
        defer wg.Done()
        disk, err := disk.UsageWithContext(ctx, "/")
        mu.Lock()
        defer mu.Unlock()
        if err != nil {
            errs = append(errs, err)
        } else {
            stats.Disk = disk.UsedPercent
        }
    }()

    // Network
    wg.Add(1)
    go func() {
        defer wg.Done()
        counters, err := net.IOCountersWithContext(ctx, false)
        mu.Lock()
        defer mu.Unlock()
        if err != nil {
            errs = append(errs, err)
        } else if len(counters) > 0 {
            stats.Net = counters[0].BytesSent + counters[0].BytesRecv
        }
    }()

    wg.Wait()

    if len(errs) > 0 {
        return nil, errs[0]
    }

    return &stats, nil
}

func main() {
    ctx := context.Background()
    stats, err := getSystemStats(ctx)
    if err != nil {
        panic(err)
    }

    fmt.Printf("CPU: %v\n", stats.CPU)
    fmt.Printf("Memory: %.2f%%\n", stats.Mem)
    fmt.Printf("Disk: %.2f%%\n", stats.Disk)
    fmt.Printf("Network: %d bytes\n", stats.Net)
}

Best Practices

Always Use WithContext

Prefer WithContext variants for better control and testability, even if you’re just passing context.Background().

Reuse Contexts

Create context once for a logical operation and pass it through your call stack rather than creating new contexts repeatedly.

Don't Store Contexts

Never store contexts in structs. Pass them as function parameters according to Go conventions.

Cancel When Done

Always call the cancel function returned by WithTimeout or WithCancel using defer to prevent context leaks.

Common Patterns

Wrapper Functions

type Monitor struct {
    ctx context.Context
}

// Don't do this - storing context is an anti-pattern
// func NewMonitor(ctx context.Context) *Monitor {
//     return &Monitor{ctx: ctx}
// }

// Instead, pass context to methods
func (m *Monitor) GetMemory(ctx context.Context) (*mem.VirtualMemoryStat, error) {
    return mem.VirtualMemoryWithContext(ctx)
}

Configuration Helper

func NewHostContext(basePath string) context.Context {
    return context.WithValue(
        context.Background(),
        common.EnvKey,
        common.EnvMap{
            common.HostProcEnvKey: filepath.Join(basePath, "proc"),
            common.HostSysEnvKey:  filepath.Join(basePath, "sys"),
            common.HostEtcEnvKey:  filepath.Join(basePath, "etc"),
            common.HostVarEnvKey:  filepath.Join(basePath, "var"),
            common.HostRunEnvKey:  filepath.Join(basePath, "run"),
            common.HostDevEnvKey:  filepath.Join(basePath, "dev"),
        },
    )
}

// Usage
ctx := NewHostContext("/hostfs")
info, err := host.InfoWithContext(ctx)

Next Steps

Environment Variables

Learn about environment variable configuration

Caching

Optimize performance with caching strategies

Quick Start

Get started with basic gopsutil usage

API Reference

Explore the complete API documentation

Build docs developers (and LLMs) love