Skip to content

Commit 726153f

Browse files
committed
Add /proc/modules parsing
Signed-off-by: Furkan <[email protected]>
1 parent b3d77ec commit 726153f

File tree

3 files changed

+295
-0
lines changed

3 files changed

+295
-0
lines changed

proc_modules.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright 2018 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package procfs
15+
16+
import (
17+
"bufio"
18+
"bytes"
19+
"io"
20+
"strconv"
21+
"strings"
22+
23+
"github.com/prometheus/procfs/internal/util"
24+
)
25+
26+
// Module represents a single module info in the kernel.
27+
type Module struct {
28+
// Name is the name of the module.
29+
Name string
30+
// Size is the memory size of the module, in bytes
31+
Size uint64
32+
// Instances is the number of instances of the module are currently loaded.
33+
// A value of zero represents an unloaded module.
34+
Instances uint64
35+
// Dependencies is the list of modules that this module depends on.
36+
Dependencies []string
37+
// State is the state of the module is in: Live, Loading, or Unloading are the only possible values.
38+
State string
39+
// Offset is a memory offset for the loaded module
40+
Offset uint64
41+
// Taints is a list of taints that the module has.
42+
Taints []string
43+
}
44+
45+
// Modules represents a list of Module structs.
46+
type Modules []Module
47+
48+
// Modules parses the metrics from /proc/modules file and returns a slice of
49+
// structs containing the relevant info.
50+
func (fs FS) Modules() ([]Module, error) {
51+
data, err := util.ReadFileNoStat(fs.proc.Path("modules"))
52+
if err != nil {
53+
return nil, err
54+
}
55+
return parseModules(bytes.NewReader(data))
56+
}
57+
58+
// parseModules parses the metrics from /proc/modules file
59+
// and returns a []Module structure.
60+
// - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/4/html/reference_guide/s2-proc-modules
61+
// - https://unix.stackexchange.com/a/152527/300614
62+
func parseModules(r io.Reader) ([]Module, error) {
63+
var (
64+
scanner = bufio.NewScanner(r)
65+
modules = make([]Module, 0)
66+
)
67+
68+
for scanner.Scan() {
69+
parts := strings.Fields(scanner.Text())
70+
71+
module := Module{
72+
Name: parts[0],
73+
Dependencies: []string{},
74+
State: parts[4],
75+
Taints: []string{},
76+
}
77+
78+
if size, err := strconv.ParseUint(parts[1], 10, 64); err == nil {
79+
module.Size = size
80+
}
81+
82+
if instances, err := strconv.ParseUint(parts[2], 10, 64); err == nil {
83+
module.Instances = instances
84+
}
85+
86+
dependencies := parts[3]
87+
if dependencies != "-" {
88+
module.Dependencies = strings.Split(strings.TrimSuffix(dependencies, ","), ",")
89+
}
90+
91+
if offset, err := strconv.ParseUint(parts[5], 10, 64); err == nil {
92+
module.Offset = offset
93+
}
94+
95+
// Kernel Taint State is available if parts length is greater than 6.
96+
if len(parts) > 6 {
97+
taints := strings.TrimSuffix(strings.TrimPrefix(parts[6], "("), ")")
98+
module.Taints = strings.Split(taints, "")
99+
}
100+
101+
modules = append(modules, module)
102+
}
103+
104+
return modules, scanner.Err()
105+
}

proc_modules_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright 2020 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package procfs
15+
16+
import (
17+
"reflect"
18+
"testing"
19+
)
20+
21+
func TestProcInterrupts(t *testing.T) {
22+
fs := getProcFixtures(t)
23+
24+
modules, err := fs.Modules()
25+
if err != nil {
26+
t.Fatal(err)
27+
}
28+
29+
if want, have := 89, len(modules); want != have {
30+
t.Errorf("want length %d, have %d", want, have)
31+
}
32+
33+
for _, test := range []struct {
34+
name string
35+
index int
36+
want Module
37+
}{
38+
{
39+
name: "no dependencies and taints",
40+
index: 0,
41+
want: Module{
42+
Name: "nft_counter",
43+
Size: 16384,
44+
Instances: 4,
45+
Dependencies: []string{},
46+
State: "Live",
47+
Offset: 0,
48+
Taints: []string{},
49+
},
50+
},
51+
{
52+
name: "have dependencies with no taints",
53+
index: 11,
54+
want: Module{
55+
Name: "nf_tables",
56+
Size: 245760,
57+
Instances: 19,
58+
Dependencies: []string{"nft_counter", "nft_chain_nat", "nft_compat"},
59+
State: "Live",
60+
Offset: 0,
61+
Taints: []string{},
62+
},
63+
},
64+
{
65+
name: "have multiple taints with multiple dependencies",
66+
index: 83,
67+
want: Module{
68+
Name: "drm",
69+
Size: 622592,
70+
Instances: 3,
71+
Dependencies: []string{"virtio_gpu", "drm_kms_helper"},
72+
State: "Live",
73+
Offset: 0,
74+
Taints: []string{"P", "O", "E"},
75+
},
76+
},
77+
{
78+
name: "have single taint with single dependency",
79+
index: 88,
80+
want: Module{
81+
Name: "failover",
82+
Size: 16384,
83+
Instances: 1,
84+
Dependencies: []string{"net_failover"},
85+
State: "Live",
86+
Offset: 0,
87+
Taints: []string{"P"},
88+
},
89+
},
90+
} {
91+
t.Run(test.name, func(t *testing.T) {
92+
if want, have := test.want, modules[test.index]; !reflect.DeepEqual(want, have) {
93+
t.Errorf("want %v, have %v", want, have)
94+
}
95+
})
96+
}
97+
}

