Skip to content

Commit

Permalink
Merge branch 'master' into block-device-size
Browse files Browse the repository at this point in the history
Signed-off-by: Finn Snape <[email protected]>
  • Loading branch information
fs185143 authored Nov 26, 2024
2 parents 6c3ef0b + 9c0d20a commit 779abd2
Show file tree
Hide file tree
Showing 14 changed files with 204 additions and 30 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version: 2.1
jobs:
lint:
docker:
- image: cimg/go:1.22
- image: cimg/go:1.23
steps:
- checkout
- run: make check_license
Expand Down Expand Up @@ -46,16 +46,16 @@ workflows:
matrix:
parameters:
go_version:
- "1.20"
- "1.21"
- "1.22"
- "1.23"
- test:
name: test-windows
os: windows
run_test: false
matrix:
parameters:
go_version:
- "1.20"
- "1.21"
- "1.22"
- "1.23"
10 changes: 5 additions & 5 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Install Go
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
with:
go-version: 1.22.x
go-version: 1.23.x
- name: Install snmp_exporter/generator dependencies
run: sudo apt-get update && sudo apt-get -y install libsnmp-dev
if: github.repository == 'prometheus/snmp_exporter'
- name: Lint
uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1
uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0
with:
args: --verbose
version: v1.59.0
version: v1.60.2
5 changes: 5 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
linters:
enable:
- errcheck
- forbidigo
- godot
- gofmt
- goimports
Expand All @@ -15,6 +16,10 @@ linters:
- unused

linter-settings:
forbidigo:
forbid:
- p: ^fmt\.Print.*$
msg: Do not commit print statements.
godot:
capital: true
exclude:
Expand Down
8 changes: 7 additions & 1 deletion Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_
SKIP_GOLANGCI_LINT :=
GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?=
GOLANGCI_LINT_VERSION ?= v1.59.0
GOLANGCI_LINT_VERSION ?= v1.60.2
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
Expand Down Expand Up @@ -275,3 +275,9 @@ $(1)_precheck:
exit 1; \
fi
endef

govulncheck: install-govulncheck
govulncheck ./...

install-govulncheck:
command -v govulncheck > /dev/null || go install golang.org/x/vuln/cmd/govulncheck@latest
28 changes: 28 additions & 0 deletions blockdevice/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ type BlockQueueStats struct {
WriteZeroesMaxBytes uint64
}

type IODeviceStats struct {
IODoneCount uint64
IOErrCount uint64
}

// DeviceMapperInfo models the devicemapper files that are located in the sysfs tree for each block device
// and described in the kernel documentation:
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm
Expand Down Expand Up @@ -211,6 +216,7 @@ const (
sysBlockDM = "dm"
sysUnderlyingDev = "slaves"
sysBlockSize = "size"
sysDevicePath = "device"
)

// FS represents the pseudo-filesystems proc and sys, which provides an
Expand Down Expand Up @@ -486,3 +492,25 @@ func (fs FS) SysBlockDeviceSize(device string) (uint64, error) {
}
return procfs.SectorSize * size, nil
}

// SysBlockDeviceIO returns stats for the block device io counters
// IO done count: /sys/block/<disk>/device/iodone_cnt
// IO error count: /sys/block/<disk>/device/ioerr_cnt.
func (fs FS) SysBlockDeviceIOStat(device string) (IODeviceStats, error) {
var (
ioDeviceStats IODeviceStats
err error
)
for file, p := range map[string]*uint64{
"iodone_cnt": &ioDeviceStats.IODoneCount,
"ioerr_cnt": &ioDeviceStats.IOErrCount,
} {
var val uint64
val, err = util.ReadHexFromFile(fs.sys.Path(sysBlockPath, device, sysDevicePath, file))
if err != nil {
return IODeviceStats{}, err
}
*p = val
}
return ioDeviceStats, nil
}
103 changes: 103 additions & 0 deletions ext4/ext4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package btrfs provides access to statistics exposed by ext4 filesystems.
package ext4

import (
"path/filepath"
"strings"

"github.com/prometheus/procfs/internal/fs"
"github.com/prometheus/procfs/internal/util"
)

const (
sysFSPath = "fs"
sysFSExt4Path = "ext4"
)

// Stats contains statistics for a single Btrfs filesystem.
// See Linux fs/btrfs/sysfs.c for more information.
type Stats struct {
Name string

Errors uint64
Warnings uint64
Messages uint64
}

// FS represents the pseudo-filesystems proc and sys, which provides an
// interface to kernel data structures.
type FS struct {
proc *fs.FS
sys *fs.FS
}

// NewDefaultFS returns a new blockdevice fs using the default mountPoints for proc and sys.
// It will error if either of these mount points can't be read.
func NewDefaultFS() (FS, error) {
return NewFS(fs.DefaultProcMountPoint, fs.DefaultSysMountPoint)
}

// NewFS returns a new XFS handle using the given proc and sys mountPoints. It will error
// if either of the mounts point can't be read.
func NewFS(procMountPoint string, sysMountPoint string) (FS, error) {
if strings.TrimSpace(procMountPoint) == "" {
procMountPoint = fs.DefaultProcMountPoint
}
procfs, err := fs.NewFS(procMountPoint)
if err != nil {
return FS{}, err
}
if strings.TrimSpace(sysMountPoint) == "" {
sysMountPoint = fs.DefaultSysMountPoint
}
sysfs, err := fs.NewFS(sysMountPoint)
if err != nil {
return FS{}, err
}
return FS{&procfs, &sysfs}, nil
}

