From b146f770858bbc20a48ccdefa94ee236b34572b5 Mon Sep 17 00:00:00 2001 From: Luiz Ozaki Date: Mon, 27 Jun 2016 21:12:53 -0300 Subject: [PATCH 1/8] NFS input: Implemented new plugin for NFS metrics --- plugins/inputs/all/all.go | 1 + plugins/inputs/nfs/README.md | 13 ++ plugins/inputs/nfs/nfs.go | 343 +++++++++++++++++++++++++++++++++ plugins/inputs/nfs/nfs_test.go | 267 +++++++++++++++++++++++++ 4 files changed, 624 insertions(+) create mode 100644 plugins/inputs/nfs/README.md create mode 100644 plugins/inputs/nfs/nfs.go create mode 100644 plugins/inputs/nfs/nfs_test.go diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go index 529a13bae..c046d49d4 100644 --- a/plugins/inputs/all/all.go +++ b/plugins/inputs/all/all.go @@ -40,6 +40,7 @@ import ( _ "github.com/influxdata/telegraf/plugins/inputs/nats_consumer" _ "github.com/influxdata/telegraf/plugins/inputs/net_response" _ "github.com/influxdata/telegraf/plugins/inputs/nginx" + _ "github.com/influxdata/telegraf/plugins/inputs/nfs" _ "github.com/influxdata/telegraf/plugins/inputs/nsq" _ "github.com/influxdata/telegraf/plugins/inputs/nsq_consumer" _ "github.com/influxdata/telegraf/plugins/inputs/nstat" diff --git a/plugins/inputs/nfs/README.md b/plugins/inputs/nfs/README.md new file mode 100644 index 000000000..40ad19613 --- /dev/null +++ b/plugins/inputs/nfs/README.md @@ -0,0 +1,13 @@ +# Telegraf plugin: NFS + +#### Plugin arguments: +- **iostat** bool: Collect only the common iostat metrics +- **fullstat** bool: Collect all metrics available + +#### Description + +The NFS plugin collects data from /proc/self/mountstats + +#### References +[nfsiostat](http://git.linux-nfs.org/?p=steved/nfs-utils.git;a=summary) +[What is in /proc/self/mountstats for NFS mounts: an introduction](https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex) diff --git a/plugins/inputs/nfs/nfs.go b/plugins/inputs/nfs/nfs.go new file mode 100644 index 000000000..69ed58b46 --- /dev/null +++ b/plugins/inputs/nfs/nfs.go @@ -0,0 +1,343 @@ +package nfs + +import ( + "bufio" + "log" + "os" + "strconv" + "strings" + "fmt" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" +) + +type NFS struct { + Iostat bool + Fullstat bool +} + +var sampleConfig = ` + # iostat = true + # Read iostat metrics + iostat = true + # fullstat = true + # Read all metrics + fullstat = true +` + +func (n *NFS) SampleConfig() string { + return sampleConfig +} + +func (n *NFS) Description() string { + return "Read NFS metrics from /proc/self/mountstats" +} + +var eventsFields = []string{ + "inoderevalidates", + "dentryrevalidates", + "datainvalidates", + "attrinvalidates", + "vfsopen", + "vfslookup", + "vfspermission", + "vfsupdatepage", + "vfsreadpage", + "vfsreadpages", + "vfswritepage", + "vfswritepages", + "vfsreaddir", + "vfssetattr", + "vfsflush", + "vfsfsync", + "vfslock", + "vfsrelease", + "congestionwait", + "setattrtrunc", + "extendwrite", + "sillyrenames", + "shortreads", + "shortwrites", + "delay", + "pnfsreads", + "pnfswrites", +} + +var bytesFields = []string{ + "normalreadbytes", + "normalwritebytes", + "directreadbytes", + "directwritebytes", + "serverreadbytes", + "serverwritebytes", + "readpages", + "writepages", +} + +var xprtudpFields = []string{ +// "port", + "bind_count", + "rpcsends", + "rpcreceives", + "badxids", + "inflightsends", + "backlogutil", +} + +var xprttcpFields = []string{ +// "port", + "bind_count", + "connect_count", + "connect_time", + "idle_time", + "rpcsends", + "rpcreceives", + "badxids", + "inflightsends", + "backlogutil", +} + +var nfs3Fields = []string{ + "NULL", + "GETATTR", + "SETATTR", + "LOOKUP", + "ACCESS", + "READLINK", + "READ", + "WRITE", + "CREATE", + "MKDIR", + "SYMLINK", + "MKNOD", + "REMOVE", + "RMDIR", + "RENAME", + "LINK", + "READDIR", + "READDIRPLUS", + "FSSTAT", + "FSINFO", + "PATHCONF", + "COMMIT", +} + +var nfs4Fields = []string{ + "NULL", + "READ", + "WRITE", + "COMMIT", + "OPEN", + "OPEN_CONFIRM", + "OPEN_NOATTR", + "OPEN_DOWNGRADE", + "CLOSE", + "SETATTR", + "FSINFO", + "RENEW", + "SETCLIENTID", + "SETCLIENTID_CONFIRM", + "LOCK", + "LOCKT", + "LOCKU", + "ACCESS", + "GETATTR", + "LOOKUP", + "LOOKUP_ROOT", + "REMOVE", + "RENAME", + "LINK", + "SYMLINK", + "CREATE", + "PATHCONF", + "STATFS", + "READLINK", + "READDIR", + "SERVER_CAPS", + "DELEGRETURN", + "GETACL", + "SETACL", + "FS_LOCATIONS", + "RELEASE_LOCKOWNER", + "SECINFO", + "FSID_PRESENT", + "EXCHANGE_ID", + "CREATE_SESSION", + "DESTROY_SESSION", + "SEQUENCE", + "GET_LEASE_TIME", + "RECLAIM_COMPLETE", + "LAYOUTGET", + "GETDEVICEINFO", + "LAYOUTCOMMIT", + "LAYOUTRETURN", + "SECINFO_NO_NAME", + "TEST_STATEID", + "FREE_STATEID", + "GETDEVICELIST", + "BIND_CONN_TO_SESSION", + "DESTROY_CLIENTID", + "SEEK", + "ALLOCATE", + "DEALLOCATE", + "LAYOUTSTATS", + "CLONE", +} + +var nfsopFields = []string { + "ops", + "trans", + "timeouts", + "bytes_sent", + "bytes_recv", + "queue_time", + "response_time", + "total_time", +} + +func convert(line []string) []float64 { + var nline []float64 + for _, l := range line[1:] { + f, _ := strconv.ParseFloat(l, 64) + nline = append(nline, f) + } + return nline +} + +func In(list []string, val string) bool { + for _, v := range list { + if v == val { + return true + } + } + return false +} + +func (n *NFS) parseStat(mountpoint string, version string, line []string, acc telegraf.Accumulator) error { + tags := map[string]string{"mountpoint": mountpoint} + nline := convert(line) + first := strings.Replace(line[0], ":", "", 1) + + var fields = make(map[string]interface{}) + + if version == "3" || version == "4" { + if In(nfs3Fields, first) { + if first == "READ" { + fields["read_ops"] = nline[0] + fields["read_retrans"] = (nline[1] - nline[0]) + fields["read_bytes"] = (nline[3] + nline[4]) + fields["read_rtt"] = nline[6] + fields["read_exe"] = nline[7] + acc.AddFields("nfsstat_read", fields, tags) + } else if first == "WRITE" { + fields["write_ops"] = nline[0] + fields["write_retrans"] = (nline[1] - nline[0]) + fields["write_bytes"] = (nline[3] + nline[4]) + fields["write_rtt"] = nline[6] + fields["write_exe"] = nline[7] + acc.AddFields("nfsstat_write", fields, tags) + } + } + } + return nil +} + +func (n *NFS) parseData(mountpoint string, version string, line []string, acc telegraf.Accumulator) error { + tags := map[string]string{"mountpoint": mountpoint} + nline := convert(line) + first := strings.Replace(line[0], ":", "", 1) + + var fields = make(map[string]interface{}) + + if first == "events" { + for i,t := range eventsFields { + fields[t] = nline[i] + } + acc.AddFields("nfs_events", fields, tags) + } else if first == "bytes" { + for i,t := range bytesFields { + fields[t] = nline[i] + } + acc.AddFields("nfs_bytes", fields, tags) + } else if first == "xprt" { + switch line[1] { + case "tcp": { + for i,t := range xprttcpFields { + fields[t] = nline[i+2] + } + acc.AddFields("nfs_xprttcp", fields, tags) + } + case "udp": { + for i,t := range xprtudpFields { + fields[t] = nline[i+2] + } + acc.AddFields("nfs_xprtudp", fields, tags) + } + } + } else if version == "3" { + if In(nfs3Fields, first) { + for i , t := range nline { + item := fmt.Sprintf("%s_%s", first, nfsopFields[i]) + fields[item] = t + } + acc.AddFields("nfs_ops", fields, tags) + } + } else if version == "4" { + if In(nfs4Fields, first) { + for i , t := range nline { + item := fmt.Sprintf("%s_%s", first, nfsopFields[i]) + fields[item] = t + } + acc.AddFields("nfs_ops", fields, tags) + } + } + return nil +} + +func (n *NFS) processText(scanner *bufio.Scanner, acc telegraf.Accumulator) error { + var device string + var version string + for scanner.Scan() { + line := strings.Fields(scanner.Text()) + if In(line, "fstype") && In(line, "nfs") { + device = fmt.Sprintf("%s %s", line[1], line[4]) + } else if In(line, "(nfs)") { + version = strings.Split(line[5], "/")[1] + } + if (len(line) > 0) { + if n.Iostat == true { + n.parseStat(device, version, line, acc) + } + if n.Fullstat == true { + n.parseData(device, version, line, acc) + } + } + } + return nil +} + +func (n *NFS) Gather(acc telegraf.Accumulator) error { + var outerr error + + file, err := os.Open("/proc/self/mountstats") + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + n.processText(scanner, acc) + + if err := scanner.Err(); err != nil { + log.Fatal(err) + } + + return outerr +} + +func init() { + inputs.Add("nfs", func() telegraf.Input { + return &NFS{} + }) +} diff --git a/plugins/inputs/nfs/nfs_test.go b/plugins/inputs/nfs/nfs_test.go new file mode 100644 index 000000000..ba2a37dee --- /dev/null +++ b/plugins/inputs/nfs/nfs_test.go @@ -0,0 +1,267 @@ +package nfs + +import ( + "testing" + "bufio" + "strings" + "github.com/influxdata/telegraf/testutil" + +) + +const mountstatstext = `device rootfs mounted on / with fstype rootfs +device proc mounted on /proc with fstype proc +device sysfs mounted on /sys with fstype sysfs +device devtmpfs mounted on /dev with fstype devtmpfs +device devpts mounted on /dev/pts with fstype devpts +device tmpfs mounted on /dev/shm with fstype tmpfs +device /dev/loop0 mounted on /dev/.initramfs/live with fstype iso9660 +device /dev/loop6 mounted on / with fstype ext4 +device /proc/bus/usb mounted on /proc/bus/usb with fstype usbfs +device none mounted on /proc/sys/fs/binfmt_misc with fstype binfmt_misc +device /tmp mounted on /tmp with fstype tmpfs +device /home mounted on /home with fstype tmpfs +device /var mounted on /var with fstype tmpfs +device /etc mounted on /etc with fstype tmpfs +device /dev/ram1 mounted on /root with fstype ext2 +device cgroup mounted on /cgroup/cpuset with fstype cgroup +device cgroup mounted on /cgroup/cpu with fstype cgroup +device cgroup mounted on /cgroup/cpuacct with fstype cgroup +device cgroup mounted on /cgroup/memory with fstype cgroup +device cgroup mounted on /cgroup/devices with fstype cgroup +device cgroup mounted on /cgroup/freezer with fstype cgroup +device cgroup mounted on /cgroup/net_cls with fstype cgroup +device cgroup mounted on /cgroup/blkio with fstype cgroup +device sunrpc mounted on /var/lib/nfs/rpc_pipefs with fstype rpc_pipefs +device /etc/auto.misc mounted on /misc with fstype autofs +device -hosts mounted on /net with fstype autofs +device 1.2.3.4:/storage/NFS mounted on /storage/NFS with fstype nfs statvers=1.1 + opts: rw,vers=3,rsize=32768,wsize=32768,namlen=255,acregmin=60,acregmax=60,acdirmin=60,acdirmax=60,hard,nolock,noacl,nordirplus,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=1.2.3.4,mountvers=3,mountport=49193,mountproto=tcp,local_lock=all + age: 1136770 + caps: caps=0x3fe6,wtmult=512,dtsize=8192,bsize=0,namlen=255 + sec: flavor=1,pseudoflavor=1 + events: 301736 22838 410979 26188427 27525 9140 114420 30785253 5308856 5364858 30784819 79832668 170 64 18194 29294718 0 18279 0 2 785551 0 0 0 0 0 0 + bytes: 204440464584 110857586443 783170354688 296174954496 1134399088816 407107155723 85749323 30784819 + RPC iostats version: 1.0 p/v: 100003/3 (nfs) + xprt: tcp 733 1 1 0 0 96172963 96172963 0 620878754 0 690 196347132 524706275 + per-op statistics + NULL: 0 0 0 0 0 0 0 0 + GETATTR: 100 101 102 103 104 105 106 107 + SETATTR: 200 201 202 203 204 205 206 207 + LOOKUP: 300 301 302 303 304 305 306 307 + ACCESS: 400 401 402 403 404 405 406 407 + READLINK: 500 501 502 503 504 505 506 507 + READ: 600 601 602 603 604 605 606 607 + WRITE: 700 701 702 703 704 705 706 707 + CREATE: 800 801 802 803 804 805 806 807 + MKDIR: 900 901 902 903 904 905 906 907 + SYMLINK: 1000 1001 1002 1003 1004 1005 1006 1007 + MKNOD: 1100 1101 1102 1103 1104 1105 1106 1107 + REMOVE: 1200 1201 1202 1203 1204 1205 1206 1207 + RMDIR: 1300 1301 1302 1303 1304 1305 1306 1307 + RENAME: 1400 1401 1402 1403 1404 1405 1406 1407 + LINK: 1500 1501 1502 1503 1504 1505 1506 1507 + READDIR: 1600 1601 1602 1603 1604 1605 1606 1607 + READDIRPLUS: 1700 1701 1702 1703 1704 1705 1706 1707 + FSSTAT: 1800 1801 1802 1803 1804 1805 1806 1807 + FSINFO: 1900 1901 1902 1903 1904 1905 1906 1907 + PATHCONF: 2000 2001 2002 2003 2004 2005 2006 2007 + COMMIT: 2100 2101 2102 2103 2104 2105 2106 2107 + +device 2.2.2.2:/nfsdata/ mounted on /mnt with fstype nfs4 statvers=1.1 + opts: rw,vers=4,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=3.3.3.3,minorversion=0,local_lock=none + age: 19 + caps: caps=0xfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255 + nfsv4: bm0=0xfdffafff,bm1=0xf9be3e,acl=0x0 + sec: flavor=1,pseudoflavor=1 + events: 0 168232 0 0 0 10095 217808 0 2 9797 0 9739 0 0 19739 19739 0 19739 0 0 0 0 0 0 0 0 0 + bytes: 1612840960 0 0 0 627536112 0 158076 0 + RPC iostats version: 1.0 p/v: 100003/4 (nfs) + xprt: tcp 737 0 1 0 0 69698 69697 0 81817 0 2 1082 12119 + per-op statistics + NULL: 0 0 0 0 0 0 0 0 + READ: 9797 9797 0 1000 2000 71 7953 8200 + WRITE: 0 0 0 0 0 0 0 0 + COMMIT: 0 0 0 0 0 0 0 0 + OPEN: 19740 19740 0 4737600 7343280 505 3449 4172 + OPEN_CONFIRM: 10211 10211 0 1552072 694348 74 836 1008 + OPEN_NOATTR: 0 0 0 0 0 0 0 0 + OPEN_DOWNGRADE: 0 0 0 0 0 0 0 0 + CLOSE: 19739 19739 0 3316152 2605548 334 3045 3620 + SETATTR: 0 0 0 0 0 0 0 0 + FSINFO: 1 1 0 132 108 0 0 0 + RENEW: 0 0 0 0 0 0 0 0 + SETCLIENTID: 0 0 0 0 0 0 0 0 + SETCLIENTID_CONFIRM: 0 0 0 0 0 0 0 0 + LOCK: 0 0 0 0 0 0 0 0 + LOCKT: 0 0 0 0 0 0 0 0 + LOCKU: 0 0 0 0 0 0 0 0 + ACCESS: 96 96 0 14584 19584 0 8 10 + GETATTR: 1 1 0 132 188 0 0 0 + LOOKUP: 10095 10095 0 1655576 2382420 36 898 1072 + LOOKUP_ROOT: 0 0 0 0 0 0 0 0 + REMOVE: 0 0 0 0 0 0 0 0 + RENAME: 0 0 0 0 0 0 0 0 + LINK: 0 0 0 0 0 0 0 0 + SYMLINK: 0 0 0 0 0 0 0 0 + CREATE: 0 0 0 0 0 0 0 0 + PATHCONF: 1 1 0 128 72 0 0 0 + STATFS: 0 0 0 0 0 0 0 0 + READLINK: 0 0 0 0 0 0 0 0 + READDIR: 0 0 0 0 0 0 0 0 + SERVER_CAPS: 2 2 0 256 176 0 0 0 + DELEGRETURN: 0 0 0 0 0 0 0 0 + GETACL: 0 0 0 0 0 0 0 0 + SETACL: 0 0 0 0 0 0 0 0 + FS_LOCATIONS: 0 0 0 0 0 0 0 0 + RELEASE_LOCKOWNER: 0 0 0 0 0 0 0 0 + SECINFO: 0 0 0 0 0 0 0 0 + EXCHANGE_ID: 0 0 0 0 0 0 0 0 + CREATE_SESSION: 0 0 0 0 0 0 0 0 + DESTROY_SESSION: 500 501 502 503 504 505 506 507 + SEQUENCE: 0 0 0 0 0 0 0 0 + GET_LEASE_TIME: 0 0 0 0 0 0 0 0 + RECLAIM_COMPLETE: 0 0 0 0 0 0 0 0 + LAYOUTGET: 0 0 0 0 0 0 0 0 + GETDEVICEINFO: 0 0 0 0 0 0 0 0 + LAYOUTCOMMIT: 0 0 0 0 0 0 0 0 + LAYOUTRETURN: 0 0 0 0 0 0 0 0 + +` + +func TestNFSParsev3(t *testing.T) { + var acc testutil.Accumulator + + nfs := NFS{} + data := strings.Fields(" READLINK: 500 501 502 503 504 505 506 507") + nfs.parseData("1.2.3.4:/storage/NFS /storage/NFS", "3", data, &acc) + + fields_ops := map[string]interface{}{ + "READLINK_ops": float64(500), + "READLINK_trans": float64(501), + "READLINK_timeouts": float64(502), + "READLINK_bytes_sent": float64(503), + "READLINK_bytes_recv": float64(504), + "READLINK_queue_time": float64(505), + "READLINK_response_time": float64(506), + "READLINK_total_time": float64(507), + } + acc.AssertContainsFields(t, "nfs_ops", fields_ops) +} + +func TestNFSParsev4(t *testing.T) { + var acc testutil.Accumulator + + nfs := NFS{} + data := strings.Fields(" DESTROY_SESSION: 500 501 502 503 504 505 506 507") + nfs.parseData("2.2.2.2:/nfsdata/ /mnt", "4", data, &acc) + + fields_ops := map[string]interface{}{ + "DESTROY_SESSION_ops": float64(500), + "DESTROY_SESSION_trans": float64(501), + "DESTROY_SESSION_timeouts": float64(502), + "DESTROY_SESSION_bytes_sent": float64(503), + "DESTROY_SESSION_bytes_recv": float64(504), + "DESTROY_SESSION_queue_time": float64(505), + "DESTROY_SESSION_response_time": float64(506), + "DESTROY_SESSION_total_time": float64(507), + } + acc.AssertContainsFields(t, "nfs_ops", fields_ops) +} + +func TestNFSProcessStat(t *testing.T) { + var acc testutil.Accumulator + + nfs := NFS{} + nfs.iostat = true + scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) + + nfs.processText(scanner, &acc) + + fields_readstat := map[string]interface{}{ + "read_ops": float64(600), + "read_retrans": float64(1), + "read_bytes": float64(1207), + "read_rtt": float64(606), + "read_exe": float64(607), + } + fields_writestat := map[string]interface{}{ + "write_ops": float64(700), + "write_retrans": float64(1), + "write_bytes": float64(1407), + "write_rtt": float64(706), + "write_exe": float64(707), + } + tags := map[string]string { + "mountpoint": "1.2.3.4:/storage/NFS /storage/NFS", + } + acc.AssertContainsTaggedFields(t, "nfsstat_read", fields_readstat, tags) + acc.AssertContainsTaggedFields(t, "nfsstat_write", fields_writestat, tags) +} + +func TestNFSProcessFull(t *testing.T) { + var acc testutil.Accumulator + + nfs := NFS{} + nfs.fullstat = true + scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) + + nfs.processText(scanner, &acc) + + fields_events := map[string]interface{}{ + "inoderevalidates": float64(301736), + "dentryrevalidates": float64(22838), + "datainvalidates": float64(410979), + "attrinvalidates": float64(26188427), + "vfsopen": float64(27525), + "vfslookup": float64(9140), + "vfspermission": float64(114420), + "vfsupdatepage": float64(30785253), + "vfsreadpage": float64(5308856), + "vfsreadpages": float64(5364858), + "vfswritepage": float64(30784819), + "vfswritepages": float64(79832668), + "vfsreaddir": float64(170), + "vfssetattr": float64(64), + "vfsflush": float64(18194), + "vfsfsync": float64(29294718), + "vfslock": float64(0), + "vfsrelease": float64(18279), + "congestionwait": float64(0), + "setattrtrunc": float64(2), + "extendwrite": float64(785551), + "sillyrenames": float64(0), + "shortreads": float64(0), + "shortwrites": float64(0), + "delay": float64(0), + "pnfsreads": float64(0), + "pnfswrites": float64(0), + } + fields_bytes := map[string]interface{}{ + "normalreadbytes": float64(204440464584), + "normalwritebytes": float64(110857586443), + "directreadbytes": float64(783170354688), + "directwritebytes": float64(296174954496), + "serverreadbytes": float64(1134399088816), + "serverwritebytes": float64(407107155723), + "readpages": float64(85749323), + "writepages": float64(30784819), + } + fields_xprttcp := map[string]interface{}{ +// "port": float64(733), + "bind_count": float64(1), + "connect_count": float64(1), + "connect_time": float64(0), + "idle_time": float64(0), + "rpcsends": float64(96172963), + "rpcreceives": float64(96172963), + "badxids": float64(0), + "inflightsends": float64(620878754), + "backlogutil": float64(0), + } + + acc.AssertContainsFields(t, "nfs_events", fields_events) + acc.AssertContainsFields(t, "nfs_bytes", fields_bytes) + acc.AssertContainsFields(t, "nfs_xprttcp", fields_xprttcp) +} From 702aa9d4c469ab7445089895e40f02e4c3b0c78b Mon Sep 17 00:00:00 2001 From: Luiz Ozaki Date: Mon, 27 Jun 2016 21:16:55 -0300 Subject: [PATCH 2/8] Update README.md --- plugins/inputs/nfs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/inputs/nfs/README.md b/plugins/inputs/nfs/README.md index 40ad19613..6c748079c 100644 --- a/plugins/inputs/nfs/README.md +++ b/plugins/inputs/nfs/README.md @@ -10,4 +10,5 @@ The NFS plugin collects data from /proc/self/mountstats #### References [nfsiostat](http://git.linux-nfs.org/?p=steved/nfs-utils.git;a=summary) + [What is in /proc/self/mountstats for NFS mounts: an introduction](https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex) From fa0f129505c81a16ecc38828b7cb3953744950db Mon Sep 17 00:00:00 2001 From: Luiz Ozaki Date: Tue, 28 Jun 2016 12:21:46 -0300 Subject: [PATCH 3/8] typo --- plugins/inputs/nfs/nfs_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/inputs/nfs/nfs_test.go b/plugins/inputs/nfs/nfs_test.go index ba2a37dee..75d73c9d8 100644 --- a/plugins/inputs/nfs/nfs_test.go +++ b/plugins/inputs/nfs/nfs_test.go @@ -174,7 +174,7 @@ func TestNFSProcessStat(t *testing.T) { var acc testutil.Accumulator nfs := NFS{} - nfs.iostat = true + nfs.Iostat = true scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) nfs.processText(scanner, &acc) @@ -204,7 +204,7 @@ func TestNFSProcessFull(t *testing.T) { var acc testutil.Accumulator nfs := NFS{} - nfs.fullstat = true + nfs.Fullstat = true scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) nfs.processText(scanner, &acc) From ca50b092f90de2fc69b24552e379ba785dd465f1 Mon Sep 17 00:00:00 2001 From: Luiz Ozaki Date: Wed, 13 Jul 2016 18:30:45 -0300 Subject: [PATCH 4/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 53e672534..3718ebf38 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ Currently implemented sources: * [mongodb](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mongodb) * [mysql](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mysql) * [net_response](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/net_response) +* [nfs](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nfs) * [nginx](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nginx) * [nsq](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nsq) * [nstat](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nstat) From 7ea24dd953be4715363a02cc8920a38aa918b1b9 Mon Sep 17 00:00:00 2001 From: Rasmus Larsen Date: Tue, 30 Aug 2016 12:29:46 +0200 Subject: [PATCH 5/8] Change input name from NFS to NFSCLIENT. - Remove Iostat option and enable it generally. - Disable Fullstat by default. - Move mountpoint tag into two separate tags, one still called mountpoint and one called serverexport. - Update descriptions. - Fix bug that caused the tags not to show up on Ubuntu 16.04. --- plugins/inputs/all/all.go | 2 +- plugins/inputs/nfs/README.md | 14 ------ plugins/inputs/nfsclient/README.md | 14 ++++++ .../{nfs/nfs.go => nfsclient/nfsclient.go} | 48 +++++++++---------- .../nfsclient_test.go} | 32 ++++++------- 5 files changed, 53 insertions(+), 57 deletions(-) delete mode 100644 plugins/inputs/nfs/README.md create mode 100644 plugins/inputs/nfsclient/README.md rename plugins/inputs/{nfs/nfs.go => nfsclient/nfsclient.go} (85%) rename plugins/inputs/{nfs/nfs_test.go => nfsclient/nfsclient_test.go} (93%) diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go index cfa4b47ad..228e5d2b6 100644 --- a/plugins/inputs/all/all.go +++ b/plugins/inputs/all/all.go @@ -41,7 +41,7 @@ import ( _ "github.com/influxdata/telegraf/plugins/inputs/nats_consumer" _ "github.com/influxdata/telegraf/plugins/inputs/net_response" _ "github.com/influxdata/telegraf/plugins/inputs/nginx" - _ "github.com/influxdata/telegraf/plugins/inputs/nfs" + _ "github.com/influxdata/telegraf/plugins/inputs/nfsclient" _ "github.com/influxdata/telegraf/plugins/inputs/nsq" _ "github.com/influxdata/telegraf/plugins/inputs/nsq_consumer" _ "github.com/influxdata/telegraf/plugins/inputs/nstat" diff --git a/plugins/inputs/nfs/README.md b/plugins/inputs/nfs/README.md deleted file mode 100644 index 6c748079c..000000000 --- a/plugins/inputs/nfs/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Telegraf plugin: NFS - -#### Plugin arguments: -- **iostat** bool: Collect only the common iostat metrics -- **fullstat** bool: Collect all metrics available - -#### Description - -The NFS plugin collects data from /proc/self/mountstats - -#### References -[nfsiostat](http://git.linux-nfs.org/?p=steved/nfs-utils.git;a=summary) - -[What is in /proc/self/mountstats for NFS mounts: an introduction](https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex) diff --git a/plugins/inputs/nfsclient/README.md b/plugins/inputs/nfsclient/README.md new file mode 100644 index 000000000..7f514c3be --- /dev/null +++ b/plugins/inputs/nfsclient/README.md @@ -0,0 +1,14 @@ +# Telegraf plugin: NFSCLIENT + +#### Plugin arguments: +- **fullstat** bool: Collect per-operation statistics + +#### Description + +The NFSCLIENT plugin collects data from /proc/self/mountstats, by default it will only include a quite limited set of IO metrics. +If fullstat is set, it will collect a lot of per-operation statistics. + +#### References +[nfsiostat](http://git.linux-nfs.org/?p=steved/nfs-utils.git;a=summary) + +[What is in /proc/self/mountstats for NFS mounts: an introduction](https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex) diff --git a/plugins/inputs/nfs/nfs.go b/plugins/inputs/nfsclient/nfsclient.go similarity index 85% rename from plugins/inputs/nfs/nfs.go rename to plugins/inputs/nfsclient/nfsclient.go index 69ed58b46..3365040bd 100644 --- a/plugins/inputs/nfs/nfs.go +++ b/plugins/inputs/nfsclient/nfsclient.go @@ -1,4 +1,4 @@ -package nfs +package nfsclient import ( "bufio" @@ -12,26 +12,22 @@ import ( "github.com/influxdata/telegraf/plugins/inputs" ) -type NFS struct { - Iostat bool +type NFSCLIENT struct { Fullstat bool } var sampleConfig = ` - # iostat = true - # Read iostat metrics - iostat = true # fullstat = true - # Read all metrics - fullstat = true + # Read more low-level metrics + fullstat = false ` -func (n *NFS) SampleConfig() string { +func (n *NFSCLIENT) SampleConfig() string { return sampleConfig } -func (n *NFS) Description() string { - return "Read NFS metrics from /proc/self/mountstats" +func (n *NFSCLIENT) Description() string { + return "Read per-mount NFS metrics from /proc/self/mountstats" } var eventsFields = []string{ @@ -214,8 +210,8 @@ func In(list []string, val string) bool { return false } -func (n *NFS) parseStat(mountpoint string, version string, line []string, acc telegraf.Accumulator) error { - tags := map[string]string{"mountpoint": mountpoint} +func (n *NFSCLIENT) parseStat(mountpoint string, export string, version string, line []string, acc telegraf.Accumulator) error { + tags := map[string]string{"mountpoint": mountpoint, "serverexport": export} nline := convert(line) first := strings.Replace(line[0], ":", "", 1) @@ -243,8 +239,8 @@ func (n *NFS) parseStat(mountpoint string, version string, line []string, acc te return nil } -func (n *NFS) parseData(mountpoint string, version string, line []string, acc telegraf.Accumulator) error { - tags := map[string]string{"mountpoint": mountpoint} +func (n *NFSCLIENT) parseData(mountpoint string, export string, version string, line []string, acc telegraf.Accumulator) error { + tags := map[string]string{"mountpoint": mountpoint, "serverexport": export} nline := convert(line) first := strings.Replace(line[0], ":", "", 1) @@ -295,29 +291,29 @@ func (n *NFS) parseData(mountpoint string, version string, line []string, acc te return nil } -func (n *NFS) processText(scanner *bufio.Scanner, acc telegraf.Accumulator) error { +func (n *NFSCLIENT) processText(scanner *bufio.Scanner, acc telegraf.Accumulator) error { var device string var version string + var export string for scanner.Scan() { line := strings.Fields(scanner.Text()) - if In(line, "fstype") && In(line, "nfs") { - device = fmt.Sprintf("%s %s", line[1], line[4]) - } else if In(line, "(nfs)") { + if In(line, "fstype") && In(line, "nfs") || In(line, "nfs4") { + device = line[4] + export = line[1] + } else if In(line, "(nfs)") || In(line, "(nfs4)") { version = strings.Split(line[5], "/")[1] } if (len(line) > 0) { - if n.Iostat == true { - n.parseStat(device, version, line, acc) - } + n.parseStat(device, export, version, line, acc) if n.Fullstat == true { - n.parseData(device, version, line, acc) + n.parseData(device, export, version, line, acc) } } } return nil } -func (n *NFS) Gather(acc telegraf.Accumulator) error { +func (n *NFSCLIENT) Gather(acc telegraf.Accumulator) error { var outerr error file, err := os.Open("/proc/self/mountstats") @@ -337,7 +333,7 @@ func (n *NFS) Gather(acc telegraf.Accumulator) error { } func init() { - inputs.Add("nfs", func() telegraf.Input { - return &NFS{} + inputs.Add("nfsclient", func() telegraf.Input { + return &NFSCLIENT{} }) } diff --git a/plugins/inputs/nfs/nfs_test.go b/plugins/inputs/nfsclient/nfsclient_test.go similarity index 93% rename from plugins/inputs/nfs/nfs_test.go rename to plugins/inputs/nfsclient/nfsclient_test.go index 75d73c9d8..248e9301a 100644 --- a/plugins/inputs/nfs/nfs_test.go +++ b/plugins/inputs/nfsclient/nfsclient_test.go @@ -1,4 +1,4 @@ -package nfs +package nfsclient import ( "testing" @@ -34,7 +34,7 @@ device cgroup mounted on /cgroup/blkio with fstype cgroup device sunrpc mounted on /var/lib/nfs/rpc_pipefs with fstype rpc_pipefs device /etc/auto.misc mounted on /misc with fstype autofs device -hosts mounted on /net with fstype autofs -device 1.2.3.4:/storage/NFS mounted on /storage/NFS with fstype nfs statvers=1.1 +device 1.2.3.4:/storage/NFSCLIENT mounted on /storage/NFS with fstype nfs statvers=1.1 opts: rw,vers=3,rsize=32768,wsize=32768,namlen=255,acregmin=60,acregmax=60,acdirmin=60,acdirmax=60,hard,nolock,noacl,nordirplus,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=1.2.3.4,mountvers=3,mountport=49193,mountproto=tcp,local_lock=all age: 1136770 caps: caps=0x3fe6,wtmult=512,dtsize=8192,bsize=0,namlen=255 @@ -130,12 +130,12 @@ device 2.2.2.2:/nfsdata/ mounted on /mnt with fstype nfs4 statvers=1.1 ` -func TestNFSParsev3(t *testing.T) { +func TestNFSCLIENTParsev3(t *testing.T) { var acc testutil.Accumulator - nfs := NFS{} + nfsclient := NFSCLIENT{} data := strings.Fields(" READLINK: 500 501 502 503 504 505 506 507") - nfs.parseData("1.2.3.4:/storage/NFS /storage/NFS", "3", data, &acc) + nfsclient.parseData("1.2.3.4:/storage/NFSCLIENT /storage/NFS", "3", data, &acc) fields_ops := map[string]interface{}{ "READLINK_ops": float64(500), @@ -150,10 +150,10 @@ func TestNFSParsev3(t *testing.T) { acc.AssertContainsFields(t, "nfs_ops", fields_ops) } -func TestNFSParsev4(t *testing.T) { +func TestNFSCLIENTParsev4(t *testing.T) { var acc testutil.Accumulator - nfs := NFS{} + nfsclient := NFSCLIENT{} data := strings.Fields(" DESTROY_SESSION: 500 501 502 503 504 505 506 507") nfs.parseData("2.2.2.2:/nfsdata/ /mnt", "4", data, &acc) @@ -170,14 +170,14 @@ func TestNFSParsev4(t *testing.T) { acc.AssertContainsFields(t, "nfs_ops", fields_ops) } -func TestNFSProcessStat(t *testing.T) { +func TestNFSCLIENTProcessStat(t *testing.T) { var acc testutil.Accumulator - nfs := NFS{} - nfs.Iostat = true + nfsclient := NFSCLIENT{} + nfsclient.Iostat = true scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) - nfs.processText(scanner, &acc) + nfsclient.processText(scanner, &acc) fields_readstat := map[string]interface{}{ "read_ops": float64(600), @@ -194,20 +194,20 @@ func TestNFSProcessStat(t *testing.T) { "write_exe": float64(707), } tags := map[string]string { - "mountpoint": "1.2.3.4:/storage/NFS /storage/NFS", + "mountpoint": "1.2.3.4:/storage/NFSCLIENT /storage/NFS", } acc.AssertContainsTaggedFields(t, "nfsstat_read", fields_readstat, tags) acc.AssertContainsTaggedFields(t, "nfsstat_write", fields_writestat, tags) } -func TestNFSProcessFull(t *testing.T) { +func TestNFSCLIENTProcessFull(t *testing.T) { var acc testutil.Accumulator - nfs := NFS{} - nfs.Fullstat = true + nfsclient := NFSCLIENT{} + nfsclient.Fullstat = true scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) - nfs.processText(scanner, &acc) + nfsclient.processText(scanner, &acc) fields_events := map[string]interface{}{ "inoderevalidates": float64(301736), From 4fc43dd55e162e936a527f4f193460b333efca81 Mon Sep 17 00:00:00 2001 From: Rasmus Larsen Date: Tue, 30 Aug 2016 12:50:42 +0200 Subject: [PATCH 6/8] Correct NFS to NFSCLIENT in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc5abbe60..b8747a312 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ Currently implemented sources: * [mongodb](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mongodb) * [mysql](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/mysql) * [net_response](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/net_response) -* [nfs](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nfs) +* [nfsclient](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nfsclient) * [nginx](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nginx) * [nsq](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nsq) * [nstat](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/nstat) From a9f039e6a453be78fb2be1ba96982af2d0b7fc92 Mon Sep 17 00:00:00 2001 From: Rasmus Larsen Date: Tue, 30 Aug 2016 12:55:02 +0200 Subject: [PATCH 7/8] Fix formatting. --- plugins/inputs/all/all.go | 2 +- plugins/inputs/nfsclient/nfsclient.go | 542 +++++++++++---------- plugins/inputs/nfsclient/nfsclient_test.go | 233 +++++---- 3 files changed, 389 insertions(+), 388 deletions(-) diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go index 228e5d2b6..a3da96aa0 100644 --- a/plugins/inputs/all/all.go +++ b/plugins/inputs/all/all.go @@ -40,8 +40,8 @@ import ( _ "github.com/influxdata/telegraf/plugins/inputs/mysql" _ "github.com/influxdata/telegraf/plugins/inputs/nats_consumer" _ "github.com/influxdata/telegraf/plugins/inputs/net_response" - _ "github.com/influxdata/telegraf/plugins/inputs/nginx" _ "github.com/influxdata/telegraf/plugins/inputs/nfsclient" + _ "github.com/influxdata/telegraf/plugins/inputs/nginx" _ "github.com/influxdata/telegraf/plugins/inputs/nsq" _ "github.com/influxdata/telegraf/plugins/inputs/nsq_consumer" _ "github.com/influxdata/telegraf/plugins/inputs/nstat" diff --git a/plugins/inputs/nfsclient/nfsclient.go b/plugins/inputs/nfsclient/nfsclient.go index 3365040bd..c86044856 100644 --- a/plugins/inputs/nfsclient/nfsclient.go +++ b/plugins/inputs/nfsclient/nfsclient.go @@ -1,19 +1,19 @@ package nfsclient import ( - "bufio" - "log" - "os" - "strconv" - "strings" - "fmt" + "bufio" + "fmt" + "log" + "os" + "strconv" + "strings" - "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/plugins/inputs" + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" ) type NFSCLIENT struct { - Fullstat bool + Fullstat bool } var sampleConfig = ` @@ -23,317 +23,319 @@ var sampleConfig = ` ` func (n *NFSCLIENT) SampleConfig() string { - return sampleConfig + return sampleConfig } func (n *NFSCLIENT) Description() string { - return "Read per-mount NFS metrics from /proc/self/mountstats" + return "Read per-mount NFS metrics from /proc/self/mountstats" } var eventsFields = []string{ - "inoderevalidates", - "dentryrevalidates", - "datainvalidates", - "attrinvalidates", - "vfsopen", - "vfslookup", - "vfspermission", - "vfsupdatepage", - "vfsreadpage", - "vfsreadpages", - "vfswritepage", - "vfswritepages", - "vfsreaddir", - "vfssetattr", - "vfsflush", - "vfsfsync", - "vfslock", - "vfsrelease", - "congestionwait", - "setattrtrunc", - "extendwrite", - "sillyrenames", - "shortreads", - "shortwrites", - "delay", - "pnfsreads", - "pnfswrites", + "inoderevalidates", + "dentryrevalidates", + "datainvalidates", + "attrinvalidates", + "vfsopen", + "vfslookup", + "vfspermission", + "vfsupdatepage", + "vfsreadpage", + "vfsreadpages", + "vfswritepage", + "vfswritepages", + "vfsreaddir", + "vfssetattr", + "vfsflush", + "vfsfsync", + "vfslock", + "vfsrelease", + "congestionwait", + "setattrtrunc", + "extendwrite", + "sillyrenames", + "shortreads", + "shortwrites", + "delay", + "pnfsreads", + "pnfswrites", } var bytesFields = []string{ - "normalreadbytes", - "normalwritebytes", - "directreadbytes", - "directwritebytes", - "serverreadbytes", - "serverwritebytes", - "readpages", - "writepages", + "normalreadbytes", + "normalwritebytes", + "directreadbytes", + "directwritebytes", + "serverreadbytes", + "serverwritebytes", + "readpages", + "writepages", } var xprtudpFields = []string{ -// "port", - "bind_count", - "rpcsends", - "rpcreceives", - "badxids", - "inflightsends", - "backlogutil", + // "port", + "bind_count", + "rpcsends", + "rpcreceives", + "badxids", + "inflightsends", + "backlogutil", } var xprttcpFields = []string{ -// "port", - "bind_count", - "connect_count", - "connect_time", - "idle_time", - "rpcsends", - "rpcreceives", - "badxids", - "inflightsends", - "backlogutil", + // "port", + "bind_count", + "connect_count", + "connect_time", + "idle_time", + "rpcsends", + "rpcreceives", + "badxids", + "inflightsends", + "backlogutil", } var nfs3Fields = []string{ - "NULL", - "GETATTR", - "SETATTR", - "LOOKUP", - "ACCESS", - "READLINK", - "READ", - "WRITE", - "CREATE", - "MKDIR", - "SYMLINK", - "MKNOD", - "REMOVE", - "RMDIR", - "RENAME", - "LINK", - "READDIR", - "READDIRPLUS", - "FSSTAT", - "FSINFO", - "PATHCONF", - "COMMIT", + "NULL", + "GETATTR", + "SETATTR", + "LOOKUP", + "ACCESS", + "READLINK", + "READ", + "WRITE", + "CREATE", + "MKDIR", + "SYMLINK", + "MKNOD", + "REMOVE", + "RMDIR", + "RENAME", + "LINK", + "READDIR", + "READDIRPLUS", + "FSSTAT", + "FSINFO", + "PATHCONF", + "COMMIT", } var nfs4Fields = []string{ - "NULL", - "READ", - "WRITE", - "COMMIT", - "OPEN", - "OPEN_CONFIRM", - "OPEN_NOATTR", - "OPEN_DOWNGRADE", - "CLOSE", - "SETATTR", - "FSINFO", - "RENEW", - "SETCLIENTID", - "SETCLIENTID_CONFIRM", - "LOCK", - "LOCKT", - "LOCKU", - "ACCESS", - "GETATTR", - "LOOKUP", - "LOOKUP_ROOT", - "REMOVE", - "RENAME", - "LINK", - "SYMLINK", - "CREATE", - "PATHCONF", - "STATFS", - "READLINK", - "READDIR", - "SERVER_CAPS", - "DELEGRETURN", - "GETACL", - "SETACL", - "FS_LOCATIONS", - "RELEASE_LOCKOWNER", - "SECINFO", - "FSID_PRESENT", - "EXCHANGE_ID", - "CREATE_SESSION", - "DESTROY_SESSION", - "SEQUENCE", - "GET_LEASE_TIME", - "RECLAIM_COMPLETE", - "LAYOUTGET", - "GETDEVICEINFO", - "LAYOUTCOMMIT", - "LAYOUTRETURN", - "SECINFO_NO_NAME", - "TEST_STATEID", - "FREE_STATEID", - "GETDEVICELIST", - "BIND_CONN_TO_SESSION", - "DESTROY_CLIENTID", - "SEEK", - "ALLOCATE", - "DEALLOCATE", - "LAYOUTSTATS", - "CLONE", + "NULL", + "READ", + "WRITE", + "COMMIT", + "OPEN", + "OPEN_CONFIRM", + "OPEN_NOATTR", + "OPEN_DOWNGRADE", + "CLOSE", + "SETATTR", + "FSINFO", + "RENEW", + "SETCLIENTID", + "SETCLIENTID_CONFIRM", + "LOCK", + "LOCKT", + "LOCKU", + "ACCESS", + "GETATTR", + "LOOKUP", + "LOOKUP_ROOT", + "REMOVE", + "RENAME", + "LINK", + "SYMLINK", + "CREATE", + "PATHCONF", + "STATFS", + "READLINK", + "READDIR", + "SERVER_CAPS", + "DELEGRETURN", + "GETACL", + "SETACL", + "FS_LOCATIONS", + "RELEASE_LOCKOWNER", + "SECINFO", + "FSID_PRESENT", + "EXCHANGE_ID", + "CREATE_SESSION", + "DESTROY_SESSION", + "SEQUENCE", + "GET_LEASE_TIME", + "RECLAIM_COMPLETE", + "LAYOUTGET", + "GETDEVICEINFO", + "LAYOUTCOMMIT", + "LAYOUTRETURN", + "SECINFO_NO_NAME", + "TEST_STATEID", + "FREE_STATEID", + "GETDEVICELIST", + "BIND_CONN_TO_SESSION", + "DESTROY_CLIENTID", + "SEEK", + "ALLOCATE", + "DEALLOCATE", + "LAYOUTSTATS", + "CLONE", } -var nfsopFields = []string { - "ops", - "trans", - "timeouts", - "bytes_sent", - "bytes_recv", - "queue_time", - "response_time", - "total_time", +var nfsopFields = []string{ + "ops", + "trans", + "timeouts", + "bytes_sent", + "bytes_recv", + "queue_time", + "response_time", + "total_time", } func convert(line []string) []float64 { - var nline []float64 - for _, l := range line[1:] { - f, _ := strconv.ParseFloat(l, 64) - nline = append(nline, f) - } - return nline + var nline []float64 + for _, l := range line[1:] { + f, _ := strconv.ParseFloat(l, 64) + nline = append(nline, f) + } + return nline } func In(list []string, val string) bool { - for _, v := range list { - if v == val { - return true - } - } - return false + for _, v := range list { + if v == val { + return true + } + } + return false } func (n *NFSCLIENT) parseStat(mountpoint string, export string, version string, line []string, acc telegraf.Accumulator) error { - tags := map[string]string{"mountpoint": mountpoint, "serverexport": export} - nline := convert(line) - first := strings.Replace(line[0], ":", "", 1) + tags := map[string]string{"mountpoint": mountpoint, "serverexport": export} + nline := convert(line) + first := strings.Replace(line[0], ":", "", 1) - var fields = make(map[string]interface{}) + var fields = make(map[string]interface{}) - if version == "3" || version == "4" { - if In(nfs3Fields, first) { - if first == "READ" { - fields["read_ops"] = nline[0] - fields["read_retrans"] = (nline[1] - nline[0]) - fields["read_bytes"] = (nline[3] + nline[4]) - fields["read_rtt"] = nline[6] - fields["read_exe"] = nline[7] - acc.AddFields("nfsstat_read", fields, tags) - } else if first == "WRITE" { - fields["write_ops"] = nline[0] - fields["write_retrans"] = (nline[1] - nline[0]) - fields["write_bytes"] = (nline[3] + nline[4]) - fields["write_rtt"] = nline[6] - fields["write_exe"] = nline[7] - acc.AddFields("nfsstat_write", fields, tags) - } - } - } - return nil + if version == "3" || version == "4" { + if In(nfs3Fields, first) { + if first == "READ" { + fields["read_ops"] = nline[0] + fields["read_retrans"] = (nline[1] - nline[0]) + fields["read_bytes"] = (nline[3] + nline[4]) + fields["read_rtt"] = nline[6] + fields["read_exe"] = nline[7] + acc.AddFields("nfsstat_read", fields, tags) + } else if first == "WRITE" { + fields["write_ops"] = nline[0] + fields["write_retrans"] = (nline[1] - nline[0]) + fields["write_bytes"] = (nline[3] + nline[4]) + fields["write_rtt"] = nline[6] + fields["write_exe"] = nline[7] + acc.AddFields("nfsstat_write", fields, tags) + } + } + } + return nil } func (n *NFSCLIENT) parseData(mountpoint string, export string, version string, line []string, acc telegraf.Accumulator) error { - tags := map[string]string{"mountpoint": mountpoint, "serverexport": export} - nline := convert(line) - first := strings.Replace(line[0], ":", "", 1) + tags := map[string]string{"mountpoint": mountpoint, "serverexport": export} + nline := convert(line) + first := strings.Replace(line[0], ":", "", 1) - var fields = make(map[string]interface{}) + var fields = make(map[string]interface{}) - if first == "events" { - for i,t := range eventsFields { - fields[t] = nline[i] - } - acc.AddFields("nfs_events", fields, tags) - } else if first == "bytes" { - for i,t := range bytesFields { - fields[t] = nline[i] - } - acc.AddFields("nfs_bytes", fields, tags) - } else if first == "xprt" { - switch line[1] { - case "tcp": { - for i,t := range xprttcpFields { - fields[t] = nline[i+2] - } - acc.AddFields("nfs_xprttcp", fields, tags) - } - case "udp": { - for i,t := range xprtudpFields { - fields[t] = nline[i+2] - } - acc.AddFields("nfs_xprtudp", fields, tags) - } - } - } else if version == "3" { - if In(nfs3Fields, first) { - for i , t := range nline { - item := fmt.Sprintf("%s_%s", first, nfsopFields[i]) - fields[item] = t - } - acc.AddFields("nfs_ops", fields, tags) - } - } else if version == "4" { - if In(nfs4Fields, first) { - for i , t := range nline { - item := fmt.Sprintf("%s_%s", first, nfsopFields[i]) - fields[item] = t - } - acc.AddFields("nfs_ops", fields, tags) - } - } - return nil + if first == "events" { + for i, t := range eventsFields { + fields[t] = nline[i] + } + acc.AddFields("nfs_events", fields, tags) + } else if first == "bytes" { + for i, t := range bytesFields { + fields[t] = nline[i] + } + acc.AddFields("nfs_bytes", fields, tags) + } else if first == "xprt" { + switch line[1] { + case "tcp": + { + for i, t := range xprttcpFields { + fields[t] = nline[i+2] + } + acc.AddFields("nfs_xprttcp", fields, tags) + } + case "udp": + { + for i, t := range xprtudpFields { + fields[t] = nline[i+2] + } + acc.AddFields("nfs_xprtudp", fields, tags) + } + } + } else if version == "3" { + if In(nfs3Fields, first) { + for i, t := range nline { + item := fmt.Sprintf("%s_%s", first, nfsopFields[i]) + fields[item] = t + } + acc.AddFields("nfs_ops", fields, tags) + } + } else if version == "4" { + if In(nfs4Fields, first) { + for i, t := range nline { + item := fmt.Sprintf("%s_%s", first, nfsopFields[i]) + fields[item] = t + } + acc.AddFields("nfs_ops", fields, tags) + } + } + return nil } func (n *NFSCLIENT) processText(scanner *bufio.Scanner, acc telegraf.Accumulator) error { - var device string - var version string - var export string - for scanner.Scan() { - line := strings.Fields(scanner.Text()) - if In(line, "fstype") && In(line, "nfs") || In(line, "nfs4") { - device = line[4] - export = line[1] - } else if In(line, "(nfs)") || In(line, "(nfs4)") { - version = strings.Split(line[5], "/")[1] - } - if (len(line) > 0) { - n.parseStat(device, export, version, line, acc) - if n.Fullstat == true { - n.parseData(device, export, version, line, acc) - } - } - } - return nil + var device string + var version string + var export string + for scanner.Scan() { + line := strings.Fields(scanner.Text()) + if In(line, "fstype") && In(line, "nfs") || In(line, "nfs4") { + device = line[4] + export = line[1] + } else if In(line, "(nfs)") || In(line, "(nfs4)") { + version = strings.Split(line[5], "/")[1] + } + if len(line) > 0 { + n.parseStat(device, export, version, line, acc) + if n.Fullstat == true { + n.parseData(device, export, version, line, acc) + } + } + } + return nil } func (n *NFSCLIENT) Gather(acc telegraf.Accumulator) error { - var outerr error + var outerr error - file, err := os.Open("/proc/self/mountstats") - if err != nil { - log.Fatal(err) - } - defer file.Close() + file, err := os.Open("/proc/self/mountstats") + if err != nil { + log.Fatal(err) + } + defer file.Close() - scanner := bufio.NewScanner(file) - n.processText(scanner, acc) + scanner := bufio.NewScanner(file) + n.processText(scanner, acc) - if err := scanner.Err(); err != nil { - log.Fatal(err) - } + if err := scanner.Err(); err != nil { + log.Fatal(err) + } - return outerr + return outerr } func init() { - inputs.Add("nfsclient", func() telegraf.Input { - return &NFSCLIENT{} - }) + inputs.Add("nfsclient", func() telegraf.Input { + return &NFSCLIENT{} + }) } diff --git a/plugins/inputs/nfsclient/nfsclient_test.go b/plugins/inputs/nfsclient/nfsclient_test.go index 248e9301a..eeadc6802 100644 --- a/plugins/inputs/nfsclient/nfsclient_test.go +++ b/plugins/inputs/nfsclient/nfsclient_test.go @@ -1,11 +1,10 @@ package nfsclient import ( - "testing" - "bufio" - "strings" + "bufio" "github.com/influxdata/telegraf/testutil" - + "strings" + "testing" ) const mountstatstext = `device rootfs mounted on / with fstype rootfs @@ -131,137 +130,137 @@ device 2.2.2.2:/nfsdata/ mounted on /mnt with fstype nfs4 statvers=1.1 ` func TestNFSCLIENTParsev3(t *testing.T) { - var acc testutil.Accumulator + var acc testutil.Accumulator - nfsclient := NFSCLIENT{} - data := strings.Fields(" READLINK: 500 501 502 503 504 505 506 507") - nfsclient.parseData("1.2.3.4:/storage/NFSCLIENT /storage/NFS", "3", data, &acc) + nfsclient := NFSCLIENT{} + data := strings.Fields(" READLINK: 500 501 502 503 504 505 506 507") + nfsclient.parseData("1.2.3.4:/storage/NFSCLIENT /storage/NFS", "3", data, &acc) - fields_ops := map[string]interface{}{ - "READLINK_ops": float64(500), - "READLINK_trans": float64(501), - "READLINK_timeouts": float64(502), - "READLINK_bytes_sent": float64(503), - "READLINK_bytes_recv": float64(504), - "READLINK_queue_time": float64(505), - "READLINK_response_time": float64(506), - "READLINK_total_time": float64(507), - } - acc.AssertContainsFields(t, "nfs_ops", fields_ops) + fields_ops := map[string]interface{}{ + "READLINK_ops": float64(500), + "READLINK_trans": float64(501), + "READLINK_timeouts": float64(502), + "READLINK_bytes_sent": float64(503), + "READLINK_bytes_recv": float64(504), + "READLINK_queue_time": float64(505), + "READLINK_response_time": float64(506), + "READLINK_total_time": float64(507), + } + acc.AssertContainsFields(t, "nfs_ops", fields_ops) } func TestNFSCLIENTParsev4(t *testing.T) { - var acc testutil.Accumulator + var acc testutil.Accumulator - nfsclient := NFSCLIENT{} - data := strings.Fields(" DESTROY_SESSION: 500 501 502 503 504 505 506 507") - nfs.parseData("2.2.2.2:/nfsdata/ /mnt", "4", data, &acc) + nfsclient := NFSCLIENT{} + data := strings.Fields(" DESTROY_SESSION: 500 501 502 503 504 505 506 507") + nfs.parseData("2.2.2.2:/nfsdata/ /mnt", "4", data, &acc) - fields_ops := map[string]interface{}{ - "DESTROY_SESSION_ops": float64(500), - "DESTROY_SESSION_trans": float64(501), - "DESTROY_SESSION_timeouts": float64(502), - "DESTROY_SESSION_bytes_sent": float64(503), - "DESTROY_SESSION_bytes_recv": float64(504), - "DESTROY_SESSION_queue_time": float64(505), - "DESTROY_SESSION_response_time": float64(506), - "DESTROY_SESSION_total_time": float64(507), - } - acc.AssertContainsFields(t, "nfs_ops", fields_ops) + fields_ops := map[string]interface{}{ + "DESTROY_SESSION_ops": float64(500), + "DESTROY_SESSION_trans": float64(501), + "DESTROY_SESSION_timeouts": float64(502), + "DESTROY_SESSION_bytes_sent": float64(503), + "DESTROY_SESSION_bytes_recv": float64(504), + "DESTROY_SESSION_queue_time": float64(505), + "DESTROY_SESSION_response_time": float64(506), + "DESTROY_SESSION_total_time": float64(507), + } + acc.AssertContainsFields(t, "nfs_ops", fields_ops) } func TestNFSCLIENTProcessStat(t *testing.T) { - var acc testutil.Accumulator + var acc testutil.Accumulator - nfsclient := NFSCLIENT{} - nfsclient.Iostat = true - scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) + nfsclient := NFSCLIENT{} + nfsclient.Iostat = true + scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) - nfsclient.processText(scanner, &acc) + nfsclient.processText(scanner, &acc) - fields_readstat := map[string]interface{}{ - "read_ops": float64(600), - "read_retrans": float64(1), - "read_bytes": float64(1207), - "read_rtt": float64(606), - "read_exe": float64(607), - } - fields_writestat := map[string]interface{}{ - "write_ops": float64(700), - "write_retrans": float64(1), - "write_bytes": float64(1407), - "write_rtt": float64(706), - "write_exe": float64(707), - } - tags := map[string]string { - "mountpoint": "1.2.3.4:/storage/NFSCLIENT /storage/NFS", - } - acc.AssertContainsTaggedFields(t, "nfsstat_read", fields_readstat, tags) - acc.AssertContainsTaggedFields(t, "nfsstat_write", fields_writestat, tags) + fields_readstat := map[string]interface{}{ + "read_ops": float64(600), + "read_retrans": float64(1), + "read_bytes": float64(1207), + "read_rtt": float64(606), + "read_exe": float64(607), + } + fields_writestat := map[string]interface{}{ + "write_ops": float64(700), + "write_retrans": float64(1), + "write_bytes": float64(1407), + "write_rtt": float64(706), + "write_exe": float64(707), + } + tags := map[string]string{ + "mountpoint": "1.2.3.4:/storage/NFSCLIENT /storage/NFS", + } + acc.AssertContainsTaggedFields(t, "nfsstat_read", fields_readstat, tags) + acc.AssertContainsTaggedFields(t, "nfsstat_write", fields_writestat, tags) } func TestNFSCLIENTProcessFull(t *testing.T) { - var acc testutil.Accumulator + var acc testutil.Accumulator - nfsclient := NFSCLIENT{} - nfsclient.Fullstat = true - scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) + nfsclient := NFSCLIENT{} + nfsclient.Fullstat = true + scanner := bufio.NewScanner(strings.NewReader(mountstatstext)) - nfsclient.processText(scanner, &acc) + nfsclient.processText(scanner, &acc) - fields_events := map[string]interface{}{ - "inoderevalidates": float64(301736), - "dentryrevalidates": float64(22838), - "datainvalidates": float64(410979), - "attrinvalidates": float64(26188427), - "vfsopen": float64(27525), - "vfslookup": float64(9140), - "vfspermission": float64(114420), - "vfsupdatepage": float64(30785253), - "vfsreadpage": float64(5308856), - "vfsreadpages": float64(5364858), - "vfswritepage": float64(30784819), - "vfswritepages": float64(79832668), - "vfsreaddir": float64(170), - "vfssetattr": float64(64), - "vfsflush": float64(18194), - "vfsfsync": float64(29294718), - "vfslock": float64(0), - "vfsrelease": float64(18279), - "congestionwait": float64(0), - "setattrtrunc": float64(2), - "extendwrite": float64(785551), - "sillyrenames": float64(0), - "shortreads": float64(0), - "shortwrites": float64(0), - "delay": float64(0), - "pnfsreads": float64(0), - "pnfswrites": float64(0), - } - fields_bytes := map[string]interface{}{ - "normalreadbytes": float64(204440464584), - "normalwritebytes": float64(110857586443), - "directreadbytes": float64(783170354688), - "directwritebytes": float64(296174954496), - "serverreadbytes": float64(1134399088816), - "serverwritebytes": float64(407107155723), - "readpages": float64(85749323), - "writepages": float64(30784819), - } - fields_xprttcp := map[string]interface{}{ -// "port": float64(733), - "bind_count": float64(1), - "connect_count": float64(1), - "connect_time": float64(0), - "idle_time": float64(0), - "rpcsends": float64(96172963), - "rpcreceives": float64(96172963), - "badxids": float64(0), - "inflightsends": float64(620878754), - "backlogutil": float64(0), - } + fields_events := map[string]interface{}{ + "inoderevalidates": float64(301736), + "dentryrevalidates": float64(22838), + "datainvalidates": float64(410979), + "attrinvalidates": float64(26188427), + "vfsopen": float64(27525), + "vfslookup": float64(9140), + "vfspermission": float64(114420), + "vfsupdatepage": float64(30785253), + "vfsreadpage": float64(5308856), + "vfsreadpages": float64(5364858), + "vfswritepage": float64(30784819), + "vfswritepages": float64(79832668), + "vfsreaddir": float64(170), + "vfssetattr": float64(64), + "vfsflush": float64(18194), + "vfsfsync": float64(29294718), + "vfslock": float64(0), + "vfsrelease": float64(18279), + "congestionwait": float64(0), + "setattrtrunc": float64(2), + "extendwrite": float64(785551), + "sillyrenames": float64(0), + "shortreads": float64(0), + "shortwrites": float64(0), + "delay": float64(0), + "pnfsreads": float64(0), + "pnfswrites": float64(0), + } + fields_bytes := map[string]interface{}{ + "normalreadbytes": float64(204440464584), + "normalwritebytes": float64(110857586443), + "directreadbytes": float64(783170354688), + "directwritebytes": float64(296174954496), + "serverreadbytes": float64(1134399088816), + "serverwritebytes": float64(407107155723), + "readpages": float64(85749323), + "writepages": float64(30784819), + } + fields_xprttcp := map[string]interface{}{ + // "port": float64(733), + "bind_count": float64(1), + "connect_count": float64(1), + "connect_time": float64(0), + "idle_time": float64(0), + "rpcsends": float64(96172963), + "rpcreceives": float64(96172963), + "badxids": float64(0), + "inflightsends": float64(620878754), + "backlogutil": float64(0), + } - acc.AssertContainsFields(t, "nfs_events", fields_events) - acc.AssertContainsFields(t, "nfs_bytes", fields_bytes) - acc.AssertContainsFields(t, "nfs_xprttcp", fields_xprttcp) + acc.AssertContainsFields(t, "nfs_events", fields_events) + acc.AssertContainsFields(t, "nfs_bytes", fields_bytes) + acc.AssertContainsFields(t, "nfs_xprttcp", fields_xprttcp) } From 6b9b3e23173e585b3d1711086706ac2b0a696827 Mon Sep 17 00:00:00 2001 From: Rasmus Larsen Date: Tue, 30 Aug 2016 14:03:15 +0200 Subject: [PATCH 8/8] Improve documentation. --- plugins/inputs/nfsclient/README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/plugins/inputs/nfsclient/README.md b/plugins/inputs/nfsclient/README.md index 7f514c3be..8442c7bf0 100644 --- a/plugins/inputs/nfsclient/README.md +++ b/plugins/inputs/nfsclient/README.md @@ -1,14 +1,39 @@ # Telegraf plugin: NFSCLIENT #### Plugin arguments: -- **fullstat** bool: Collect per-operation statistics +- **fullstat** bool: Collect per-operation type metrics #### Description The NFSCLIENT plugin collects data from /proc/self/mountstats, by default it will only include a quite limited set of IO metrics. If fullstat is set, it will collect a lot of per-operation statistics. +#### Measurements & Fields + +- nfsstat_read + - read_bytes (integer, bytes) + - read_exe (integer, bytes) + - read_ops (integer, bytes) + - read_retrans (integer, miliseconds) + - read_rtt (integer, miliseconds) + +- nfsstat_write + - write_bytes (integer, bytes) + - write_ops (integer, bytes) + - write_retrans (integer, bytes) + - write_exe (integer, miliseconds) + - write_rtt (integer, miliseconds) + +In addition enabling fullstat will make many more metrics available. + +#### Tags + +- All measurements have the following tags: + - mountpoint The local mountpoint, for instance: "/var/www" + - serverexport The full server export, for instance: "nfsserver.example.org:/export" + #### References [nfsiostat](http://git.linux-nfs.org/?p=steved/nfs-utils.git;a=summary) +[net/sunrpc/stats.c - Linux source code](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/net/sunrpc/stats.c) [What is in /proc/self/mountstats for NFS mounts: an introduction](https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex)