Updating server dependancies (#5249)
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
ca3211bc04
Коммит
701d1ab638
47
vendor/github.com/prometheus/common/expfmt/decode.go
сгенерированный
поставляемый
47
vendor/github.com/prometheus/common/expfmt/decode.go
сгенерированный
поставляемый
@@ -31,6 +31,7 @@ type Decoder interface {
|
||||
Decode(*dto.MetricFamily) error
|
||||
}
|
||||
|
||||
// DecodeOptions contains options used by the Decoder and in sample extraction.
|
||||
type DecodeOptions struct {
|
||||
// Timestamp is added to each value from the stream that has no explicit timestamp set.
|
||||
Timestamp model.Time
|
||||
@@ -142,6 +143,8 @@ func (d *textDecoder) Decode(v *dto.MetricFamily) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SampleDecoder wraps a Decoder to extract samples from the metric families
|
||||
// decoded by the wrapped Decoder.
|
||||
type SampleDecoder struct {
|
||||
Dec Decoder
|
||||
Opts *DecodeOptions
|
||||
@@ -149,37 +152,51 @@ type SampleDecoder struct {
|
||||
f dto.MetricFamily
|
||||
}
|
||||
|
||||
// Decode calls the Decode method of the wrapped Decoder and then extracts the
|
||||
// samples from the decoded MetricFamily into the provided model.Vector.
|
||||
func (sd *SampleDecoder) Decode(s *model.Vector) error {
|
||||
if err := sd.Dec.Decode(&sd.f); err != nil {
|
||||
err := sd.Dec.Decode(&sd.f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*s = extractSamples(&sd.f, sd.Opts)
|
||||
return nil
|
||||
*s, err = extractSamples(&sd.f, sd.Opts)
|
||||
return err
|
||||
}
|
||||
|
||||
// Extract samples builds a slice of samples from the provided metric families.
|
||||
func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) model.Vector {
|
||||
var all model.Vector
|
||||
// ExtractSamples builds a slice of samples from the provided metric
|
||||
// families. If an error occurs during sample extraction, it continues to
|
||||
// extract from the remaining metric families. The returned error is the last
|
||||
// error that has occured.
|
||||
func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error) {
|
||||
var (
|
||||
all model.Vector
|
||||
lastErr error
|
||||
)
|
||||
for _, f := range fams {
|
||||
all = append(all, extractSamples(f, o)...)
|
||||
some, err := extractSamples(f, o)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
all = append(all, some...)
|
||||
}
|
||||
return all
|
||||
return all, lastErr
|
||||
}
|
||||
|
||||
func extractSamples(f *dto.MetricFamily, o *DecodeOptions) model.Vector {
|
||||
func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error) {
|
||||
switch f.GetType() {
|
||||
case dto.MetricType_COUNTER:
|
||||
return extractCounter(o, f)
|
||||
return extractCounter(o, f), nil
|
||||
case dto.MetricType_GAUGE:
|
||||
return extractGauge(o, f)
|
||||
return extractGauge(o, f), nil
|
||||
case dto.MetricType_SUMMARY:
|
||||
return extractSummary(o, f)
|
||||
return extractSummary(o, f), nil
|
||||
case dto.MetricType_UNTYPED:
|
||||
return extractUntyped(o, f)
|
||||
return extractUntyped(o, f), nil
|
||||
case dto.MetricType_HISTOGRAM:
|
||||
return extractHistogram(o, f)
|
||||
return extractHistogram(o, f), nil
|
||||
}
|
||||
panic("expfmt.extractSamples: unknown metric family type")
|
||||
return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType())
|
||||
}
|
||||
|
||||
func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||
|
||||
68
vendor/github.com/prometheus/common/expfmt/decode_test.go
сгенерированный
поставляемый
68
vendor/github.com/prometheus/common/expfmt/decode_test.go
сгенерированный
поставляемый
@@ -21,6 +21,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
@@ -365,3 +368,68 @@ func BenchmarkDiscriminatorHTTPHeader(b *testing.B) {
|
||||
testDiscriminatorHTTPHeader(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractSamples(t *testing.T) {
|
||||
var (
|
||||
goodMetricFamily1 = &dto.MetricFamily{
|
||||
Name: proto.String("foo"),
|
||||
Help: proto.String("Help for foo."),
|
||||
Type: dto.MetricType_COUNTER.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
&dto.Metric{
|
||||
Counter: &dto.Counter{
|
||||
Value: proto.Float64(4711),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
goodMetricFamily2 = &dto.MetricFamily{
|
||||
Name: proto.String("bar"),
|
||||
Help: proto.String("Help for bar."),
|
||||
Type: dto.MetricType_GAUGE.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
&dto.Metric{
|
||||
Gauge: &dto.Gauge{
|
||||
Value: proto.Float64(3.14),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
badMetricFamily = &dto.MetricFamily{
|
||||
Name: proto.String("bad"),
|
||||
Help: proto.String("Help for bad."),
|
||||
Type: dto.MetricType(42).Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
&dto.Metric{
|
||||
Gauge: &dto.Gauge{
|
||||
Value: proto.Float64(2.7),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
opts = &DecodeOptions{
|
||||
Timestamp: 42,
|
||||
}
|
||||
)
|
||||
|
||||
got, err := ExtractSamples(opts, goodMetricFamily1, goodMetricFamily2)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error from ExtractSamples:", err)
|
||||
}
|
||||
want := model.Vector{
|
||||
&model.Sample{Metric: model.Metric{model.MetricNameLabel: "foo"}, Value: 4711, Timestamp: 42},
|
||||
&model.Sample{Metric: model.Metric{model.MetricNameLabel: "bar"}, Value: 3.14, Timestamp: 42},
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
got, err = ExtractSamples(opts, goodMetricFamily1, badMetricFamily, goodMetricFamily2)
|
||||
if err == nil {
|
||||
t.Error("Expected error from ExtractSamples")
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
7
vendor/github.com/prometheus/common/expfmt/expfmt.go
сгенерированный
поставляемый
7
vendor/github.com/prometheus/common/expfmt/expfmt.go
сгенерированный
поставляемый
@@ -11,14 +11,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// A package for reading and writing Prometheus metrics.
|
||||
// Package expfmt contains tools for reading and writing Prometheus metrics.
|
||||
package expfmt
|
||||
|
||||
// Format specifies the HTTP content type of the different wire protocols.
|
||||
type Format string
|
||||
|
||||
// Constants to assemble the Content-Type values for the different wire protocols.
|
||||
const (
|
||||
TextVersion = "0.0.4"
|
||||
|
||||
TextVersion = "0.0.4"
|
||||
ProtoType = `application/vnd.google.protobuf`
|
||||
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||
ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
||||
|
||||
11
vendor/github.com/prometheus/common/log/syslog_formatter.go
сгенерированный
поставляемый
11
vendor/github.com/prometheus/common/log/syslog_formatter.go
сгенерированный
поставляемый
@@ -23,6 +23,8 @@ import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var _ logrus.Formatter = (*syslogger)(nil)
|
||||
|
||||
func init() {
|
||||
setSyslogFormatter = func(appname, local string) error {
|
||||
if appname == "" {
|
||||
@@ -43,7 +45,7 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
var ceeTag = []byte("@cee:")
|
||||
var prefixTag []byte
|
||||
|
||||
type syslogger struct {
|
||||
wrap logrus.Formatter
|
||||
@@ -56,6 +58,11 @@ func newSyslogger(appname string, facility string, fmter logrus.Formatter) (*sys
|
||||
return nil, err
|
||||
}
|
||||
out, err := syslog.New(priority, appname)
|
||||
_, isJSON := fmter.(*logrus.JSONFormatter)
|
||||
if isJSON {
|
||||
// add cee tag to json formatted syslogs
|
||||
prefixTag = []byte("@cee:")
|
||||
}
|
||||
return &syslogger{
|
||||
out: out,
|
||||
wrap: fmter,
|
||||
@@ -92,7 +99,7 @@ func (s *syslogger) Format(e *logrus.Entry) ([]byte, error) {
|
||||
}
|
||||
// only append tag to data sent to syslog (line), not to what
|
||||
// is returned
|
||||
line := string(append(ceeTag, data...))
|
||||
line := string(append(prefixTag, data...))
|
||||
|
||||
switch e.Level {
|
||||
case logrus.PanicLevel:
|
||||
|
||||
52
vendor/github.com/prometheus/common/log/syslog_formatter_test.go
сгенерированный
поставляемый
Обычный файл
52
vendor/github.com/prometheus/common/log/syslog_formatter_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,52 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// +build !windows,!nacl,!plan9
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/syslog"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetFacility(t *testing.T) {
|
||||
testCases := []struct {
|
||||
facility string
|
||||
expectedPriority syslog.Priority
|
||||
expectedErr error
|
||||
}{
|
||||
{"0", syslog.LOG_LOCAL0, nil},
|
||||
{"1", syslog.LOG_LOCAL1, nil},
|
||||
{"2", syslog.LOG_LOCAL2, nil},
|
||||
{"3", syslog.LOG_LOCAL3, nil},
|
||||
{"4", syslog.LOG_LOCAL4, nil},
|
||||
{"5", syslog.LOG_LOCAL5, nil},
|
||||
{"6", syslog.LOG_LOCAL6, nil},
|
||||
{"7", syslog.LOG_LOCAL7, nil},
|
||||
{"8", syslog.LOG_LOCAL0, errors.New("invalid local(8) for syslog")},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
priority, err := getFacility(tc.facility)
|
||||
if err != tc.expectedErr {
|
||||
if err.Error() != tc.expectedErr.Error() {
|
||||
t.Errorf("want %s, got %s", tc.expectedErr.Error(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if priority != tc.expectedPriority {
|
||||
t.Errorf("want %q, got %q", tc.expectedPriority, priority)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/prometheus/common/model/metric.go
сгенерированный
поставляемый
2
vendor/github.com/prometheus/common/model/metric.go
сгенерированный
поставляемый
@@ -44,7 +44,7 @@ func (m Metric) Before(o Metric) bool {
|
||||
|
||||
// Clone returns a copy of the Metric.
|
||||
func (m Metric) Clone() Metric {
|
||||
clone := Metric{}
|
||||
clone := make(Metric, len(m))
|
||||
for k, v := range m {
|
||||
clone[k] = v
|
||||
}
|
||||
|
||||
7
vendor/github.com/prometheus/common/route/route.go
сгенерированный
поставляемый
7
vendor/github.com/prometheus/common/route/route.go
сгенерированный
поставляемый
@@ -33,18 +33,19 @@ func WithParam(ctx context.Context, p, v string) context.Context {
|
||||
return context.WithValue(ctx, param(p), v)
|
||||
}
|
||||
|
||||
type contextFn func(r *http.Request) (context.Context, error)
|
||||
// ContextFunc returns a new context for a request.
|
||||
type ContextFunc func(r *http.Request) (context.Context, error)
|
||||
|
||||
// Router wraps httprouter.Router and adds support for prefixed sub-routers
|
||||
// and per-request context injections.
|
||||
type Router struct {
|
||||
rtr *httprouter.Router
|
||||
prefix string
|
||||
ctxFn contextFn
|
||||
ctxFn ContextFunc
|
||||
}
|
||||
|
||||
// New returns a new Router.
|
||||
func New(ctxFn contextFn) *Router {
|
||||
func New(ctxFn ContextFunc) *Router {
|
||||
if ctxFn == nil {
|
||||
ctxFn = func(r *http.Request) (context.Context, error) {
|
||||
return context.Background(), nil
|
||||
|
||||
2
vendor/github.com/prometheus/common/route/route_test.go
сгенерированный
поставляемый
2
vendor/github.com/prometheus/common/route/route_test.go
сгенерированный
поставляемый
@@ -29,7 +29,7 @@ func TestRedirect(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextFn(t *testing.T) {
|
||||
func TestContextFunc(t *testing.T) {
|
||||
router := New(func(r *http.Request) (context.Context, error) {
|
||||
return context.WithValue(context.Background(), "testkey", "testvalue"), nil
|
||||
})
|
||||
|
||||
4
vendor/github.com/prometheus/procfs/.travis.yml
сгенерированный
поставляемый
4
vendor/github.com/prometheus/procfs/.travis.yml
сгенерированный
поставляемый
@@ -1,5 +1,5 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.6.4
|
||||
- 1.7.4
|
||||
|
||||
1
vendor/github.com/prometheus/procfs/AUTHORS.md
сгенерированный
поставляемый
1
vendor/github.com/prometheus/procfs/AUTHORS.md
сгенерированный
поставляемый
@@ -14,6 +14,7 @@ The following individuals have contributed code to this repository
|
||||
* Ji-Hoon, Seol <jihoon.seol@gmail.com>
|
||||
* Jonas Große Sundrup <cherti@letopolis.de>
|
||||
* Julius Volz <julius.volz@gmail.com>
|
||||
* Matt Layher <mdlayher@gmail.com>
|
||||
* Matthias Rampke <mr@soundcloud.com>
|
||||
* Nicky Gerritsen <nicky@streamone.nl>
|
||||
* Rémi Audebert <contact@halfr.net>
|
||||
|
||||
19
vendor/github.com/prometheus/procfs/fixtures/26231/mountstats
сгенерированный
поставляемый
Обычный файл
19
vendor/github.com/prometheus/procfs/fixtures/26231/mountstats
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,19 @@
|
||||
device rootfs mounted on / with fstype rootfs
|
||||
device sysfs mounted on /sys with fstype sysfs
|
||||
device proc mounted on /proc with fstype proc
|
||||
device /dev/sda1 mounted on / with fstype ext4
|
||||
device 192.168.1.1:/srv/test mounted on /mnt/nfs/test with fstype nfs4 statvers=1.1
|
||||
opts: rw,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.5,local_lock=none
|
||||
age: 13968
|
||||
caps: caps=0xfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255
|
||||
nfsv4: bm0=0xfdffafff,bm1=0xf9be3e,bm2=0x0,acl=0x0,pnfs=not configured
|
||||
sec: flavor=1,pseudoflavor=1
|
||||
events: 52 226 0 0 1 13 398 0 0 331 0 47 0 0 77 0 0 77 0 0 0 0 0 0 0 0 0
|
||||
bytes: 1207640230 0 0 0 1210214218 0 295483 0
|
||||
RPC iostats version: 1.0 p/v: 100003/4 (nfs)
|
||||
xprt: tcp 832 0 1 0 11 6428 6428 0 12154 0 24 26 5726
|
||||
per-op statistics
|
||||
NULL: 0 0 0 0 0 0 0 0
|
||||
READ: 1298 1298 0 207680 1210292152 6 79386 79407
|
||||
WRITE: 0 0 0 0 0 0 0 0
|
||||
|
||||
552
vendor/github.com/prometheus/procfs/mountstats.go
сгенерированный
поставляемый
Обычный файл
552
vendor/github.com/prometheus/procfs/mountstats.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,552 @@
|
||||
package procfs
|
||||
|
||||
// While implementing parsing of /proc/[pid]/mountstats, this blog was used
|
||||
// heavily as a reference:
|
||||
// https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex
|
||||
//
|
||||
// Special thanks to Chris Siebenmann for all of his posts explaining the
|
||||
// various statistics available for NFS.
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Constants shared between multiple functions.
|
||||
const (
|
||||
deviceEntryLen = 8
|
||||
|
||||
fieldBytesLen = 8
|
||||
fieldEventsLen = 27
|
||||
|
||||
statVersion10 = "1.0"
|
||||
statVersion11 = "1.1"
|
||||
|
||||
fieldTransport10Len = 10
|
||||
fieldTransport11Len = 13
|
||||
)
|
||||
|
||||
// A Mount is a device mount parsed from /proc/[pid]/mountstats.
|
||||
type Mount struct {
|
||||
// Name of the device.
|
||||
Device string
|
||||
// The mount point of the device.
|
||||
Mount string
|
||||
// The filesystem type used by the device.
|
||||
Type string
|
||||
// If available additional statistics related to this Mount.
|
||||
// Use a type assertion to determine if additional statistics are available.
|
||||
Stats MountStats
|
||||
}
|
||||
|
||||
// A MountStats is a type which contains detailed statistics for a specific
|
||||
// type of Mount.
|
||||
type MountStats interface {
|
||||
mountStats()
|
||||
}
|
||||
|
||||
// A MountStatsNFS is a MountStats implementation for NFSv3 and v4 mounts.
|
||||
type MountStatsNFS struct {
|
||||
// The version of statistics provided.
|
||||
StatVersion string
|
||||
// The age of the NFS mount.
|
||||
Age time.Duration
|
||||
// Statistics related to byte counters for various operations.
|
||||
Bytes NFSBytesStats
|
||||
// Statistics related to various NFS event occurrences.
|
||||
Events NFSEventsStats
|
||||
// Statistics broken down by filesystem operation.
|
||||
Operations []NFSOperationStats
|
||||
// Statistics about the NFS RPC transport.
|
||||
Transport NFSTransportStats
|
||||
}
|
||||
|
||||
// mountStats implements MountStats.
|
||||
func (m MountStatsNFS) mountStats() {}
|
||||
|
||||
// A NFSBytesStats contains statistics about the number of bytes read and written
|
||||
// by an NFS client to and from an NFS server.
|
||||
type NFSBytesStats struct {
|
||||
// Number of bytes read using the read() syscall.
|
||||
Read uint64
|
||||
// Number of bytes written using the write() syscall.
|
||||
Write uint64
|
||||
// Number of bytes read using the read() syscall in O_DIRECT mode.
|
||||
DirectRead uint64
|
||||
// Number of bytes written using the write() syscall in O_DIRECT mode.
|
||||
DirectWrite uint64
|
||||
// Number of bytes read from the NFS server, in total.
|
||||
ReadTotal uint64
|
||||
// Number of bytes written to the NFS server, in total.
|
||||
WriteTotal uint64
|
||||
// Number of pages read directly via mmap()'d files.
|
||||
ReadPages uint64
|
||||
// Number of pages written directly via mmap()'d files.
|
||||
WritePages uint64
|
||||
}
|
||||
|
||||
// A NFSEventsStats contains statistics about NFS event occurrences.
|
||||
type NFSEventsStats struct {
|
||||
// Number of times cached inode attributes are re-validated from the server.
|
||||
InodeRevalidate uint64
|
||||
// Number of times cached dentry nodes are re-validated from the server.
|
||||
DnodeRevalidate uint64
|
||||
// Number of times an inode cache is cleared.
|
||||
DataInvalidate uint64
|
||||
// Number of times cached inode attributes are invalidated.
|
||||
AttributeInvalidate uint64
|
||||
// Number of times files or directories have been open()'d.
|
||||
VFSOpen uint64
|
||||
// Number of times a directory lookup has occurred.
|
||||
VFSLookup uint64
|
||||
// Number of times permissions have been checked.
|
||||
VFSAccess uint64
|
||||
// Number of updates (and potential writes) to pages.
|
||||
VFSUpdatePage uint64
|
||||
// Number of pages read directly via mmap()'d files.
|
||||
VFSReadPage uint64
|
||||
// Number of times a group of pages have been read.
|
||||
VFSReadPages uint64
|
||||
// Number of pages written directly via mmap()'d files.
|
||||
VFSWritePage uint64
|
||||
// Number of times a group of pages have been written.
|
||||
VFSWritePages uint64
|
||||
// Number of times directory entries have been read with getdents().
|
||||
VFSGetdents uint64
|
||||
// Number of times attributes have been set on inodes.
|
||||
VFSSetattr uint64
|
||||
// Number of pending writes that have been forcefully flushed to the server.
|
||||
VFSFlush uint64
|
||||
// Number of times fsync() has been called on directories and files.
|
||||
VFSFsync uint64
|
||||
// Number of times locking has been attemped on a file.
|
||||
VFSLock uint64
|
||||
// Number of times files have been closed and released.
|
||||
VFSFileRelease uint64
|
||||
// Unknown. Possibly unused.
|
||||
CongestionWait uint64
|
||||
// Number of times files have been truncated.
|
||||
Truncation uint64
|
||||
// Number of times a file has been grown due to writes beyond its existing end.
|
||||
WriteExtension uint64
|
||||
// Number of times a file was removed while still open by another process.
|
||||
SillyRename uint64
|
||||
// Number of times the NFS server gave less data than expected while reading.
|
||||
ShortRead uint64
|
||||
// Number of times the NFS server wrote less data than expected while writing.
|
||||
ShortWrite uint64
|
||||
// Number of times the NFS server indicated EJUKEBOX; retrieving data from
|
||||
// offline storage.
|
||||
JukeboxDelay uint64
|
||||
// Number of NFS v4.1+ pNFS reads.
|
||||
PNFSRead uint64
|
||||
// Number of NFS v4.1+ pNFS writes.
|
||||
PNFSWrite uint64
|
||||
}
|
||||
|
||||
// A NFSOperationStats contains statistics for a single operation.
|
||||
type NFSOperationStats struct {
|
||||
// The name of the operation.
|
||||
Operation string
|
||||
// Number of requests performed for this operation.
|
||||
Requests uint64
|
||||
// Number of times an actual RPC request has been transmitted for this operation.
|
||||
Transmissions uint64
|
||||
// Number of times a request has had a major timeout.
|
||||
MajorTimeouts uint64
|
||||
// Number of bytes sent for this operation, including RPC headers and payload.
|
||||
BytesSent uint64
|
||||
// Number of bytes received for this operation, including RPC headers and payload.
|
||||
BytesReceived uint64
|
||||
// Duration all requests spent queued for transmission before they were sent.
|
||||
CumulativeQueueTime time.Duration
|
||||
// Duration it took to get a reply back after the request was transmitted.
|
||||
CumulativeTotalResponseTime time.Duration
|
||||
// Duration from when a request was enqueued to when it was completely handled.
|
||||
CumulativeTotalRequestTime time.Duration
|
||||
}
|
||||
|
||||
// A NFSTransportStats contains statistics for the NFS mount RPC requests and
|
||||
// responses.
|
||||
type NFSTransportStats struct {
|
||||
// The local port used for the NFS mount.
|
||||
Port uint64
|
||||
// Number of times the client has had to establish a connection from scratch
|
||||
// to the NFS server.
|
||||
Bind uint64
|
||||
// Number of times the client has made a TCP connection to the NFS server.
|
||||
Connect uint64
|
||||
// Duration (in jiffies, a kernel internal unit of time) the NFS mount has
|
||||
// spent waiting for connections to the server to be established.
|
||||
ConnectIdleTime uint64
|
||||
// Duration since the NFS mount last saw any RPC traffic.
|
||||
IdleTime time.Duration
|
||||
// Number of RPC requests for this mount sent to the NFS server.
|
||||
Sends uint64
|
||||
// Number of RPC responses for this mount received from the NFS server.
|
||||
Receives uint64
|
||||
// Number of times the NFS server sent a response with a transaction ID
|
||||
// unknown to this client.
|
||||
BadTransactionIDs uint64
|
||||
// A running counter, incremented on each request as the current difference
|
||||
// ebetween sends and receives.
|
||||
CumulativeActiveRequests uint64
|
||||
// A running counter, incremented on each request by the current backlog
|
||||
// queue size.
|
||||
CumulativeBacklog uint64
|
||||
|
||||
// Stats below only available with stat version 1.1.
|
||||
|
||||
// Maximum number of simultaneously active RPC requests ever used.
|
||||
MaximumRPCSlotsUsed uint64
|
||||
// A running counter, incremented on each request as the current size of the
|
||||
// sending queue.
|
||||
CumulativeSendingQueue uint64
|
||||
// A running counter, incremented on each request as the current size of the
|
||||
// pending queue.
|
||||
CumulativePendingQueue uint64
|
||||
}
|
||||
|
||||
// parseMountStats parses a /proc/[pid]/mountstats file and returns a slice
|
||||
// of Mount structures containing detailed information about each mount.
|
||||
// If available, statistics for each mount are parsed as well.
|
||||
func parseMountStats(r io.Reader) ([]*Mount, error) {
|
||||
const (
|
||||
device = "device"
|
||||
statVersionPrefix = "statvers="
|
||||
|
||||
nfs3Type = "nfs"
|
||||
nfs4Type = "nfs4"
|
||||
)
|
||||
|
||||
var mounts []*Mount
|
||||
|
||||
s := bufio.NewScanner(r)
|
||||
for s.Scan() {
|
||||
// Only look for device entries in this function
|
||||
ss := strings.Fields(string(s.Bytes()))
|
||||
if len(ss) == 0 || ss[0] != device {
|
||||
continue
|
||||
}
|
||||
|
||||
m, err := parseMount(ss)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Does this mount also possess statistics information?
|
||||
if len(ss) > deviceEntryLen {
|
||||
// Only NFSv3 and v4 are supported for parsing statistics
|
||||
if m.Type != nfs3Type && m.Type != nfs4Type {
|
||||
return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type)
|
||||
}
|
||||
|
||||
statVersion := strings.TrimPrefix(ss[8], statVersionPrefix)
|
||||
|
||||
stats, err := parseMountStatsNFS(s, statVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.Stats = stats
|
||||
}
|
||||
|
||||
mounts = append(mounts, m)
|
||||
}
|
||||
|
||||
return mounts, s.Err()
|
||||
}
|
||||
|
||||
// parseMount parses an entry in /proc/[pid]/mountstats in the format:
|
||||
// device [device] mounted on [mount] with fstype [type]
|
||||
func parseMount(ss []string) (*Mount, error) {
|
||||
if len(ss) < deviceEntryLen {
|
||||
return nil, fmt.Errorf("invalid device entry: %v", ss)
|
||||
}
|
||||
|
||||
// Check for specific words appearing at specific indices to ensure
|
||||
// the format is consistent with what we expect
|
||||
format := []struct {
|
||||
i int
|
||||
s string
|
||||
}{
|
||||
{i: 0, s: "device"},
|
||||
{i: 2, s: "mounted"},
|
||||
{i: 3, s: "on"},
|
||||
{i: 5, s: "with"},
|
||||
{i: 6, s: "fstype"},
|
||||
}
|
||||
|
||||
for _, f := range format {
|
||||
if ss[f.i] != f.s {
|
||||
return nil, fmt.Errorf("invalid device entry: %v", ss)
|
||||
}
|
||||
}
|
||||
|
||||
return &Mount{
|
||||
Device: ss[1],
|
||||
Mount: ss[4],
|
||||
Type: ss[7],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseMountStatsNFS parses a MountStatsNFS by scanning additional information
|
||||
// related to NFS statistics.
|
||||
func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) {
|
||||
// Field indicators for parsing specific types of data
|
||||
const (
|
||||
fieldAge = "age:"
|
||||
fieldBytes = "bytes:"
|
||||
fieldEvents = "events:"
|
||||
fieldPerOpStats = "per-op"
|
||||
fieldTransport = "xprt:"
|
||||
)
|
||||
|
||||
stats := &MountStatsNFS{
|
||||
StatVersion: statVersion,
|
||||
}
|
||||
|
||||
for s.Scan() {
|
||||
ss := strings.Fields(string(s.Bytes()))
|
||||
if len(ss) == 0 {
|
||||
break
|
||||
}
|
||||
if len(ss) < 2 {
|
||||
return nil, fmt.Errorf("not enough information for NFS stats: %v", ss)
|
||||
}
|
||||
|
||||
switch ss[0] {
|
||||
case fieldAge:
|
||||
// Age integer is in seconds
|
||||
d, err := time.ParseDuration(ss[1] + "s")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats.Age = d
|
||||
case fieldBytes:
|
||||
bstats, err := parseNFSBytesStats(ss[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats.Bytes = *bstats
|
||||
case fieldEvents:
|
||||
estats, err := parseNFSEventsStats(ss[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats.Events = *estats
|
||||
case fieldTransport:
|
||||
if len(ss) < 3 {
|
||||
return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss)
|
||||
}
|
||||
|
||||
tstats, err := parseNFSTransportStats(ss[2:], statVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats.Transport = *tstats
|
||||
}
|
||||
|
||||
// When encountering "per-operation statistics", we must break this
|
||||
// loop and parse them seperately to ensure we can terminate parsing
|
||||
// before reaching another device entry; hence why this 'if' statement
|
||||
// is not just another switch case
|
||||
if ss[0] == fieldPerOpStats {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// NFS per-operation stats appear last before the next device entry
|
||||
perOpStats, err := parseNFSOperationStats(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats.Operations = perOpStats
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// parseNFSBytesStats parses a NFSBytesStats line using an input set of
|
||||
// integer fields.
|
||||
func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) {
|
||||
if len(ss) != fieldBytesLen {
|
||||
return nil, fmt.Errorf("invalid NFS bytes stats: %v", ss)
|
||||
}
|
||||
|
||||
ns := make([]uint64, 0, fieldBytesLen)
|
||||
for _, s := range ss {
|
||||
n, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ns = append(ns, n)
|
||||
}
|
||||
|
||||
return &NFSBytesStats{
|
||||
Read: ns[0],
|
||||
Write: ns[1],
|
||||
DirectRead: ns[2],
|
||||
DirectWrite: ns[3],
|
||||
ReadTotal: ns[4],
|
||||
WriteTotal: ns[5],
|
||||
ReadPages: ns[6],
|
||||
WritePages: ns[7],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseNFSEventsStats parses a NFSEventsStats line using an input set of
|
||||
// integer fields.
|
||||
func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) {
|
||||
if len(ss) != fieldEventsLen {
|
||||
return nil, fmt.Errorf("invalid NFS events stats: %v", ss)
|
||||
}
|
||||
|
||||
ns := make([]uint64, 0, fieldEventsLen)
|
||||
for _, s := range ss {
|
||||
n, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ns = append(ns, n)
|
||||
}
|
||||
|
||||
return &NFSEventsStats{
|
||||
InodeRevalidate: ns[0],
|
||||
DnodeRevalidate: ns[1],
|
||||
DataInvalidate: ns[2],
|
||||
AttributeInvalidate: ns[3],
|
||||
VFSOpen: ns[4],
|
||||
VFSLookup: ns[5],
|
||||
VFSAccess: ns[6],
|
||||
VFSUpdatePage: ns[7],
|
||||
VFSReadPage: ns[8],
|
||||
VFSReadPages: ns[9],
|
||||
VFSWritePage: ns[10],
|
||||
VFSWritePages: ns[11],
|
||||
VFSGetdents: ns[12],
|
||||
VFSSetattr: ns[13],
|
||||
VFSFlush: ns[14],
|
||||
VFSFsync: ns[15],
|
||||
VFSLock: ns[16],
|
||||
VFSFileRelease: ns[17],
|
||||
CongestionWait: ns[18],
|
||||
Truncation: ns[19],
|
||||
WriteExtension: ns[20],
|
||||
SillyRename: ns[21],
|
||||
ShortRead: ns[22],
|
||||
ShortWrite: ns[23],
|
||||
JukeboxDelay: ns[24],
|
||||
PNFSRead: ns[25],
|
||||
PNFSWrite: ns[26],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseNFSOperationStats parses a slice of NFSOperationStats by scanning
|
||||
// additional information about per-operation statistics until an empty
|
||||
// line is reached.
|
||||
func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
|
||||
const (
|
||||
// Number of expected fields in each per-operation statistics set
|
||||
numFields = 9
|
||||
)
|
||||
|
||||
var ops []NFSOperationStats
|
||||
|
||||
for s.Scan() {
|
||||
ss := strings.Fields(string(s.Bytes()))
|
||||
if len(ss) == 0 {
|
||||
// Must break when reading a blank line after per-operation stats to
|
||||
// enable top-level function to parse the next device entry
|
||||
break
|
||||
}
|
||||
|
||||
if len(ss) != numFields {
|
||||
return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss)
|
||||
}
|
||||
|
||||
// Skip string operation name for integers
|
||||
ns := make([]uint64, 0, numFields-1)
|
||||
for _, st := range ss[1:] {
|
||||
n, err := strconv.ParseUint(st, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ns = append(ns, n)
|
||||
}
|
||||
|
||||
ops = append(ops, NFSOperationStats{
|
||||
Operation: strings.TrimSuffix(ss[0], ":"),
|
||||
Requests: ns[0],
|
||||
Transmissions: ns[1],
|
||||
MajorTimeouts: ns[2],
|
||||
BytesSent: ns[3],
|
||||
BytesReceived: ns[4],
|
||||
CumulativeQueueTime: time.Duration(ns[5]) * time.Millisecond,
|
||||
CumulativeTotalResponseTime: time.Duration(ns[6]) * time.Millisecond,
|
||||
CumulativeTotalRequestTime: time.Duration(ns[7]) * time.Millisecond,
|
||||
})
|
||||
}
|
||||
|
||||
return ops, s.Err()
|
||||
}
|
||||
|
||||
// parseNFSTransportStats parses a NFSTransportStats line using an input set of
|
||||
// integer fields matched to a specific stats version.
|
||||
func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats, error) {
|
||||
switch statVersion {
|
||||
case statVersion10:
|
||||
if len(ss) != fieldTransport10Len {
|
||||
return nil, fmt.Errorf("invalid NFS transport stats 1.0 statement: %v", ss)
|
||||
}
|
||||
case statVersion11:
|
||||
if len(ss) != fieldTransport11Len {
|
||||
return nil, fmt.Errorf("invalid NFS transport stats 1.1 statement: %v", ss)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized NFS transport stats version: %q", statVersion)
|
||||
}
|
||||
|
||||
// Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay
|
||||
// in a v1.0 response
|
||||
ns := make([]uint64, 0, fieldTransport11Len)
|
||||
for _, s := range ss {
|
||||
n, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ns = append(ns, n)
|
||||
}
|
||||
|
||||
return &NFSTransportStats{
|
||||
Port: ns[0],
|
||||
Bind: ns[1],
|
||||
Connect: ns[2],
|
||||
ConnectIdleTime: ns[3],
|
||||
IdleTime: time.Duration(ns[4]) * time.Second,
|
||||
Sends: ns[5],
|
||||
Receives: ns[6],
|
||||
BadTransactionIDs: ns[7],
|
||||
CumulativeActiveRequests: ns[8],
|
||||
CumulativeBacklog: ns[9],
|
||||
MaximumRPCSlotsUsed: ns[10],
|
||||
CumulativeSendingQueue: ns[11],
|
||||
CumulativePendingQueue: ns[12],
|
||||
}, nil
|
||||
}
|
||||
252
vendor/github.com/prometheus/procfs/mountstats_test.go
сгенерированный
поставляемый
Обычный файл
252
vendor/github.com/prometheus/procfs/mountstats_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,252 @@
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMountStats(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
s string
|
||||
fs bool
|
||||
mounts []*Mount
|
||||
invalid bool
|
||||
}{
|
||||
{
|
||||
name: "no devices",
|
||||
s: `hello`,
|
||||
},
|
||||
{
|
||||
name: "device has too few fields",
|
||||
s: `device foo`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs BAD on / with fstype rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs mounted BAD / with fstype rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs mounted on / BAD fstype rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device incorrect format",
|
||||
s: `device rootfs mounted on / with BAD rootfs`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device rootfs cannot have stats",
|
||||
s: `device rootfs mounted on / with fstype rootfs stats`,
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with too little info",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nhello",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad bytes",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nbytes: 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad events",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nevents: 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad per-op stats",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nper-op statistics\nFOO 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport stats",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nxprt: tcp",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport version",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=foo\nxprt: tcp 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport stats version 1.0",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.0\nxprt: tcp 0 0 0 0 0 0 0 0 0 0 0 0 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "NFSv4 device with bad transport stats version 1.1",
|
||||
s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nxprt: tcp 0 0 0 0 0 0 0 0 0 0",
|
||||
invalid: true,
|
||||
},
|
||||
{
|
||||
name: "device rootfs OK",
|
||||
s: `device rootfs mounted on / with fstype rootfs`,
|
||||
mounts: []*Mount{{
|
||||
Device: "rootfs",
|
||||
Mount: "/",
|
||||
Type: "rootfs",
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "NFSv3 device with minimal stats OK",
|
||||
s: `device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.1`,
|
||||
mounts: []*Mount{{
|
||||
Device: "192.168.1.1:/srv",
|
||||
Mount: "/mnt/nfs",
|
||||
Type: "nfs",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.1",
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "fixtures OK",
|
||||
fs: true,
|
||||
mounts: []*Mount{
|
||||
{
|
||||
Device: "rootfs",
|
||||
Mount: "/",
|
||||
Type: "rootfs",
|
||||
},
|
||||
{
|
||||
Device: "sysfs",
|
||||
Mount: "/sys",
|
||||
Type: "sysfs",
|
||||
},
|
||||
{
|
||||
Device: "proc",
|
||||
Mount: "/proc",
|
||||
Type: "proc",
|
||||
},
|
||||
{
|
||||
Device: "/dev/sda1",
|
||||
Mount: "/",
|
||||
Type: "ext4",
|
||||
},
|
||||
{
|
||||
Device: "192.168.1.1:/srv/test",
|
||||
Mount: "/mnt/nfs/test",
|
||||
Type: "nfs4",
|
||||
Stats: &MountStatsNFS{
|
||||
StatVersion: "1.1",
|
||||
Age: 13968 * time.Second,
|
||||
Bytes: NFSBytesStats{
|
||||
Read: 1207640230,
|
||||
ReadTotal: 1210214218,
|
||||
ReadPages: 295483,
|
||||
},
|
||||
Events: NFSEventsStats{
|
||||
InodeRevalidate: 52,
|
||||
DnodeRevalidate: 226,
|
||||
VFSOpen: 1,
|
||||
VFSLookup: 13,
|
||||
VFSAccess: 398,
|
||||
VFSReadPages: 331,
|
||||
VFSWritePages: 47,
|
||||
VFSFlush: 77,
|
||||
VFSFileRelease: 77,
|
||||
},
|
||||
Operations: []NFSOperationStats{
|
||||
{
|
||||
Operation: "NULL",
|
||||
},
|
||||
{
|
||||
Operation: "READ",
|
||||
Requests: 1298,
|
||||
Transmissions: 1298,
|
||||
BytesSent: 207680,
|
||||
BytesReceived: 1210292152,
|
||||
CumulativeQueueTime: 6 * time.Millisecond,
|
||||
CumulativeTotalResponseTime: 79386 * time.Millisecond,
|
||||
CumulativeTotalRequestTime: 79407 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
Operation: "WRITE",
|
||||
},
|
||||
},
|
||||
Transport: NFSTransportStats{
|
||||
Port: 832,
|
||||
Connect: 1,
|
||||
IdleTime: 11 * time.Second,
|
||||
Sends: 6428,
|
||||
Receives: 6428,
|
||||
CumulativeActiveRequests: 12154,
|
||||
MaximumRPCSlotsUsed: 24,
|
||||
CumulativeSendingQueue: 26,
|
||||
CumulativePendingQueue: 5726,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Logf("[%02d] test %q", i, tt.name)
|
||||
|
||||
var mounts []*Mount
|
||||
var err error
|
||||
|
||||
if tt.s != "" {
|
||||
mounts, err = parseMountStats(strings.NewReader(tt.s))
|
||||
}
|
||||
if tt.fs {
|
||||
proc, err := FS("fixtures").NewProc(26231)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create proc: %v", err)
|
||||
}
|
||||
|
||||
mounts, err = proc.MountStats()
|
||||
}
|
||||
|
||||
if tt.invalid && err == nil {
|
||||
t.Error("expected an error, but none occurred")
|
||||
}
|
||||
if !tt.invalid && err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if want, have := tt.mounts, mounts; !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("mounts:\nwant:\n%v\nhave:\n%v", mountsStr(want), mountsStr(have))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mountsStr(mounts []*Mount) string {
|
||||
var out string
|
||||
for i, m := range mounts {
|
||||
out += fmt.Sprintf("[%d] %q on %q (%q)", i, m.Device, m.Mount, m.Type)
|
||||
|
||||
stats, ok := m.Stats.(*MountStatsNFS)
|
||||
if !ok {
|
||||
out += "\n"
|
||||
continue
|
||||
}
|
||||
|
||||
out += fmt.Sprintf("\n\t- v%s, age: %s", stats.StatVersion, stats.Age)
|
||||
out += fmt.Sprintf("\n\t- bytes: %v", stats.Bytes)
|
||||
out += fmt.Sprintf("\n\t- events: %v", stats.Events)
|
||||
out += fmt.Sprintf("\n\t- transport: %v", stats.Transport)
|
||||
out += fmt.Sprintf("\n\t- per-operation stats:")
|
||||
|
||||
for _, o := range stats.Operations {
|
||||
out += fmt.Sprintf("\n\t\t- %v", o)
|
||||
}
|
||||
|
||||
out += "\n"
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
12
vendor/github.com/prometheus/procfs/proc.go
сгенерированный
поставляемый
12
vendor/github.com/prometheus/procfs/proc.go
сгенерированный
поставляемый
@@ -192,6 +192,18 @@ func (p Proc) FileDescriptorsLen() (int, error) {
|
||||
return len(fds), nil
|
||||
}
|
||||
|
||||
// MountStats retrieves statistics and configuration for mount points in a
|
||||
// process's namespace.
|
||||
func (p Proc) MountStats() ([]*Mount, error) {
|
||||
f, err := os.Open(p.path("mountstats"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return parseMountStats(f)
|
||||
}
|
||||
|
||||
func (p Proc) fileDescriptors() ([]string, error) {
|
||||
d, err := os.Open(p.path("fd"))
|
||||
if err != nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user