// ProcStat returns stats for the filesystem.
func (fs FS) ProcStat() ([]*Stats, error) {
matches, err := filepath.Glob(fs.sys.Path("fs/ext4/*"))
if err != nil {
return nil, err
}

stats := make([]*Stats, 0, len(matches))
for _, m := range matches {
s := &Stats{}

// "*" used in glob above indicates the name of the filesystem.
name := filepath.Base(m)
s.Name = name
for file, p := range map[string]*uint64{
"errors_count": &s.Errors,
"warning_count": &s.Warnings,
"msg_count": &s.Messages,
} {
var val uint64
val, err = util.ReadUintFromFile(fs.sys.Path(sysFSPath, sysFSExt4Path, name, file))
if err == nil {
*p = val
}
}

stats = append(stats, s)
}

return stats, nil
}
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module github.com/prometheus/procfs

go 1.20
go 1.21

require (
github.com/google/go-cmp v0.6.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.20.0
golang.org/x/sync v0.8.0
golang.org/x/sys v0.26.0
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
14 changes: 14 additions & 0 deletions internal/util/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package util

import (
"errors"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -110,3 +111,16 @@ func ParseBool(b string) *bool {
}
return &truth
}

// ReadHexFromFile reads a file and attempts to parse a uint64 from a hexadecimal format 0xXX.
func ReadHexFromFile(path string) (uint64, error) {
data, err := os.ReadFile(path)
if err != nil {
return 0, err
}
hexString := strings.TrimSpace(string(data))
if !strings.HasPrefix(hexString, "0x") {
return 0, errors.New("invalid format: hex string does not start with '0x'")
}
return strconv.ParseUint(hexString[2:], 16, 64)
}
2 changes: 1 addition & 1 deletion net_ip_socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type (
// UsedSockets shows the total number of parsed lines representing the
// number of used sockets.
UsedSockets uint64
// Drops shows the total number of dropped packets of all UPD sockets.
// Drops shows the total number of dropped packets of all UDP sockets.
Drops *uint64
}

Expand Down
2 changes: 0 additions & 2 deletions proc_smaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package procfs
import (
"bufio"
"errors"
"fmt"
"os"
"regexp"
"strconv"
Expand Down Expand Up @@ -117,7 +116,6 @@ func (p Proc) procSMapsRollupManual() (ProcSMapsRollup, error) {
func (s *ProcSMapsRollup) parseLine(line string) error {
kv := strings.SplitN(line, ":", 2)
if len(kv) != 2 {
fmt.Println(line)
return errors.New("invalid net/dev line, missing colon")
}

Expand Down
18 changes: 11 additions & 7 deletions proc_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ func (s *ProcStatus) fillStatus(k string, vString string, vUint uint64, vUintByt
}
}
case "NSpid":
s.NSpids = calcNSPidsList(vString)
nspids, err := calcNSPidsList(vString)
if err != nil {
return err
}
s.NSpids = nspids
case "VmPeak":
s.VmPeak = vUintBytes
case "VmSize":
Expand Down Expand Up @@ -222,17 +226,17 @@ func calcCpusAllowedList(cpuString string) []uint64 {
return g
}

func calcNSPidsList(nspidsString string) []uint64 {
s := strings.Split(nspidsString, " ")
func calcNSPidsList(nspidsString string) ([]uint64, error) {
s := strings.Split(nspidsString, "\t")
var nspids []uint64

for _, nspid := range s {
nspid, _ := strconv.ParseUint(nspid, 10, 64)
if nspid == 0 {
continue
nspid, err := strconv.ParseUint(nspid, 10, 64)
if err != nil {
return nil, err
}
nspids = append(nspids, nspid)
}

return nspids
return nspids, nil
}
16 changes: 16 additions & 0 deletions proc_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,19 @@ func TestCpusAllowedList(t *testing.T) {
t.Errorf("want CpusAllowedList %v, have %v", want, have)
}
}

func TestNsPids(t *testing.T) {
p, err := getProcFixtures(t).Proc(26235)
if err != nil {
t.Fatal(err)
}

s, err := p.NewStatus()
if err != nil {
t.Fatal(err)
}

if want, have := []uint64{26235, 1}, s.NSpids; !reflect.DeepEqual(want, have) {
t.Errorf("want NsPids %v, have %v", want, have)
}
}
8 changes: 4 additions & 4 deletions testdata/fixtures.ttar
Original file line number Diff line number Diff line change
Expand Up @@ -818,10 +818,10 @@ Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 64
Groups:
NStgid: 26235 1
NSpid: 26235 1
NSpgid: 26235 1
NSsid: 26235 1
NStgid: 26235 1
NSpid: 26235 1
NSpgid: 26235 1
NSsid: 26235 1
VmPeak: 758200 kB
VmSize: 758200 kB
VmLck: 0 kB
Expand Down

0 comments on commit 779abd2

Please sign in to comment.