ingress-nginx-helm/vendor/github.com/ncabatoff/procfs/proc_status.go
Manuel Alejandro de Brito Fontes f4a4daed84 Update go dependencies
2018-12-05 13:27:09 -03:00

203 lines
6.5 KiB
Go

// Copyright 2018 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 (
"fmt"
"io"
"io/ioutil"
"os"
"strings"
)
// ProcStatus provides status information about the process,
// read from /proc/[pid]/status.
type (
ProcStatus struct {
TID int
TracerPid int
UIDReal int
UIDEffective int
UIDSavedSet int
UIDFileSystem int
GIDReal int
GIDEffective int
GIDSavedSet int
GIDFileSystem int
FDSize int
VmPeakKB int
VmSizeKB int
VmLckKB int
VmHWMKB int
VmRSSKB int
VmDataKB int
VmStkKB int
VmExeKB int
VmLibKB int
VmPTEKB int
VmSwapKB int
VoluntaryCtxtSwitches int
NonvoluntaryCtxtSwitches int
}
procStatusFiller func(*ProcStatus, string) error
procStatusBuilder struct {
scanners map[string]procStatusFiller
}
)
func (ps *ProcStatus) refTID() []interface{} {
return []interface{}{&ps.TID}
}
func (ps *ProcStatus) refTracerPid() []interface{} {
return []interface{}{&ps.TracerPid}
}
func (ps *ProcStatus) refUID() []interface{} {
return []interface{}{&ps.UIDReal, &ps.UIDEffective, &ps.UIDSavedSet, &ps.UIDFileSystem}
}
func (ps *ProcStatus) refGID() []interface{} {
return []interface{}{&ps.GIDReal, &ps.GIDEffective, &ps.GIDSavedSet, &ps.GIDFileSystem}
}
func (ps *ProcStatus) refFDSize() []interface{} {
return []interface{}{&ps.FDSize}
}
func (ps *ProcStatus) refVmPeakKB() []interface{} {
return []interface{}{&ps.VmPeakKB}
}
func (ps *ProcStatus) refVmSizeKB() []interface{} {
return []interface{}{&ps.VmSizeKB}
}
func (ps *ProcStatus) refVmLckKB() []interface{} {
return []interface{}{&ps.VmLckKB}
}
func (ps *ProcStatus) refVmHWMKB() []interface{} {
return []interface{}{&ps.VmHWMKB}
}
func (ps *ProcStatus) refVmRSSKB() []interface{} {
return []interface{}{&ps.VmRSSKB}
}
func (ps *ProcStatus) refVmDataKB() []interface{} {
return []interface{}{&ps.VmDataKB}
}
func (ps *ProcStatus) refVmStkKB() []interface{} {
return []interface{}{&ps.VmStkKB}
}
func (ps *ProcStatus) refVmExeKB() []interface{} {
return []interface{}{&ps.VmExeKB}
}
func (ps *ProcStatus) refVmLibKB() []interface{} {
return []interface{}{&ps.VmLibKB}
}
func (ps *ProcStatus) refVmPTEKB() []interface{} {
return []interface{}{&ps.VmPTEKB}
}
func (ps *ProcStatus) refVmSwapKB() []interface{} {
return []interface{}{&ps.VmSwapKB}
}
func (ps *ProcStatus) refVoluntaryCtxtSwitches() []interface{} {
return []interface{}{&ps.VoluntaryCtxtSwitches}
}
func (ps *ProcStatus) refNonvoluntaryCtxtSwitches() []interface{} {
return []interface{}{&ps.NonvoluntaryCtxtSwitches}
}
func newFiller(format string, ref func(ps *ProcStatus) []interface{}) procStatusFiller {
return procStatusFiller(func(ps *ProcStatus, s string) error {
_, err := fmt.Sscanf(s, format, ref(ps)...)
return err
})
}
func newProcStatusBuilder() *procStatusBuilder {
return &procStatusBuilder{
scanners: map[string]procStatusFiller{
"Pid": newFiller("%d", (*ProcStatus).refTID),
"TracerPid": newFiller("%d", (*ProcStatus).refTracerPid),
"Uid": newFiller("%d %d %d %d", (*ProcStatus).refUID),
"Gid": newFiller("%d %d %d %d", (*ProcStatus).refGID),
"FDSize": newFiller("%d", (*ProcStatus).refFDSize),
"VmPeak": newFiller("%d kB", (*ProcStatus).refVmPeakKB),
"VmSize": newFiller("%d kB", (*ProcStatus).refVmSizeKB),
"VmLck": newFiller("%d kB", (*ProcStatus).refVmLckKB),
"VmHWM": newFiller("%d kB", (*ProcStatus).refVmHWMKB),
"VmRSS": newFiller("%d kB", (*ProcStatus).refVmRSSKB),
"VmData": newFiller("%d kB", (*ProcStatus).refVmDataKB),
"VmStk": newFiller("%d kB", (*ProcStatus).refVmStkKB),
"VmExe": newFiller("%d kB", (*ProcStatus).refVmExeKB),
"VmLib": newFiller("%d kB", (*ProcStatus).refVmLibKB),
"VmPTE": newFiller("%d kB", (*ProcStatus).refVmPTEKB),
"VmSwap": newFiller("%d kB", (*ProcStatus).refVmSwapKB),
"voluntary_ctxt_switches": newFiller("%d", (*ProcStatus).refVoluntaryCtxtSwitches),
"nonvoluntary_ctxt_switches": newFiller("%d", (*ProcStatus).refNonvoluntaryCtxtSwitches),
},
}
}
func (b *procStatusBuilder) readStatus(r io.Reader) (ProcStatus, error) {
contents, err := ioutil.ReadAll(r)
if err != nil {
return ProcStatus{}, err
}
s := string(contents)
var ps ProcStatus
for lineno := 0; s != ""; lineno++ {
crpos := strings.IndexByte(s, '\n')
if crpos == -1 {
return ProcStatus{}, fmt.Errorf("line %d from status file without newline: %s", lineno, s)
}
line := strings.TrimSpace(s[:crpos])
s = s[crpos+1:]
if line == "" {
if s == "" {
break
}
continue
}
pos := strings.IndexByte(line, ':')
if pos == -1 {
return ProcStatus{}, fmt.Errorf("line %d from status file without ':': %s", lineno, line)
}
field := line[:pos]
scanner, ok := b.scanners[field]
if !ok {
continue
}
err = scanner(&ps, line[pos+1:])
// TODO: flag parse errors with some kind of "warning" error.
if err != nil {
// Be lenient about parse errors, because otherwise we miss out on some interesting
// procs. For example, my Ubuntu kernel (4.4.0-130-generic #156-Ubuntu) is showing
// a Chromium status file with "VmLib: 18446744073709442944 kB".
continue
}
}
return ps, nil
}
var psb = newProcStatusBuilder()
// NewStatus returns the current status information of the process.
func (p Proc) NewStatus() (ProcStatus, error) {
f, err := os.Open(p.path("status"))
if err != nil {
return ProcStatus{}, err
}
defer f.Close()
return psb.readStatus(f)
}