testdata/fixtures.ttar

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3157,6 +3157,99 @@ Lines: 1
31573157
0
31583158
Mode: 644
31593159
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3160+
Path: fixtures/proc/modules
3161+
Lines: 89
3162+
nft_counter 16384 4 - Live 0xffffffffc0c77000
3163+
nft_chain_nat 16384 2 - Live 0xffffffffc0c72000
3164+
nft_compat 20480 8 - Live 0xffffffffc0c6c000
3165+
xt_tcpudp 20480 4 - Live 0xffffffffc0c66000
3166+
xt_nat 16384 4 - Live 0xffffffffc0c61000
3167+
xt_multiport 20480 0 - Live 0xffffffffc0c5b000
3168+
xt_mark 16384 0 - Live 0xffffffffc0c56000
3169+
xt_conntrack 16384 0 - Live 0xffffffffc0c42000
3170+
xt_comment 16384 0 - Live 0xffffffffc0c3d000
3171+
xt_addrtype 16384 0 - Live 0xffffffffc0c51000
3172+
xt_MASQUERADE 20480 0 - Live 0xffffffffc0c4b000
3173+
nf_tables 245760 19 nft_counter,nft_chain_nat,nft_compat, Live 0xffffffffc0c00000
3174+
nfnetlink 20480 2 nft_compat,nf_tables, Live 0xffffffffc0bfa000
3175+
ip6table_filter 16384 0 - Live 0xffffffffc0b8b000
3176+
iptable_filter 16384 0 - Live 0xffffffffc0bde000
3177+
ip6table_nat 16384 0 - Live 0xffffffffc0bd9000
3178+
iptable_nat 16384 0 - Live 0xffffffffc0bf5000
3179+
nf_nat 49152 5 nft_chain_nat,xt_nat,xt_MASQUERADE,ip6table_nat,iptable_nat, Live 0xffffffffc0be8000
3180+
nf_conntrack 172032 4 xt_nat,xt_conntrack,xt_MASQUERADE,nf_nat, Live 0xffffffffc0bae000
3181+
nf_defrag_ipv6 24576 1 nf_conntrack, Live 0xffffffffc0ba3000
3182+
nf_defrag_ipv4 16384 1 nf_conntrack, Live 0xffffffffc0b9e000
3183+
ip6_tables 32768 2 ip6table_filter,ip6table_nat, Live 0xffffffffc0b82000
3184+
veth 32768 0 - Live 0xffffffffc0b95000
3185+
bridge 307200 0 - Live 0xffffffffc0b36000
3186+
stp 16384 1 bridge, Live 0xffffffffc0b2f000
3187+
llc 16384 2 bridge,stp, Live 0xffffffffc0b26000
3188+
tap 28672 0 - Live 0xffffffffc0b1b000
3189+
binfmt_misc 24576 1 - Live 0xffffffffc0ad6000
3190+
overlay 151552 0 - Live 0xffffffffc0ab0000
3191+
isofs 53248 1 - Live 0xffffffffc09d0000
3192+
nls_iso8859_1 16384 1 - Live 0xffffffffc097f000
3193+
input_leds 16384 0 - Live 0xffffffffc099d000
3194+
serio_raw 20480 0 - Live 0xffffffffc098b000
3195+
virtio_input 20480 0 - Live 0xffffffffc0979000
3196+
dm_multipath 40960 0 - Live 0xffffffffc093f000
3197+
sch_fq_codel 20480 3 - Live 0xffffffffc0939000
3198+
scsi_dh_rdac 20480 0 - Live 0xffffffffc0930000
3199+
scsi_dh_emc 16384 0 - Live 0xffffffffc0928000
3200+
scsi_dh_alua 20480 0 - Live 0xffffffffc0917000
3201+
ipmi_devintf 20480 0 - Live 0xffffffffc091e000
3202+
ipmi_msghandler 122880 1 ipmi_devintf, Live 0xffffffffc08f8000
3203+
msr 16384 0 - Live 0xffffffffc08f0000
3204+
efi_pstore 16384 0 - Live 0xffffffffc08eb000
3205+
virtio_rng 16384 0 - Live 0xffffffffc0581000
3206+
ip_tables 32768 2 iptable_filter,iptable_nat, Live 0xffffffffc0743000
3207+
x_tables 53248 15 nft_compat,xt_tcpudp,xt_nat,xt_multiport,xt_mark,xt_conntrack,xt_comment,xt_addrtype,xt_MASQUERADE,ip6table_filter,iptable_filter,ip6table_nat,iptable_nat,ip6_tables,ip_tables, Live 0xffffffffc0735000
3208+
autofs4 49152 2 - Live 0xffffffffc0728000
3209+
btrfs 1552384 0 - Live 0xffffffffc0761000
3210+
blake2b_generic 20480 0 - Live 0xffffffffc06d3000
3211+
zstd_compress 229376 1 btrfs, Live 0xffffffffc06ef000
3212+
raid10 69632 0 - Live 0xffffffffc06dd000
3213+
raid456 163840 0 - Live 0xffffffffc06aa000
3214+
async_raid6_recov 24576 1 raid456, Live 0xffffffffc06a3000
3215+
async_memcpy 20480 2 raid456,async_raid6_recov, Live 0xffffffffc069d000
3216+
async_pq 24576 2 raid456,async_raid6_recov, Live 0xffffffffc0696000
3217+
async_xor 20480 3 raid456,async_raid6_recov,async_pq, Live 0xffffffffc0690000
3218+
async_tx 20480 5 raid456,async_raid6_recov,async_memcpy,async_pq,async_xor, Live 0xffffffffc068a000
3219+
xor 24576 2 btrfs,async_xor, Live 0xffffffffc0593000
3220+
raid6_pq 122880 4 btrfs,raid456,async_raid6_recov,async_pq, Live 0xffffffffc066b000
3221+
libcrc32c 16384 5 nf_tables,nf_nat,nf_conntrack,btrfs,raid456, Live 0xffffffffc0556000
3222+
raid1 49152 0 - Live 0xffffffffc0610000
3223+
raid0 24576 0 - Live 0xffffffffc0517000
3224+
multipath 20480 0 - Live 0xffffffffc0501000
3225+
linear 20480 0 - Live 0xffffffffc045b000
3226+
virtio_gpu 69632 0 - Live 0xffffffffc05a0000
3227+
virtio_dma_buf 16384 1 virtio_gpu, Live 0xffffffffc0536000
3228+
crct10dif_pclmul 16384 1 - Live 0xffffffffc050e000
3229+
drm_kms_helper 311296 3 virtio_gpu, Live 0xffffffffc061e000
3230+
crc32_pclmul 16384 0 - Live 0xffffffffc0527000
3231+
syscopyarea 16384 1 drm_kms_helper, Live 0xffffffffc0520000
3232+
sysfillrect 20480 1 drm_kms_helper, Live 0xffffffffc0508000
3233+
ghash_clmulni_intel 16384 0 - Live 0xffffffffc0456000
3234+
sysimgblt 16384 1 drm_kms_helper, Live 0xffffffffc04fc000
3235+
fb_sys_fops 16384 1 drm_kms_helper, Live 0xffffffffc0425000
3236+
cec 61440 1 drm_kms_helper, Live 0xffffffffc0751000
3237+
rc_core 65536 1 cec, Live 0xffffffffc0540000
3238+
aesni_intel 376832 0 - Live 0xffffffffc05b3000
3239+
crypto_simd 16384 1 aesni_intel, Live 0xffffffffc059b000
3240+
ahci 45056 1 - Live 0xffffffffc0587000
3241+
virtio_net 61440 0 - Live 0xffffffffc0571000
3242+
xhci_pci 24576 0 - Live 0xffffffffc0562000
3243+
net_failover 20480 1 virtio_net, Live 0xffffffffc055c000
3244+
cryptd 24576 2 ghash_clmulni_intel,crypto_simd, Live 0xffffffffc052c000
3245+
drm 622592 3 virtio_gpu,drm_kms_helper, Live 0xffffffffc0463000 (POE)
3246+
psmouse 176128 0 - Live 0xffffffffc042a000
3247+
libahci 45056 1 ahci, Live 0xffffffffc0419000
3248+
virtio_blk 20480 2 - Live 0xffffffffc040f000
3249+
xhci_pci_renesas 20480 1 xhci_pci, Live 0xffffffffc0407000
3250+
failover 16384 1 net_failover, Live 0xffffffffc03ff000 (P)
3251+
Mode: 644
3252+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
31603253
Path: fixtures/proc/zoneinfo
31613254
Lines: 262
31623255
Node 0, zone DMA

0 commit comments

Comments
 (0)