From 65de220430af974497fbb6d02e0be81941da89d5 Mon Sep 17 00:00:00 2001 From: James Maidment Date: Wed, 28 Feb 2018 11:15:45 -0500 Subject: [PATCH 01/11] Add wireless input --- plugins/inputs/all/all.go | 1 + plugins/inputs/wireless/README.md | 41 +++++ plugins/inputs/wireless/wireless.go | 155 +++++++++++++++++++ plugins/inputs/wireless/wireless_notlinux.go | 3 + 4 files changed, 200 insertions(+) create mode 100644 plugins/inputs/wireless/README.md create mode 100644 plugins/inputs/wireless/wireless.go create mode 100644 plugins/inputs/wireless/wireless_notlinux.go diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go index e3264ef8be4bf..08952cff51fd2 100644 --- a/plugins/inputs/all/all.go +++ b/plugins/inputs/all/all.go @@ -106,6 +106,7 @@ import ( _ "github.com/influxdata/telegraf/plugins/inputs/webhooks" _ "github.com/influxdata/telegraf/plugins/inputs/win_perf_counters" _ "github.com/influxdata/telegraf/plugins/inputs/win_services" + _ "github.com/influxdata/telegraf/plugins/inputs/wireless" _ "github.com/influxdata/telegraf/plugins/inputs/zfs" _ "github.com/influxdata/telegraf/plugins/inputs/zipkin" _ "github.com/influxdata/telegraf/plugins/inputs/zookeeper" diff --git a/plugins/inputs/wireless/README.md b/plugins/inputs/wireless/README.md new file mode 100644 index 0000000000000..918b5e050cef1 --- /dev/null +++ b/plugins/inputs/wireless/README.md @@ -0,0 +1,41 @@ +# Wireless Input Plugin + +The wireless plugin gathers metrics about wireless link quality by reading the `/proc/net/wireless` file. This plugin currently supports linux only. + +### Configuration: + +```toml +# Monitor wifi signal strength and quality +[[inputs.wireless]] + ## file paths for proc files. If empty default paths will be used: + ## /proc/net/wireless + proc_net_wireless = "/proc/net/wireless" + + ## dump metrics with 0 values too + dump_zeros = false +``` + +### Metrics: + +- metric + - tags: + - interface (wireless interface) + - fields: + - status (int64) - Its current state. This is a device dependent information + - link (int64, percentage) - general quality of the reception + - level (int64, dBm) - signal strength at the receiver + - noise (int64, dBm) - silence level (no packet) at the receiver + - nwid (int64, packets) - number of discarded packets due to invalid network id + - crypt (int64, packets) - number of packet unable to decrypt + - frag (int64, packets) - fragmented packets + - retry (int64, packets) - cumulative retry counts + - misc (int64, packets) - dropped for un-specified reason + - missed_beacon (int64, packets) - missed beacon packets + +### Example Output: + +This section shows example output in Line Protocol format. + +``` +wireless,host=example.localdomain,interface=wlan0 misc=0i,frag=0i,link=60i,level=-50i,noise=-256i,nwid=0i,crypt=0i,retry=1525i,missed_beacon=0i,status=0i 1519843022000000000 +``` diff --git a/plugins/inputs/wireless/wireless.go b/plugins/inputs/wireless/wireless.go new file mode 100644 index 0000000000000..10069b8b8fd69 --- /dev/null +++ b/plugins/inputs/wireless/wireless.go @@ -0,0 +1,155 @@ +// +build linux + +package wireless + +import ( + "bytes" + "io/ioutil" + "os" + "strconv" + "strings" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" +) + +var ( + newLineByte = []byte("\n") + wirelessHeaders = map[int]string{ + 0: "interface", + 1: "status", + 2: "link", + 3: "level", + 4: "noise", + 5: "nwid", + 6: "crypt", + 7: "frag", + 8: "retry", + 9: "misc", + 10: "missed_beacon", + } +) + +// default file paths +const ( + NET_WIRELESS = "/net/wireless" + NET_PROC = "/proc" +) + +// env variable names +const ( + ENV_WIRELESS = "PROC_NET_WIRELESS" + ENV_ROOT = "PROC_ROOT" +) + +type Wireless struct { + ProcNetWireless string `toml:"proc_net_wireless"` + DumpZeros bool `toml:"dump_zeros"` +} + +var sampleConfig = ` + ## file paths for proc files. If empty default paths will be used: + ## /proc/net/wireless + proc_net_wireless = "/proc/net/wireless" + + ## dump metrics with 0 values too + dump_zeros = false +` + +func (w *Wireless) Description() string { + return "Monitor wifi signal strength and quality" +} + +func (w *Wireless) SampleConfig() string { + return sampleConfig +} + +func (w *Wireless) Gather(acc telegraf.Accumulator) error { + // load paths, get from env if config values are empty + w.loadPaths() + + wireless, err := ioutil.ReadFile(w.ProcNetWireless) + if err != nil { + return err + } + + // collect wireless data + err = w.gatherWireless(wireless, acc) + if err != nil { + return err + } + + return nil +} + +func (w *Wireless) gatherWireless(data []byte, acc telegraf.Accumulator) error { + metrics, tags, err := loadWirelessTable(data, w.DumpZeros) + if err != nil { + return err + } + acc.AddFields("wireless", metrics, tags) + return nil +} + +// loadPaths can be used to read paths firstly from config +// if it is empty then try read from env variables +func (w *Wireless) loadPaths() { + if w.ProcNetWireless == "" { + w.ProcNetWireless = proc(ENV_WIRELESS, NET_WIRELESS) + } +} + +func loadWirelessTable(table []byte, dumpZeros bool) (map[string]interface{}, map[string]string, error) { + entries := map[string]interface{}{} + tags := map[string]string{} + // split the lines by newline + lines := bytes.Split(table, newLineByte) + var value int64 + var err error + // iterate over intefaces + for i := 2; i < len(lines); i = i + 1 { + if len(lines[i]) == 0 { + continue + } + fields := strings.Fields(string(lines[i])) + for j := 0; j < len(fields); j = j + 1 { + // parse interface + if j == 0 { + tags[wirelessHeaders[j]] = strings.Trim(fields[j], ":") + continue + } + // parse value + value, err = strconv.ParseInt(strings.Trim(fields[j], "."), 10, 64) + if err != nil { + continue + } + // value is zero + if value == 0 && dumpZeros { + continue + } + // the value is not zero, so parse it + entries[wirelessHeaders[j]] = value + } + } + return entries, tags, nil +} + +// proc can be used to read file paths from env +func proc(env, path string) string { + // try to read full file path + if p := os.Getenv(env); p != "" { + return p + } + // try to read root path, or use default root path + root := os.Getenv(ENV_ROOT) + if root == "" { + root = NET_PROC + } + return root + path +} + +func init() { + inputs.Add("wireless", func() telegraf.Input { + return &Wireless{} + }) +} diff --git a/plugins/inputs/wireless/wireless_notlinux.go b/plugins/inputs/wireless/wireless_notlinux.go new file mode 100644 index 0000000000000..a992e2efe5a20 --- /dev/null +++ b/plugins/inputs/wireless/wireless_notlinux.go @@ -0,0 +1,3 @@ +// +build !linux + +package wireless From efedb8e9cae68652b13ebc22a241682c55c4845c Mon Sep 17 00:00:00 2001 From: James Maidment Date: Fri, 2 Mar 2018 12:06:00 -0500 Subject: [PATCH 02/11] Add unit test --- plugins/inputs/wireless/wireless.go | 4 +++ plugins/inputs/wireless/wireless_test.go | 44 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 plugins/inputs/wireless/wireless_test.go diff --git a/plugins/inputs/wireless/wireless.go b/plugins/inputs/wireless/wireless.go index 10069b8b8fd69..dba79b5c23c4f 100644 --- a/plugins/inputs/wireless/wireless.go +++ b/plugins/inputs/wireless/wireless.go @@ -42,6 +42,7 @@ const ( ENV_ROOT = "PROC_ROOT" ) +// Wireless is used to store configuration values. type Wireless struct { ProcNetWireless string `toml:"proc_net_wireless"` DumpZeros bool `toml:"dump_zeros"` @@ -56,14 +57,17 @@ var sampleConfig = ` dump_zeros = false ` +// Desciption returns information about the plugin. func (w *Wireless) Description() string { return "Monitor wifi signal strength and quality" } +// SampleConfig displays configuration instructions. func (w *Wireless) SampleConfig() string { return sampleConfig } +// Gather collects the wireless information. func (w *Wireless) Gather(acc telegraf.Accumulator) error { // load paths, get from env if config values are empty w.loadPaths() diff --git a/plugins/inputs/wireless/wireless_test.go b/plugins/inputs/wireless/wireless_test.go new file mode 100644 index 0000000000000..4d96fc0ffe68c --- /dev/null +++ b/plugins/inputs/wireless/wireless_test.go @@ -0,0 +1,44 @@ +// +build linux + +package wireless + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var testInput = []byte(`Inter-| sta-| Quality | Discarded packets | Missed | WE + face | tus | link level noise | nwid crypt frag retry misc | beacon | 22 + wlan0: 0000 60. -50. -256 0 0 0 1525 0 0`) + +func TestLoadWirelessTable(t *testing.T) { + expectedMetrics := map[string]interface{}{ + "status": int64(0), + "link": int64(60), + "level": int64(-50), + "noise": int64(-256), + "nwid": int64(0), + "crypt": int64(0), + "frag": int64(0), + "retry": int64(1525), + "misc": int64(0), + "missed_beacon": int64(0), + } + expectedTags := map[string]string{ + "interface": "wlan0", + } + + metrics, tags, err := loadWirelessTable(testInput, false) + if err != nil { + t.Fatal(err) + } + + as := assert.New(t) + for k := range metrics { + as.Equal(metrics[k], expectedMetrics[k]) + } + for k := range tags { + as.Equal(tags[k], expectedTags[k]) + } +} From f6f4301973afcbd4fd8f27e736954b2ed95ddd9c Mon Sep 17 00:00:00 2001 From: James Maidment Date: Tue, 17 Apr 2018 15:46:08 -0400 Subject: [PATCH 03/11] Support gauge & counters --- plugins/inputs/wireless/README.md | 23 ++-- plugins/inputs/wireless/wireless.go | 133 ++++++++++++----------- plugins/inputs/wireless/wireless_test.go | 54 +++++---- 3 files changed, 112 insertions(+), 98 deletions(-) diff --git a/plugins/inputs/wireless/README.md b/plugins/inputs/wireless/README.md index 918b5e050cef1..3733823bf8e2c 100644 --- a/plugins/inputs/wireless/README.md +++ b/plugins/inputs/wireless/README.md @@ -10,9 +10,6 @@ The wireless plugin gathers metrics about wireless link quality by reading the ` ## file paths for proc files. If empty default paths will be used: ## /proc/net/wireless proc_net_wireless = "/proc/net/wireless" - - ## dump metrics with 0 values too - dump_zeros = false ``` ### Metrics: @@ -21,16 +18,16 @@ The wireless plugin gathers metrics about wireless link quality by reading the ` - tags: - interface (wireless interface) - fields: - - status (int64) - Its current state. This is a device dependent information - - link (int64, percentage) - general quality of the reception - - level (int64, dBm) - signal strength at the receiver - - noise (int64, dBm) - silence level (no packet) at the receiver - - nwid (int64, packets) - number of discarded packets due to invalid network id - - crypt (int64, packets) - number of packet unable to decrypt - - frag (int64, packets) - fragmented packets - - retry (int64, packets) - cumulative retry counts - - misc (int64, packets) - dropped for un-specified reason - - missed_beacon (int64, packets) - missed beacon packets + - status (int64, gauge) - Its current state. This is a device dependent information + - link (int64, percentage, gauge) - general quality of the reception + - level (int64, dBm, gauge) - signal strength at the receiver + - noise (int64, dBm, gauge) - silence level (no packet) at the receiver + - nwid (int64, packets, counter) - number of discarded packets due to invalid network id + - crypt (int64, packets, counter) - number of packet unable to decrypt + - frag (int64, packets, counter) - fragmented packets + - retry (int64, packets, counter) - cumulative retry counts + - misc (int64, packets, counter) - dropped for un-specified reason + - missed_beacon (int64, packets, counter) - missed beacon packets ### Example Output: diff --git a/plugins/inputs/wireless/wireless.go b/plugins/inputs/wireless/wireless.go index dba79b5c23c4f..efe8b7eff0296 100644 --- a/plugins/inputs/wireless/wireless.go +++ b/plugins/inputs/wireless/wireless.go @@ -13,23 +13,6 @@ import ( "github.com/influxdata/telegraf/plugins/inputs" ) -var ( - newLineByte = []byte("\n") - wirelessHeaders = map[int]string{ - 0: "interface", - 1: "status", - 2: "link", - 3: "level", - 4: "noise", - 5: "nwid", - 6: "crypt", - 7: "frag", - 8: "retry", - 9: "misc", - 10: "missed_beacon", - } -) - // default file paths const ( NET_WIRELESS = "/net/wireless" @@ -42,22 +25,36 @@ const ( ENV_ROOT = "PROC_ROOT" ) +var ( + newLineByte = []byte("\n") +) + +type wirelessInterface struct { + Interface string + Status int64 + Link int64 + Level int64 + Noise int64 + Nwid int64 + Crypt int64 + Frag int64 + Retry int64 + Misc int64 + Beacon int64 +} + // Wireless is used to store configuration values. type Wireless struct { ProcNetWireless string `toml:"proc_net_wireless"` - DumpZeros bool `toml:"dump_zeros"` } var sampleConfig = ` ## file paths for proc files. If empty default paths will be used: ## /proc/net/wireless proc_net_wireless = "/proc/net/wireless" - - ## dump metrics with 0 values too - dump_zeros = false ` -// Desciption returns information about the plugin. +// Description returns information about the plugin. func (w *Wireless) Description() string { return "Monitor wifi signal strength and quality" } @@ -72,70 +69,82 @@ func (w *Wireless) Gather(acc telegraf.Accumulator) error { // load paths, get from env if config values are empty w.loadPaths() - wireless, err := ioutil.ReadFile(w.ProcNetWireless) + table, err := ioutil.ReadFile(w.ProcNetWireless) if err != nil { return err } - // collect wireless data - err = w.gatherWireless(wireless, acc) + interfaces, err := loadWirelessTable(table) if err != nil { return err } - - return nil -} - -func (w *Wireless) gatherWireless(data []byte, acc telegraf.Accumulator) error { - metrics, tags, err := loadWirelessTable(data, w.DumpZeros) - if err != nil { - return err + for _, w := range interfaces { + tags := map[string]string{ + "interface": w.Interface, + } + fieldsG := map[string]interface{}{ + "status": w.Status, + "link": w.Link, + "level": w.Level, + "noise": w.Noise, + } + fieldsC := map[string]interface{}{ + "nwid": w.Nwid, + "crypt": w.Crypt, + "frag": w.Frag, + "retry": w.Retry, + "misc": w.Misc, + "beacon": w.Beacon, + } + acc.AddGauge("wireless", fieldsG, tags) + acc.AddCounter("wireless", fieldsC, tags) } - acc.AddFields("wireless", metrics, tags) + return nil } -// loadPaths can be used to read paths firstly from config -// if it is empty then try read from env variables -func (w *Wireless) loadPaths() { - if w.ProcNetWireless == "" { - w.ProcNetWireless = proc(ENV_WIRELESS, NET_WIRELESS) - } -} +func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { + var w []*wirelessInterface -func loadWirelessTable(table []byte, dumpZeros bool) (map[string]interface{}, map[string]string, error) { - entries := map[string]interface{}{} - tags := map[string]string{} // split the lines by newline lines := bytes.Split(table, newLineByte) - var value int64 - var err error // iterate over intefaces for i := 2; i < len(lines); i = i + 1 { if len(lines[i]) == 0 { continue } fields := strings.Fields(string(lines[i])) - for j := 0; j < len(fields); j = j + 1 { - // parse interface - if j == 0 { - tags[wirelessHeaders[j]] = strings.Trim(fields[j], ":") - continue - } - // parse value - value, err = strconv.ParseInt(strings.Trim(fields[j], "."), 10, 64) + var values []int64 + for i := 1; i < len(fields); i = i + 1 { + v, err := strconv.ParseInt(strings.Trim(fields[i], "."), 10, 64) if err != nil { - continue + return nil, err } - // value is zero - if value == 0 && dumpZeros { - continue - } - // the value is not zero, so parse it - entries[wirelessHeaders[j]] = value + values = append(values, v) } + w = append(w, &wirelessInterface{ + Interface: strings.Trim(fields[0], ":"), + Status: values[0], + Link: values[1], + Level: values[2], + Noise: values[3], + Nwid: values[4], + Crypt: values[5], + Frag: values[6], + Retry: values[7], + Misc: values[8], + Beacon: values[9], + }) + } + return w, nil +} + +// loadPaths can be used to read paths firstly from config +// if it is empty then try read from env variables +func (w *Wireless) loadPaths() { + if w.ProcNetWireless == "" { + w.ProcNetWireless = proc(ENV_WIRELESS, NET_WIRELESS) } - return entries, tags, nil } // proc can be used to read file paths from env diff --git a/plugins/inputs/wireless/wireless_test.go b/plugins/inputs/wireless/wireless_test.go index 4d96fc0ffe68c..f2ca1fc21a50b 100644 --- a/plugins/inputs/wireless/wireless_test.go +++ b/plugins/inputs/wireless/wireless_test.go @@ -10,35 +10,43 @@ import ( var testInput = []byte(`Inter-| sta-| Quality | Discarded packets | Missed | WE face | tus | link level noise | nwid crypt frag retry misc | beacon | 22 - wlan0: 0000 60. -50. -256 0 0 0 1525 0 0`) + wlan0: 0000 60. -50. -256 0 0 0 1525 0 0 + wlan1: 0000 70. -39. -256 0 0 0 12096 191188 0`) func TestLoadWirelessTable(t *testing.T) { - expectedMetrics := map[string]interface{}{ - "status": int64(0), - "link": int64(60), - "level": int64(-50), - "noise": int64(-256), - "nwid": int64(0), - "crypt": int64(0), - "frag": int64(0), - "retry": int64(1525), - "misc": int64(0), - "missed_beacon": int64(0), + expectedMetrics := []*wirelessInterface{ + &wirelessInterface{ + Interface: "wlan0", + Status: int64(0000), + Link: int64(60), + Level: int64(-50), + Noise: int64(-256), + Nwid: int64(0), + Crypt: int64(0), + Frag: int64(0), + Retry: int64(1525), + Misc: int64(0), + Beacon: int64(0), + }, + &wirelessInterface{ + Interface: "wlan1", + Status: int64(0000), + Link: int64(70), + Level: int64(-39), + Noise: int64(-256), + Nwid: int64(0), + Crypt: int64(0), + Frag: int64(0), + Retry: int64(12096), + Misc: int64(191188), + Beacon: int64(0), + }, } - expectedTags := map[string]string{ - "interface": "wlan0", - } - - metrics, tags, err := loadWirelessTable(testInput, false) + metrics, err := loadWirelessTable(testInput) if err != nil { t.Fatal(err) } as := assert.New(t) - for k := range metrics { - as.Equal(metrics[k], expectedMetrics[k]) - } - for k := range tags { - as.Equal(tags[k], expectedTags[k]) - } + as.Equal(metrics, expectedMetrics) } From 91df56f7c0d3d528e02c89dcb9f1789c7a9dc65b Mon Sep 17 00:00:00 2001 From: James Maidment Date: Sun, 29 Jul 2018 01:06:28 -0400 Subject: [PATCH 04/11] Rename files & update var naming --- plugins/inputs/wireless/wireless.go | 167 +----------------- plugins/inputs/wireless/wireless_linux.go | 169 +++++++++++++++++++ plugins/inputs/wireless/wireless_notlinux.go | 3 - 3 files changed, 170 insertions(+), 169 deletions(-) create mode 100644 plugins/inputs/wireless/wireless_linux.go delete mode 100644 plugins/inputs/wireless/wireless_notlinux.go diff --git a/plugins/inputs/wireless/wireless.go b/plugins/inputs/wireless/wireless.go index efe8b7eff0296..a992e2efe5a20 100644 --- a/plugins/inputs/wireless/wireless.go +++ b/plugins/inputs/wireless/wireless.go @@ -1,168 +1,3 @@ -// +build linux +// +build !linux package wireless - -import ( - "bytes" - "io/ioutil" - "os" - "strconv" - "strings" - - "github.com/influxdata/telegraf" - "github.com/influxdata/telegraf/plugins/inputs" -) - -// default file paths -const ( - NET_WIRELESS = "/net/wireless" - NET_PROC = "/proc" -) - -// env variable names -const ( - ENV_WIRELESS = "PROC_NET_WIRELESS" - ENV_ROOT = "PROC_ROOT" -) - -var ( - newLineByte = []byte("\n") -) - -type wirelessInterface struct { - Interface string - Status int64 - Link int64 - Level int64 - Noise int64 - Nwid int64 - Crypt int64 - Frag int64 - Retry int64 - Misc int64 - Beacon int64 -} - -// Wireless is used to store configuration values. -type Wireless struct { - ProcNetWireless string `toml:"proc_net_wireless"` -} - -var sampleConfig = ` - ## file paths for proc files. If empty default paths will be used: - ## /proc/net/wireless - proc_net_wireless = "/proc/net/wireless" -` - -// Description returns information about the plugin. -func (w *Wireless) Description() string { - return "Monitor wifi signal strength and quality" -} - -// SampleConfig displays configuration instructions. -func (w *Wireless) SampleConfig() string { - return sampleConfig -} - -// Gather collects the wireless information. -func (w *Wireless) Gather(acc telegraf.Accumulator) error { - // load paths, get from env if config values are empty - w.loadPaths() - - table, err := ioutil.ReadFile(w.ProcNetWireless) - if err != nil { - return err - } - - interfaces, err := loadWirelessTable(table) - if err != nil { - return err - } - for _, w := range interfaces { - tags := map[string]string{ - "interface": w.Interface, - } - fieldsG := map[string]interface{}{ - "status": w.Status, - "link": w.Link, - "level": w.Level, - "noise": w.Noise, - } - fieldsC := map[string]interface{}{ - "nwid": w.Nwid, - "crypt": w.Crypt, - "frag": w.Frag, - "retry": w.Retry, - "misc": w.Misc, - "beacon": w.Beacon, - } - acc.AddGauge("wireless", fieldsG, tags) - acc.AddCounter("wireless", fieldsC, tags) - } - - return nil -} - -func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { - var w []*wirelessInterface - - // split the lines by newline - lines := bytes.Split(table, newLineByte) - // iterate over intefaces - for i := 2; i < len(lines); i = i + 1 { - if len(lines[i]) == 0 { - continue - } - fields := strings.Fields(string(lines[i])) - var values []int64 - for i := 1; i < len(fields); i = i + 1 { - v, err := strconv.ParseInt(strings.Trim(fields[i], "."), 10, 64) - if err != nil { - return nil, err - } - values = append(values, v) - } - w = append(w, &wirelessInterface{ - Interface: strings.Trim(fields[0], ":"), - Status: values[0], - Link: values[1], - Level: values[2], - Noise: values[3], - Nwid: values[4], - Crypt: values[5], - Frag: values[6], - Retry: values[7], - Misc: values[8], - Beacon: values[9], - }) - } - return w, nil -} - -// loadPaths can be used to read paths firstly from config -// if it is empty then try read from env variables -func (w *Wireless) loadPaths() { - if w.ProcNetWireless == "" { - w.ProcNetWireless = proc(ENV_WIRELESS, NET_WIRELESS) - } -} - -// proc can be used to read file paths from env -func proc(env, path string) string { - // try to read full file path - if p := os.Getenv(env); p != "" { - return p - } - // try to read root path, or use default root path - root := os.Getenv(ENV_ROOT) - if root == "" { - root = NET_PROC - } - return root + path -} - -func init() { - inputs.Add("wireless", func() telegraf.Input { - return &Wireless{} - }) -} diff --git a/plugins/inputs/wireless/wireless_linux.go b/plugins/inputs/wireless/wireless_linux.go new file mode 100644 index 0000000000000..29f56883d2567 --- /dev/null +++ b/plugins/inputs/wireless/wireless_linux.go @@ -0,0 +1,169 @@ +// +build linux + +package wireless + +import ( + "bytes" + "io/ioutil" + "os" + "strconv" + "strings" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/plugins/inputs" +) + +// default file paths +const ( + NET_WIRELESS = "/net/wireless" + NET_PROC = "/proc" +) + +// env variable names +const ( + ENV_WIRELESS = "PROC_NET_WIRELESS" + ENV_ROOT = "PROC_ROOT" +) + +var ( + newLineByte = []byte("\n") +) + +type wirelessInterface struct { + Interface string + Status int64 + Link int64 + Level int64 + Noise int64 + Nwid int64 + Crypt int64 + Frag int64 + Retry int64 + Misc int64 + Beacon int64 +} + +// Wireless is used to store configuration values. +type Wireless struct { + ProcNetWireless string `toml:"proc_net_wireless"` +} + +var sampleConfig = ` + ## file paths for proc files. If empty default paths will be used: + ## /proc/net/wireless + proc_net_wireless = "/proc/net/wireless" +` + +// Description returns information about the plugin. +func (w *Wireless) Description() string { + return "Monitor wifi signal strength and quality" +} + +// SampleConfig displays configuration instructions. +func (w *Wireless) SampleConfig() string { + return sampleConfig +} + +// Gather collects the wireless information. +func (w *Wireless) Gather(acc telegraf.Accumulator) error { + // load paths, get from env if config values are empty + w.loadPaths() + + table, err := ioutil.ReadFile(w.ProcNetWireless) + if err != nil { + return err + } + + interfaces, err := loadWirelessTable(table) + if err != nil { + return err + } + for _, w := range interfaces { + tags := map[string]string{ + "interface": w.Interface, + } + fieldsG := map[string]interface{}{ + "status": w.Status, + "link": w.Link, + "level": w.Level, + "noise": w.Noise, + } + fieldsC := map[string]interface{}{ + "nwid": w.Nwid, + "crypt": w.Crypt, + "frag": w.Frag, + "retry": w.Retry, + "misc": w.Misc, + "beacon": w.Beacon, + } + acc.AddGauge("wireless", fieldsG, tags) + acc.AddCounter("wireless", fieldsC, tags) + } + + return nil +} + +func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { + var w []*wirelessInterface + + // split the lines by newline + lines := bytes.Split(table, newLineByte) + + // iterate over intefaces + for i := 2; i < len(lines); i = i + 1 { + if len(lines[i]) == 0 { + continue + } + fields := strings.Fields(string(lines[i])) + var values []int64 + for k := 1; k < len(fields); k = k + 1 { + v, err := strconv.ParseInt(fields[i], ".")) + if err != nil { + return nil, err + } + values = append(values, v) + } + w = append(w, &wirelessInterface{ + Interface: strings.Trim(fields[0], ":"), + Status: values[0], + Link: values[1], + Level: values[2], + Noise: values[3], + Nwid: values[4], + Crypt: values[5], + Frag: values[6], + Retry: values[7], + Misc: values[8], + Beacon: values[9], + }) + } + return w, nil +} + +// loadPaths can be used to read paths firstly from config +// if it is empty then try read from env variables +func (w *Wireless) loadPaths() { + if w.ProcNetWireless == "" { + w.ProcNetWireless = proc(ENV_WIRELESS, NET_WIRELESS) + } +} + +// proc can be used to read file paths from env +func proc(env, path string) string { + // try to read full file path + if p := os.Getenv(env); p != "" { + return p + } + // try to read root path, or use default root path + root := os.Getenv(ENV_ROOT) + if root == "" { + root = NET_PROC + } + return root + path +} + +func init() { + inputs.Add("wireless", func() telegraf.Input { + return &Wireless{} + }) +} diff --git a/plugins/inputs/wireless/wireless_notlinux.go b/plugins/inputs/wireless/wireless_notlinux.go deleted file mode 100644 index a992e2efe5a20..0000000000000 --- a/plugins/inputs/wireless/wireless_notlinux.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build !linux - -package wireless From 4614df089c26ebbec83ccaff5ea380692ba067f2 Mon Sep 17 00:00:00 2001 From: James Maidment Date: Thu, 20 Sep 2018 19:36:55 -0400 Subject: [PATCH 05/11] Fix bracket --- plugins/inputs/wireless/wireless_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/wireless/wireless_linux.go b/plugins/inputs/wireless/wireless_linux.go index 29f56883d2567..584e6b78d5ba3 100644 --- a/plugins/inputs/wireless/wireless_linux.go +++ b/plugins/inputs/wireless/wireless_linux.go @@ -117,7 +117,7 @@ func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { fields := strings.Fields(string(lines[i])) var values []int64 for k := 1; k < len(fields); k = k + 1 { - v, err := strconv.ParseInt(fields[i], ".")) + v, err := strconv.ParseInt(fields[i], ".") if err != nil { return nil, err } From 87a1d511cb680bd7cff5d388699e8966cdc2f231 Mon Sep 17 00:00:00 2001 From: James Maidment Date: Thu, 20 Sep 2018 20:37:24 -0400 Subject: [PATCH 06/11] Fix read bug --- plugins/inputs/wireless/wireless_linux.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/inputs/wireless/wireless_linux.go b/plugins/inputs/wireless/wireless_linux.go index 584e6b78d5ba3..19b353d6be0a6 100644 --- a/plugins/inputs/wireless/wireless_linux.go +++ b/plugins/inputs/wireless/wireless_linux.go @@ -111,13 +111,13 @@ func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { // iterate over intefaces for i := 2; i < len(lines); i = i + 1 { + var values []int64 if len(lines[i]) == 0 { continue } fields := strings.Fields(string(lines[i])) - var values []int64 for k := 1; k < len(fields); k = k + 1 { - v, err := strconv.ParseInt(fields[i], ".") + v, err := strconv.ParseInt(strings.Trim(fields[k], "."), 10, 64) if err != nil { return nil, err } From 456e5d01e62f852e8b94caa4dd499ace48c77abe Mon Sep 17 00:00:00 2001 From: James Maidment Date: Thu, 20 Sep 2018 20:39:15 -0400 Subject: [PATCH 07/11] Tidy --- plugins/inputs/wireless/wireless_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/wireless/wireless_linux.go b/plugins/inputs/wireless/wireless_linux.go index 19b353d6be0a6..667917e9bfe2e 100644 --- a/plugins/inputs/wireless/wireless_linux.go +++ b/plugins/inputs/wireless/wireless_linux.go @@ -111,10 +111,10 @@ func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { // iterate over intefaces for i := 2; i < len(lines); i = i + 1 { - var values []int64 if len(lines[i]) == 0 { continue } + values := []int64{} fields := strings.Fields(string(lines[i])) for k := 1; k < len(fields); k = k + 1 { v, err := strconv.ParseInt(strings.Trim(fields[k], "."), 10, 64) From 112cc37cb2cf25a505ff81345f73ce3a79008749 Mon Sep 17 00:00:00 2001 From: James Maidment Date: Thu, 20 Sep 2018 21:13:24 -0400 Subject: [PATCH 08/11] Use generic proc location --- plugins/inputs/wireless/wireless_linux.go | 56 +++++++++-------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/plugins/inputs/wireless/wireless_linux.go b/plugins/inputs/wireless/wireless_linux.go index 667917e9bfe2e..b543fc9e6b92d 100644 --- a/plugins/inputs/wireless/wireless_linux.go +++ b/plugins/inputs/wireless/wireless_linux.go @@ -6,6 +6,7 @@ import ( "bytes" "io/ioutil" "os" + "path" "strconv" "strings" @@ -13,21 +14,13 @@ import ( "github.com/influxdata/telegraf/plugins/inputs" ) -// default file paths -const ( - NET_WIRELESS = "/net/wireless" - NET_PROC = "/proc" -) +// default host proc path +const defaultHostProc = "/proc" -// env variable names -const ( - ENV_WIRELESS = "PROC_NET_WIRELESS" - ENV_ROOT = "PROC_ROOT" -) +// env host proc variable name +const envProc = "HOST_PROC" -var ( - newLineByte = []byte("\n") -) +var newLineByte = []byte("\n") type wirelessInterface struct { Interface string @@ -45,13 +38,13 @@ type wirelessInterface struct { // Wireless is used to store configuration values. type Wireless struct { - ProcNetWireless string `toml:"proc_net_wireless"` + HostProc string `toml:"host_proc"` } var sampleConfig = ` - ## file paths for proc files. If empty default paths will be used: - ## /proc/net/wireless - proc_net_wireless = "/proc/net/wireless" + ## Sets 'proc' directory path + ## If not specified, then default is /proc + # host_proc = "/proc" ` // Description returns information about the plugin. @@ -66,10 +59,11 @@ func (w *Wireless) SampleConfig() string { // Gather collects the wireless information. func (w *Wireless) Gather(acc telegraf.Accumulator) error { - // load paths, get from env if config values are empty - w.loadPaths() + // load proc path, get default value if config value and env variable are empty + w.loadPath() - table, err := ioutil.ReadFile(w.ProcNetWireless) + wirelessPath := path.Join(w.HostProc, "net", "wireless") + table, err := ioutil.ReadFile(wirelessPath) if err != nil { return err } @@ -105,11 +99,9 @@ func (w *Wireless) Gather(acc telegraf.Accumulator) error { func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { var w []*wirelessInterface - - // split the lines by newline lines := bytes.Split(table, newLineByte) - // iterate over intefaces + // iterate over interfaces for i := 2; i < len(lines); i = i + 1 { if len(lines[i]) == 0 { continue @@ -140,11 +132,11 @@ func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { return w, nil } -// loadPaths can be used to read paths firstly from config -// if it is empty then try read from env variables -func (w *Wireless) loadPaths() { - if w.ProcNetWireless == "" { - w.ProcNetWireless = proc(ENV_WIRELESS, NET_WIRELESS) +// loadPath can be used to read path firstly from config +// if it is empty then try read from env variable +func (w *Wireless) loadPath() { + if w.HostProc == "" { + w.HostProc = proc(envProc, defaultHostProc) } } @@ -154,12 +146,8 @@ func proc(env, path string) string { if p := os.Getenv(env); p != "" { return p } - // try to read root path, or use default root path - root := os.Getenv(ENV_ROOT) - if root == "" { - root = NET_PROC - } - return root + path + // return default path + return path } func init() { From e8537f52a0843f6ad0fbbc0de6bd74f611c9559c Mon Sep 17 00:00:00 2001 From: James Maidment Date: Thu, 20 Sep 2018 21:36:00 -0400 Subject: [PATCH 09/11] Update readme --- plugins/inputs/wireless/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/inputs/wireless/README.md b/plugins/inputs/wireless/README.md index 3733823bf8e2c..6be7bd383d451 100644 --- a/plugins/inputs/wireless/README.md +++ b/plugins/inputs/wireless/README.md @@ -7,9 +7,9 @@ The wireless plugin gathers metrics about wireless link quality by reading the ` ```toml # Monitor wifi signal strength and quality [[inputs.wireless]] - ## file paths for proc files. If empty default paths will be used: - ## /proc/net/wireless - proc_net_wireless = "/proc/net/wireless" + ## Sets 'proc' directory path + ## If not specified, then default is /proc + # host_proc = "/proc" ``` ### Metrics: From 390c38818a4afc2bd7b1f6a29a2d7519e713e8ba Mon Sep 17 00:00:00 2001 From: James Maidment Date: Fri, 21 Sep 2018 00:48:03 -0400 Subject: [PATCH 10/11] Tidy --- plugins/inputs/wireless/wireless_linux.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/inputs/wireless/wireless_linux.go b/plugins/inputs/wireless/wireless_linux.go index b543fc9e6b92d..d400a1a14bbda 100644 --- a/plugins/inputs/wireless/wireless_linux.go +++ b/plugins/inputs/wireless/wireless_linux.go @@ -108,8 +108,8 @@ func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { } values := []int64{} fields := strings.Fields(string(lines[i])) - for k := 1; k < len(fields); k = k + 1 { - v, err := strconv.ParseInt(strings.Trim(fields[k], "."), 10, 64) + for j := 1; j < len(fields); j = j + 1 { + v, err := strconv.ParseInt(strings.Trim(fields[j], "."), 10, 64) if err != nil { return nil, err } From 46125210730dc30a21681bba07338dbfa8f35611 Mon Sep 17 00:00:00 2001 From: James Maidment Date: Tue, 16 Oct 2018 14:26:45 -0400 Subject: [PATCH 11/11] Preallocate field length --- plugins/inputs/wireless/wireless_linux.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/inputs/wireless/wireless_linux.go b/plugins/inputs/wireless/wireless_linux.go index d400a1a14bbda..ed5dff27fafd7 100644 --- a/plugins/inputs/wireless/wireless_linux.go +++ b/plugins/inputs/wireless/wireless_linux.go @@ -5,6 +5,7 @@ package wireless import ( "bytes" "io/ioutil" + "log" "os" "path" "strconv" @@ -20,6 +21,9 @@ const defaultHostProc = "/proc" // env host proc variable name const envProc = "HOST_PROC" +// length of wireless interface fields +const interfaceFieldLength = 10 + var newLineByte = []byte("\n") type wirelessInterface struct { @@ -106,7 +110,7 @@ func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { if len(lines[i]) == 0 { continue } - values := []int64{} + values := make([]int64, 0, interfaceFieldLength) fields := strings.Fields(string(lines[i])) for j := 1; j < len(fields); j = j + 1 { v, err := strconv.ParseInt(strings.Trim(fields[j], "."), 10, 64) @@ -115,6 +119,10 @@ func loadWirelessTable(table []byte) ([]*wirelessInterface, error) { } values = append(values, v) } + if len(values) != interfaceFieldLength { + log.Printf("E! [input.wireless] invalid length of interface values") + continue + } w = append(w, &wirelessInterface{ Interface: strings.Trim(fields[0], ":"), Status: values[0],