Skip to content

Commit

Permalink
Introduce parsing for /proc/<pid>/net/snmp.
Browse files Browse the repository at this point in the history
Signed-off-by: Nikos Kakavas <nikakis@protonmail.com>
  • Loading branch information
nikakis committed Feb 14, 2022
1 parent 71acf3d commit a8481ba
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1 +1,2 @@
/fixtures/
.idea
16 changes: 16 additions & 0 deletions fixtures.ttar
Expand Up @@ -156,6 +156,22 @@ Inter-| Receive | Transmit
eth0: 438 5 0 0 0 0 0 0 648 8 0 0 0 0 0 0
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/proc/26231/net/snmp
Lines: 12
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
Ip: 2 64 594223 0 1 0 0 0 593186 547253 20 231 0 0 0 0 0 0 0
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 45 1 0 45 0 0 0 0 0 0 0 0 0 0 50 0 50 0 0 0 0 0 0 0 0 0 0
IcmpMsg: InType3 OutType3
IcmpMsg: 45 50
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
Tcp: 1 200 120000 -1 1103 9 8 51 15 653161 594855 348 98 1038 0
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
Udp: 10179 50 0 9846 0 0 0 58
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti
UdpLite: 0 0 0 0 0 0 0 0
Mode: 644
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/proc/26231/ns
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -4,6 +4,7 @@ go 1.13

require (
github.com/google/go-cmp v0.5.4
github.com/mitchellh/mapstructure v1.4.3
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
)
2 changes: 2 additions & 0 deletions go.sum
@@ -1,5 +1,7 @@
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
Expand Down
187 changes: 187 additions & 0 deletions proc_snmp.go
@@ -0,0 +1,187 @@
// Copyright 2022 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 procfs

import (
"bufio"
"fmt"
"github.com/mitchellh/mapstructure"
"io"
"os"
"strconv"
"strings"
)

// ProcSnmp models the content of /proc/<pid>/net/snmp.
type ProcSnmp struct {
// The process ID.
PID int
Ip
Icmp
IcmpMsg
Tcp
Udp
UdpLite
}

type Ip struct {
Forwarding float64
DefaultTTL float64
InReceives float64
InHdrErrors float64
InAddrErrors float64
ForwDatagrams float64
InUnknownProtos float64
InDiscards float64
InDelivers float64
OutRequests float64
OutDiscards float64
OutNoRoutes float64
ReasmTimeout float64
ReasmReqds float64
ReasmOKs float64
ReasmFails float64
FragOKs float64
FragFails float64
FragCreates float64
}

type Icmp struct {
InMsgs float64
InErrors float64
InCsumErrors float64
InDestUnreachs float64
InTimeExcds float64
InParmProbs float64
InSrcQuenchs float64
InRedirects float64
InEchos float64
InEchoReps float64
InTimestamps float64
InTimestampReps float64
InAddrMasks float64
InAddrMaskReps float64
OutMsgs float64
OutErrors float64
OutDestUnreachs float64
OutTimeExcds float64
OutParmProbs float64
OutSrcQuenchs float64
OutRedirects float64
OutEchos float64
OutEchoReps float64
OutTimestamps float64
OutTimestampReps float64
OutAddrMasks float64
OutAddrMaskReps float64
}

type IcmpMsg struct {
InType3 float64
OutType3 float64
}

type Tcp struct {
RtoAlgorithm float64
RtoMin float64
RtoMax float64
MaxConn float64
ActiveOpens float64
PassiveOpens float64
AttemptFails float64
EstabResets float64
CurrEstab float64
InSegs float64
OutSegs float64
RetransSegs float64
InErrs float64
OutRsts float64
InCsumErrors float64
}

type Udp struct {
InDatagrams float64
NoPorts float64
InErrors float64
OutDatagrams float64
RcvbufErrors float64
SndbufErrors float64
InCsumErrors float64
IgnoredMulti float64
}

type UdpLite struct {
InDatagrams float64
NoPorts float64
InErrors float64
OutDatagrams float64
RcvbufErrors float64
SndbufErrors float64
InCsumErrors float64
IgnoredMulti float64
}

func (p Proc) Snmp() (ProcSnmp, error) {
filename := p.path("net/snmp")
procSnmp := ProcSnmp{PID: p.PID}

file, err := os.Open(filename)
if err != nil {
return procSnmp, err
}
defer file.Close()

netStats, err := parseNetStats(file, filename)
if err != nil {
return procSnmp, err
}

mapStructureErr := mapstructure.Decode(netStats, &procSnmp)
if mapStructureErr != nil {
return procSnmp, mapStructureErr
}

return procSnmp, nil
}

// parseSnmp parses the metrics from proc/<pid>/net/snmp file
// and returns a map contains those metrics (e.g. {"Ip": {"Forwarding": 2}}
func parseNetStats(r io.Reader, fileName string) (map[string]map[string]float64, error) {
var (
netStats = map[string]map[string]float64{}
scanner = bufio.NewScanner(r)
)

for scanner.Scan() {
nameParts := strings.Split(scanner.Text(), " ")
scanner.Scan()
valueParts := strings.Split(scanner.Text(), " ")
// Remove trailing :.
protocol := nameParts[0][:len(nameParts[0])-1]
netStats[protocol] = map[string]float64{}
if len(nameParts) != len(valueParts) {
return nil, fmt.Errorf("mismatch field count mismatch in %s: %s",
fileName, protocol)
}
for i := 1; i < len(nameParts); i++ {
var err error
netStats[protocol][nameParts[i]], err = strconv.ParseFloat(valueParts[i], 64)
if err != nil {
return nil, err
}
}
}

return netStats, scanner.Err()
}
52 changes: 52 additions & 0 deletions proc_snmp_test.go
@@ -0,0 +1,52 @@
// Copyright 2022 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 procfs

import "testing"

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

procSnmp, err := p.Snmp()
if err != nil {
t.Fatal(err)
}

for _, test := range []struct {
name string
want float64
have float64
}{
{name: "pid", want: 26231, have: float64(procSnmp.PID)},
{name: "IP:Forwarding", want: 2, have: procSnmp.Ip.Forwarding},
{name: "IP:DefaultTTL", want: 64, have: procSnmp.Ip.DefaultTTL},
{name: "Icmp:InMsgs", want: 45, have: procSnmp.Icmp.InMsgs},
{name: "IcmpMsg:InType3", want: 45, have: procSnmp.IcmpMsg.InType3},
{name: "IcmpMsg:OutType3", want: 50, have: procSnmp.IcmpMsg.OutType3},
{name: "TCP:RtoAlgorithm", want: 1, have: procSnmp.Tcp.RtoAlgorithm},
{name: "TCP:RtoMin", want: 200, have: procSnmp.Tcp.RtoMin},
{name: "Udp:InDatagrams", want: 10179, have: procSnmp.Udp.InDatagrams},
{name: "Udp:NoPorts", want: 50, have: procSnmp.Udp.NoPorts},
{name: "UdpLite:InDatagrams", want: 0, have: procSnmp.UdpLite.NoPorts},
{name: "UdpLite:NoPorts", want: 0, have: procSnmp.UdpLite.NoPorts},
} {
if test.want != test.have {
t.Errorf("want %s %f, have %f", test.name, test.want, test.have)
}
}

}

0 comments on commit a8481ba

Please sign in to comment.