diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index ce255f926..e636b763a 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -26,13 +26,13 @@ jobs: with: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - id: cache-paths run: | echo "::set-output name=cache::$(go env GOCACHE)" echo "::set-output name=mod-cache::$(go env GOMODCACHE)" - name: Cache go modules - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: | ${{ steps.cache-paths.outputs.cache }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5a9ebcadf..245f7e983 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,8 +19,9 @@ jobs: uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: 1.17 + cache: false - name: Checkout repository - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Setup golangci-lint uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index efd3baea3..6bdd103ac 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,6 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Release run: make release diff --git a/.github/workflows/sbom_generator.yml b/.github/workflows/sbom_generator.yml index 97565c191..771a7e1b4 100644 --- a/.github/workflows/sbom_generator.yml +++ b/.github/workflows/sbom_generator.yml @@ -13,13 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - uses: advanced-security/sbom-generator-action@375dee8e6144d9fd0ec1f5667b4f6fb4faacefed # v0.0.1 id: sbom env: GITHUB_TOKEN: ${{ github.token }} - - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: path: ${{steps.sbom.outputs.fileName }} name: "SBOM" diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index b700ca8bd..2c2198f12 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -8,6 +8,6 @@ jobs: name: Shellcheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Run ShellCheck uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dacda8bff..5f1f3a7c9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,13 +27,13 @@ jobs: with: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - id: go-env run: | echo "::set-output name=cache::$(go env GOCACHE)" echo "::set-output name=mod-cache::$(go env GOMODCACHE)" - name: Cache go modules - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: | ${{ steps.go-env.outputs.cache }} diff --git a/.golangci.yml b/.golangci.yml index 4d163db1a..170626bfd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,21 +1,21 @@ issues: max-same-issues: 0 - exclude-rules: - - linters: - - gosec - text: "G204" - - linters: - - revive - text: "var-naming" - - linters: - - revive - text: "exported" - - linters: - - revive - text: "empty-block" - - linters: - - revive - text: "unused-parameter" + exclude-rules: + - linters: + - gosec + text: "G204" + - linters: + - revive + text: "var-naming" + - linters: + - revive + text: "exported" + - linters: + - revive + text: "empty-block" + - linters: + - revive + text: "unused-parameter" linters: enable: - asciicheck @@ -26,6 +26,7 @@ linters: - gofmt - gofumpt - goimports + - gomodguard - gosec - gosimple - importas @@ -46,10 +47,16 @@ linters: - structcheck - unused - varcheck - linters-settings: gci: sections: - - standard - - default - - prefix(github.com/shirou) + - standard + - default + - prefix(github.com/shirou) + gomodguard: + blocked: + modules: + - io/ioutil: + recommandations: + - io + - os diff --git a/cpu/cpu_solaris_test.go b/cpu/cpu_solaris_test.go index 508aad5e6..dd9362c3a 100644 --- a/cpu/cpu_solaris_test.go +++ b/cpu/cpu_solaris_test.go @@ -1,7 +1,7 @@ package cpu import ( - "io/ioutil" + "os" "path/filepath" "reflect" "sort" @@ -49,7 +49,7 @@ func TestParseISAInfo(t *testing.T) { } for _, tc := range cases { - content, err := ioutil.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) + content, err := os.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) if err != nil { t.Errorf("cannot read test case: %s", err) } @@ -138,7 +138,7 @@ func TestParseProcessorInfo(t *testing.T) { } for _, tc := range cases { - content, err := ioutil.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) + content, err := os.ReadFile(filepath.Join("testdata", "solaris", tc.filename)) if err != nil { t.Errorf("cannot read test case: %s", err) } diff --git a/cpu/cpu_test.go b/cpu/cpu_test.go index 4202ce841..688660a1a 100644 --- a/cpu/cpu_test.go +++ b/cpu/cpu_test.go @@ -138,8 +138,8 @@ func testCPUPercent(t *testing.T, percpu bool) { if err != nil { t.Errorf("error %v", err) } - // Skip CircleCI which CPU num is different - if os.Getenv("CIRCLECI") != "true" { + // Skip CI which CPU num is different + if os.Getenv("CI") != "true" { if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) { t.Fatalf("wrong number of entries from CPUPercent: %v", v) } @@ -172,8 +172,8 @@ func testCPUPercentLastUsed(t *testing.T, percpu bool) { if err != nil { t.Errorf("error %v", err) } - // Skip CircleCI which CPU num is different - if os.Getenv("CIRCLECI") != "true" { + // Skip CI which CPU num is different + if os.Getenv("CI") != "true" { if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) { t.Fatalf("wrong number of entries from CPUPercent: %v", v) } diff --git a/disk/disk_linux.go b/disk/disk_linux.go index 5015c34ae..c06516c6c 100644 --- a/disk/disk_linux.go +++ b/disk/disk_linux.go @@ -9,7 +9,6 @@ import ( "context" "errors" "fmt" - "io/ioutil" "os" "path" "path/filepath" @@ -497,7 +496,7 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) { // Try to get the serial from udev data udevDataPath := common.HostRunWithContext(ctx, fmt.Sprintf("udev/data/b%d:%d", major, minor)) - if udevdata, err := ioutil.ReadFile(udevDataPath); err == nil { + if udevdata, err := os.ReadFile(udevDataPath); err == nil { scanner := bufio.NewScanner(bytes.NewReader(udevdata)) for scanner.Scan() { values := strings.Split(scanner.Text(), "=") @@ -510,8 +509,8 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) { // Try to get the serial from sysfs, look at the disk device (minor 0) directly // because if it is a partition it is not going to contain any device information devicePath := common.HostSysWithContext(ctx, fmt.Sprintf("dev/block/%d:0/device", major)) - model, _ := ioutil.ReadFile(filepath.Join(devicePath, "model")) - serial, _ := ioutil.ReadFile(filepath.Join(devicePath, "serial")) + model, _ := os.ReadFile(filepath.Join(devicePath, "model")) + serial, _ := os.ReadFile(filepath.Join(devicePath, "serial")) if len(model) > 0 && len(serial) > 0 { return fmt.Sprintf("%s_%s", string(model), string(serial)), nil } @@ -526,7 +525,7 @@ func LabelWithContext(ctx context.Context, name string) (string, error) { return "", nil } - dmname, err := ioutil.ReadFile(dmname_filename) + dmname, err := os.ReadFile(dmname_filename) if err != nil { return "", err } diff --git a/go.mod b/go.mod index 8fc781e97..78cc4af5f 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/tklauser/go-sysconf v0.3.12 github.com/yusufpapurcu/wmi v1.2.3 - golang.org/x/sys v0.11.0 + golang.org/x/sys v0.12.0 ) retract v3.22.11 diff --git a/go.sum b/go.sum index 914427d7b..e558c9ce6 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,9 @@ github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/host/host_darwin.go b/host/host_darwin.go index 1be2e8533..f045d4f17 100644 --- a/host/host_darwin.go +++ b/host/host_darwin.go @@ -8,7 +8,7 @@ import ( "context" "encoding/binary" "errors" - "io/ioutil" + "io" "os" "strings" "unsafe" @@ -59,7 +59,7 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) { } defer file.Close() - buf, err := ioutil.ReadAll(file) + buf, err := io.ReadAll(file) if err != nil { return ret, err } diff --git a/host/host_freebsd.go b/host/host_freebsd.go index 2c9aa9d0d..9a5382d39 100644 --- a/host/host_freebsd.go +++ b/host/host_freebsd.go @@ -7,7 +7,7 @@ import ( "bytes" "context" "encoding/binary" - "io/ioutil" + "io" "math" "os" "strings" @@ -54,7 +54,7 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) { } defer file.Close() - buf, err := ioutil.ReadAll(file) + buf, err := io.ReadAll(file) if err != nil { return ret, err } @@ -111,7 +111,7 @@ func getUsersFromUtmp(utmpfile string) ([]UserStat, error) { } defer file.Close() - buf, err := ioutil.ReadAll(file) + buf, err := io.ReadAll(file) if err != nil { return ret, err } diff --git a/host/host_linux.go b/host/host_linux.go index e6ac63a39..f9d7995e7 100644 --- a/host/host_linux.go +++ b/host/host_linux.go @@ -8,7 +8,7 @@ import ( "context" "encoding/binary" "fmt" - "io/ioutil" + "io" "os" "path/filepath" "regexp" @@ -91,7 +91,7 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) { } defer file.Close() - buf, err := ioutil.ReadAll(file) + buf, err := io.ReadAll(file) if err != nil { return nil, err } @@ -411,13 +411,13 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err } for _, file := range files { // Get the name of the temperature you are reading - name, err := ioutil.ReadFile(filepath.Join(file, "type")) + name, err := os.ReadFile(filepath.Join(file, "type")) if err != nil { warns.Add(err) continue } // Get the temperature reading - current, err := ioutil.ReadFile(filepath.Join(file, "temp")) + current, err := os.ReadFile(filepath.Join(file, "temp")) if err != nil { warns.Add(err) continue @@ -461,13 +461,13 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err // Get the label of the temperature you are reading label := "" - if raw, _ = ioutil.ReadFile(basepath + "_label"); len(raw) != 0 { + if raw, _ = os.ReadFile(basepath + "_label"); len(raw) != 0 { // Format the label from "Core 0" to "core_0" label = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), " "), "_") } // Get the name of the temperature you are reading - if raw, err = ioutil.ReadFile(filepath.Join(directory, "name")); err != nil { + if raw, err = os.ReadFile(filepath.Join(directory, "name")); err != nil { warns.Add(err) continue } @@ -479,7 +479,7 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err } // Get the temperature reading - if raw, err = ioutil.ReadFile(file); err != nil { + if raw, err = os.ReadFile(file); err != nil { warns.Add(err) continue } @@ -513,7 +513,7 @@ func optionalValueReadFromFile(filename string) float64 { return 0 } - if raw, err = ioutil.ReadFile(filename); err != nil { + if raw, err = os.ReadFile(filename); err != nil { return 0 } diff --git a/host/host_openbsd.go b/host/host_openbsd.go index 569de4abd..325015c23 100644 --- a/host/host_openbsd.go +++ b/host/host_openbsd.go @@ -7,7 +7,7 @@ import ( "bytes" "context" "encoding/binary" - "io/ioutil" + "io" "os" "strings" "unsafe" @@ -65,7 +65,7 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) { } defer file.Close() - buf, err := ioutil.ReadAll(file) + buf, err := io.ReadAll(file) if err != nil { return ret, err } diff --git a/host/host_solaris.go b/host/host_solaris.go index 7d3625acb..fef67f835 100644 --- a/host/host_solaris.go +++ b/host/host_solaris.go @@ -7,7 +7,6 @@ import ( "encoding/csv" "fmt" "io" - "io/ioutil" "os" "regexp" "strconv" @@ -60,7 +59,7 @@ func HostIDWithContext(ctx context.Context) (string, error) { // Count number of processes based on the number of entries in /proc func numProcs(ctx context.Context) (uint64, error) { - dirs, err := ioutil.ReadDir("/proc") + dirs, err := os.ReadDir("/proc") if err != nil { return 0, err } @@ -138,7 +137,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { // Find distribution name from /etc/release func parseReleaseFile() (string, error) { - b, err := ioutil.ReadFile("/etc/release") + b, err := os.ReadFile("/etc/release") if err != nil { return "", err } diff --git a/host/host_test.go b/host/host_test.go index 29cb9d2db..17ced6dac 100644 --- a/host/host_test.go +++ b/host/host_test.go @@ -33,7 +33,7 @@ func TestHostInfo(t *testing.T) { } func TestUptime(t *testing.T) { - if os.Getenv("CIRCLECI") == "true" { + if os.Getenv("CI") == "true" { t.Skip("Skip CI") } @@ -48,7 +48,7 @@ func TestUptime(t *testing.T) { } func TestBoot_time(t *testing.T) { - if os.Getenv("CIRCLECI") == "true" { + if os.Getenv("CI") == "true" { t.Skip("Skip CI") } v, err := BootTime() diff --git a/internal/common/common.go b/internal/common/common.go index 9bfece362..99ed6a58e 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -14,7 +14,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/url" "os" "os/exec" @@ -87,7 +86,7 @@ func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) { fpath += "_" + i.Suffix } if PathExists(fpath) { - return ioutil.ReadFile(fpath) + return os.ReadFile(fpath) } return []byte{}, fmt.Errorf("could not find testdata: %s", fpath) } @@ -100,7 +99,7 @@ var ErrNotImplementedError = errors.New("not implemented yet") // ReadFile reads contents from a file func ReadFile(filename string) (string, error) { - content, err := ioutil.ReadFile(filename) + content, err := os.ReadFile(filename) if err != nil { return "", err } @@ -114,6 +113,30 @@ func ReadLines(filename string) ([]string, error) { return ReadLinesOffsetN(filename, 0, -1) } +// ReadLine reads a file and returns the first occurrence of a line that is prefixed with prefix. +func ReadLine(filename string, prefix string) (string, error) { + f, err := os.Open(filename) + if err != nil { + return "", err + } + defer f.Close() + r := bufio.NewReader(f) + for { + line, err := r.ReadString('\n') + if err != nil { + if err == io.EOF { + break + } + return "", err + } + if strings.HasPrefix(line, prefix) { + return line, nil + } + } + + return "", nil +} + // ReadLinesOffsetN reads contents from file and splits them by new line. // The offset tells at which line number to start. // The count determines the number of lines to read (starting from offset): diff --git a/internal/common/common_linux.go b/internal/common/common_linux.go index b58edbeb0..a644687ba 100644 --- a/internal/common/common_linux.go +++ b/internal/common/common_linux.go @@ -62,17 +62,38 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) { return 0, err } - statFile := "stat" + useStatFile := true if system == "lxc" && role == "guest" { // if lxc, /proc/uptime is used. - statFile = "uptime" + useStatFile = false } else if system == "docker" && role == "guest" { // also docker, guest - statFile = "uptime" + useStatFile = false } - filename := HostProcWithContext(ctx, statFile) + if useStatFile { + return readBootTimeStat(ctx) + } + + filename := HostProcWithContext(ctx, "uptime") lines, err := ReadLines(filename) + if err != nil { + return handleBootTimeFileReadErr(err) + } + if len(lines) != 1 { + return 0, fmt.Errorf("wrong uptime format") + } + f := strings.Fields(lines[0]) + b, err := strconv.ParseFloat(f[0], 64) + if err != nil { + return 0, err + } + currentTime := float64(time.Now().UnixNano()) / float64(time.Second) + t := currentTime - b + return uint64(t), nil +} + +func handleBootTimeFileReadErr(err error) (uint64, error) { if os.IsPermission(err) { var info syscall.Sysinfo_t err := syscall.Sysinfo(&info) @@ -84,39 +105,27 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) { t := currentTime - int64(info.Uptime) return uint64(t), nil } + return 0, err +} + +func readBootTimeStat(ctx context.Context) (uint64, error) { + filename := HostProcWithContext(ctx, "stat") + line, err := ReadLine(filename, "btime") if err != nil { - return 0, err + return handleBootTimeFileReadErr(err) } - - if statFile == "stat" { - for _, line := range lines { - if strings.HasPrefix(line, "btime") { - f := strings.Fields(line) - if len(f) != 2 { - return 0, fmt.Errorf("wrong btime format") - } - b, err := strconv.ParseInt(f[1], 10, 64) - if err != nil { - return 0, err - } - t := uint64(b) - return t, nil - } - } - } else if statFile == "uptime" { - if len(lines) != 1 { - return 0, fmt.Errorf("wrong uptime format") + if strings.HasPrefix(line, "btime") { + f := strings.Fields(line) + if len(f) != 2 { + return 0, fmt.Errorf("wrong btime format") } - f := strings.Fields(lines[0]) - b, err := strconv.ParseFloat(f[0], 64) + b, err := strconv.ParseInt(f[1], 10, 64) if err != nil { return 0, err } - currentTime := float64(time.Now().UnixNano()) / float64(time.Second) - t := currentTime - b - return uint64(t), nil + t := uint64(b) + return t, nil } - return 0, fmt.Errorf("could not find btime") } diff --git a/load/load_linux.go b/load/load_linux.go index 0298c8bed..06bceeb84 100644 --- a/load/load_linux.go +++ b/load/load_linux.go @@ -5,7 +5,7 @@ package load import ( "context" - "io/ioutil" + "os" "strconv" "strings" "syscall" @@ -76,7 +76,7 @@ func Misc() (*MiscStat, error) { func MiscWithContext(ctx context.Context) (*MiscStat, error) { filename := common.HostProcWithContext(ctx, "stat") - out, err := ioutil.ReadFile(filename) + out, err := os.ReadFile(filename) if err != nil { return nil, err } @@ -126,7 +126,7 @@ func getProcsTotal(ctx context.Context) (int64, error) { func readLoadAvgFromFile(ctx context.Context) ([]string, error) { loadavgFilename := common.HostProcWithContext(ctx, "loadavg") - line, err := ioutil.ReadFile(loadavgFilename) + line, err := os.ReadFile(loadavgFilename) if err != nil { return nil, err } diff --git a/load/load_windows.go b/load/load_windows.go index b48483849..8f53efae3 100644 --- a/load/load_windows.go +++ b/load/load_windows.go @@ -45,8 +45,8 @@ func loadAvgGoroutine(ctx context.Context) { f := func() { currentLoad, err = counter.GetValue() - loadErr = err loadAvgMutex.Lock() + loadErr = err loadAvg1M = loadAvg1M*loadAvgFactor1M + currentLoad*(1-loadAvgFactor1M) loadAvg5M = loadAvg5M*loadAvgFactor5M + currentLoad*(1-loadAvgFactor5M) loadAvg15M = loadAvg15M*loadAvgFactor15M + currentLoad*(1-loadAvgFactor15M) diff --git a/mem/mem.go b/mem/mem.go index ff960dacc..edaf268bb 100644 --- a/mem/mem.go +++ b/mem/mem.go @@ -50,6 +50,7 @@ type VirtualMemoryStat struct { // https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html // https://www.kernel.org/doc/Documentation/filesystems/proc.txt // https://www.kernel.org/doc/Documentation/vm/overcommit-accounting + // https://www.kernel.org/doc/Documentation/vm/transhuge.txt Buffers uint64 `json:"buffers"` Cached uint64 `json:"cached"` WriteBack uint64 `json:"writeBack"` @@ -78,6 +79,7 @@ type VirtualMemoryStat struct { HugePagesRsvd uint64 `json:"hugePagesRsvd"` HugePagesSurp uint64 `json:"hugePagesSurp"` HugePageSize uint64 `json:"hugePageSize"` + AnonHugePages uint64 `json:"anonHugePages"` } type SwapMemoryStat struct { diff --git a/mem/mem_linux.go b/mem/mem_linux.go index 935331728..214a91e47 100644 --- a/mem/mem_linux.go +++ b/mem/mem_linux.go @@ -311,6 +311,12 @@ func fillFromMeminfoWithContext(ctx context.Context) (*VirtualMemoryStat, *Virtu return ret, retEx, err } ret.HugePageSize = t * 1024 + case "AnonHugePages": + t, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return ret, retEx, err + } + ret.AnonHugePages = t * 1024 } } diff --git a/mem/mem_linux_test.go b/mem/mem_linux_test.go index d830fbf9c..6b6fb782a 100644 --- a/mem/mem_linux_test.go +++ b/mem/mem_linux_test.go @@ -108,6 +108,16 @@ var virtualMemoryTests = []struct { HugePageSize: 0, }, }, + { + "anonhugepages", &VirtualMemoryStat{ + Total: 260799420 * 1024, + Available: 127880216 * 1024, + Free: 119443248 * 1024, + AnonHugePages: 50409472 * 1024, + Used: 144748720128, + UsedPercent: 54.20110673559013, + }, + }, } func TestVirtualMemoryLinux(t *testing.T) { diff --git a/mem/mem_test.go b/mem/mem_test.go index 3be56562f..79ddb0fc6 100644 --- a/mem/mem_test.go +++ b/mem/mem_test.go @@ -89,7 +89,7 @@ func TestVirtualMemoryStat_String(t *testing.T) { Free: 40, } t.Log(v) - e := `{"total":10,"available":20,"used":30,"usedPercent":30.1,"free":40,"active":0,"inactive":0,"wired":0,"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,"hugePagesRsvd":0,"hugePagesSurp":0,"hugePageSize":0}` + e := `{"total":10,"available":20,"used":30,"usedPercent":30.1,"free":40,"active":0,"inactive":0,"wired":0,"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,"hugePagesRsvd":0,"hugePagesSurp":0,"hugePageSize":0,"anonHugePages":0}` if e != fmt.Sprintf("%v", v) { t.Errorf("VirtualMemoryStat string is invalid: %v", v) } diff --git a/mem/testdata/linux/virtualmemory/anonhugepages/proc/meminfo b/mem/testdata/linux/virtualmemory/anonhugepages/proc/meminfo new file mode 100644 index 000000000..d158c677b --- /dev/null +++ b/mem/testdata/linux/virtualmemory/anonhugepages/proc/meminfo @@ -0,0 +1,4 @@ +MemTotal: 260799420 kB +MemFree: 119443248 kB +MemAvailable: 127880216 kB +AnonHugePages: 50409472 kB \ No newline at end of file diff --git a/net/net_linux.go b/net/net_linux.go index de0ea7345..6e8ce67fb 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "os" "strconv" @@ -643,7 +642,7 @@ func (p *process) getUids(ctx context.Context) ([]int32, error) { func (p *process) fillFromStatus(ctx context.Context) error { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") - contents, err := ioutil.ReadFile(statPath) + contents, err := os.ReadFile(statPath) if err != nil { return err } @@ -784,7 +783,7 @@ func processInetWithContext(ctx context.Context, file string, kind netConnection // This minimizes duplicates in the returned connections // For more info: // https://github.com/shirou/gopsutil/pull/361 - contents, err := ioutil.ReadFile(file) + contents, err := os.ReadFile(file) if err != nil { return nil, err } @@ -845,7 +844,7 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in // This minimizes duplicates in the returned connections // For more info: // https://github.com/shirou/gopsutil/pull/361 - contents, err := ioutil.ReadFile(file) + contents, err := os.ReadFile(file) if err != nil { return nil, err } diff --git a/net/net_linux_test.go b/net/net_linux_test.go index f1b7fbaa7..eae0e71b9 100644 --- a/net/net_linux_test.go +++ b/net/net_linux_test.go @@ -3,7 +3,6 @@ package net import ( "context" "fmt" - "io/ioutil" "net" "os" "strings" @@ -17,7 +16,7 @@ import ( func TestIOCountersByFileParsing(t *testing.T) { // Prpare a temporary file, which will be read during the test - tmpfile, err := ioutil.TempFile("", "proc_dev_net") + tmpfile, err := os.CreateTemp("", "proc_dev_net") defer os.Remove(tmpfile.Name()) // clean up assert.Nil(t, err, "Temporary file creation failed: ", err) @@ -195,7 +194,7 @@ func TestReverse(t *testing.T) { } func TestConntrackStatFileParsing(t *testing.T) { - tmpfile, err := ioutil.TempFile("", "proc_net_stat_conntrack") + tmpfile, err := os.CreateTemp("", "proc_net_stat_conntrack") defer os.Remove(tmpfile.Name()) assert.Nil(t, err, "Temporary file creation failed: ", err) diff --git a/process/process_linux.go b/process/process_linux.go index 37cb7ca44..f7989cd21 100644 --- a/process/process_linux.go +++ b/process/process_linux.go @@ -9,7 +9,6 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" "math" "os" "path/filepath" @@ -136,7 +135,7 @@ func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "stat") - contents, err := ioutil.ReadFile(statPath) + contents, err := os.ReadFile(statPath) if err != nil { return false, err } @@ -391,7 +390,7 @@ func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]M smapsPath = smapsRollupPath } } - contents, err := ioutil.ReadFile(smapsPath) + contents, err := os.ReadFile(smapsPath) if err != nil { return nil, err } @@ -484,7 +483,7 @@ func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]M func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) { environPath := common.HostProcWithContext(ctx, strconv.Itoa(int(p.Pid)), "environ") - environContent, err := ioutil.ReadFile(environPath) + environContent, err := os.ReadFile(environPath) if err != nil { return nil, err } @@ -668,7 +667,7 @@ func (p *Process) fillFromExeWithContext(ctx context.Context) (string, error) { func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") - cmdline, err := ioutil.ReadFile(cmdPath) + cmdline, err := os.ReadFile(cmdPath) if err != nil { return "", err } @@ -682,7 +681,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") - cmdline, err := ioutil.ReadFile(cmdPath) + cmdline, err := os.ReadFile(cmdPath) if err != nil { return nil, err } @@ -705,7 +704,7 @@ func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, error) { pid := p.Pid ioPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "io") - ioline, err := ioutil.ReadFile(ioPath) + ioline, err := os.ReadFile(ioPath) if err != nil { return nil, err } @@ -741,7 +740,7 @@ func (p *Process) fillFromIOWithContext(ctx context.Context) (*IOCountersStat, e func (p *Process) fillFromStatmWithContext(ctx context.Context) (*MemoryInfoStat, *MemoryInfoExStat, error) { pid := p.Pid memPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "statm") - contents, err := ioutil.ReadFile(memPath) + contents, err := os.ReadFile(memPath) if err != nil { return nil, nil, err } @@ -802,7 +801,7 @@ func (p *Process) fillNameWithContext(ctx context.Context) error { func (p *Process) fillFromCommWithContext(ctx context.Context) error { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "comm") - contents, err := ioutil.ReadFile(statPath) + contents, err := os.ReadFile(statPath) if err != nil { return err } @@ -819,7 +818,7 @@ func (p *Process) fillFromStatus() error { func (p *Process) fillFromStatusWithContext(ctx context.Context) error { pid := p.Pid statPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "status") - contents, err := ioutil.ReadFile(statPath) + contents, err := os.ReadFile(statPath) if err != nil { return err } @@ -1026,7 +1025,7 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui statPath = common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "task", strconv.Itoa(int(tid)), "stat") } - contents, err := ioutil.ReadFile(statPath) + contents, err := os.ReadFile(statPath) if err != nil { return 0, 0, nil, 0, 0, 0, nil, err } diff --git a/process/process_linux_test.go b/process/process_linux_test.go index e8c2e8350..87df81231 100644 --- a/process/process_linux_test.go +++ b/process/process_linux_test.go @@ -6,7 +6,6 @@ package process import ( "context" "fmt" - "io/ioutil" "os" "strconv" "strings" @@ -58,7 +57,7 @@ func Test_Process_splitProcStat(t *testing.T) { } func Test_Process_splitProcStat_fromFile(t *testing.T) { - pids, err := ioutil.ReadDir("testdata/linux/") + pids, err := os.ReadDir("testdata/linux/") if err != nil { t.Error(err) } @@ -72,7 +71,7 @@ func Test_Process_splitProcStat_fromFile(t *testing.T) { if _, err := os.Stat(statFile); err != nil { continue } - contents, err := ioutil.ReadFile(statFile) + contents, err := os.ReadFile(statFile) assert.NoError(t, err) pidStr := strconv.Itoa(int(pid)) @@ -94,7 +93,7 @@ func Test_Process_splitProcStat_fromFile(t *testing.T) { } func Test_fillFromCommWithContext(t *testing.T) { - pids, err := ioutil.ReadDir("testdata/linux/") + pids, err := os.ReadDir("testdata/linux/") if err != nil { t.Error(err) } @@ -115,7 +114,7 @@ func Test_fillFromCommWithContext(t *testing.T) { } func Test_fillFromStatusWithContext(t *testing.T) { - pids, err := ioutil.ReadDir("testdata/linux/") + pids, err := os.ReadDir("testdata/linux/") if err != nil { t.Error(err) } @@ -154,7 +153,7 @@ func Benchmark_fillFromStatusWithContext(b *testing.B) { } func Test_fillFromTIDStatWithContext_lx_brandz(t *testing.T) { - pids, err := ioutil.ReadDir("testdata/lx_brandz/") + pids, err := os.ReadDir("testdata/lx_brandz/") if err != nil { t.Error(err) } diff --git a/process/process_solaris.go b/process/process_solaris.go index ad1c3cfc1..dd4bd4760 100644 --- a/process/process_solaris.go +++ b/process/process_solaris.go @@ -3,7 +3,6 @@ package process import ( "bytes" "context" - "io/ioutil" "os" "strconv" "strings" @@ -232,7 +231,7 @@ func (p *Process) fillFromPathAOutWithContext(ctx context.Context) (string, erro func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, error) { pid := p.Pid execNamePath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "execname") - exe, err := ioutil.ReadFile(execNamePath) + exe, err := os.ReadFile(execNamePath) if err != nil { return "", err } @@ -242,7 +241,7 @@ func (p *Process) fillFromExecnameWithContext(ctx context.Context) (string, erro func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") - cmdline, err := ioutil.ReadFile(cmdPath) + cmdline, err := os.ReadFile(cmdPath) if err != nil { return "", err } @@ -259,7 +258,7 @@ func (p *Process) fillFromCmdlineWithContext(ctx context.Context) (string, error func (p *Process) fillSliceFromCmdlineWithContext(ctx context.Context) ([]string, error) { pid := p.Pid cmdPath := common.HostProcWithContext(ctx, strconv.Itoa(int(pid)), "cmdline") - cmdline, err := ioutil.ReadFile(cmdPath) + cmdline, err := os.ReadFile(cmdPath) if err != nil { return nil, err } diff --git a/process/process_test.go b/process/process_test.go index 9281c93c3..51f7d9cf6 100644 --- a/process/process_test.go +++ b/process/process_test.go @@ -4,7 +4,7 @@ import ( "bufio" "errors" "fmt" - "io/ioutil" + "io" "net" "os" "os/exec" @@ -19,6 +19,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/shirou/gopsutil/v3/internal/common" ) @@ -301,7 +302,7 @@ func Test_Process_Name(t *testing.T) { } func Test_Process_Long_Name_With_Spaces(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "") + tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } @@ -347,7 +348,7 @@ func Test_Process_Long_Name_With_Spaces(t *testing.T) { } func Test_Process_Long_Name(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "") + tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } @@ -404,7 +405,7 @@ func Test_Process_Name_Against_Python(t *testing.T) { t.Skipf("psutil not found for %s: %s", py3Path, out) } - tmpdir, err := ioutil.TempDir("", "") + tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } @@ -501,7 +502,7 @@ func Test_Process_CpuPercentLoop(t *testing.T) { } func Test_Process_CreateTime(t *testing.T) { - if os.Getenv("CIRCLECI") == "true" { + if os.Getenv("CI") == "true" { t.Skip("Skip CI") } @@ -570,7 +571,7 @@ func Test_Connections(t *testing.T) { defer conn.Close() serverEstablished <- struct{}{} - _, err = ioutil.ReadAll(conn) + _, err = io.ReadAll(conn) if err != nil { panic(err) } @@ -773,7 +774,7 @@ func Test_IsRunning(t *testing.T) { } func Test_Process_Environ(t *testing.T) { - tmpdir, err := ioutil.TempDir("", "") + tmpdir, err := os.MkdirTemp("", "") if err != nil { t.Fatalf("unable to create temp dir %v", err) } @@ -862,3 +863,11 @@ func BenchmarkProcessPpid(b *testing.B) { p.Ppid() } } + +func BenchmarkProcesses(b *testing.B) { + for i := 0; i < b.N; i++ { + ps, err := Processes() + require.NoError(b, err) + require.Greater(b, len(ps), 0) + } +}