Add ARP collector for Linux#540
Conversation
grobie
left a comment
There was a problem hiding this comment.
Thanks, looks good in general. The consensus has been to handle procfs parsing in https://github.com/prometheus/procfs and use that implementation here though.
| scanner := bufio.NewScanner(data) | ||
| entries := make(map[string]uint32) | ||
|
|
||
| for scanner.Scan() { |
There was a problem hiding this comment.
scanner.Scan() can fail. You need to check scanner.Err() and handle that.
collector/arp_linux.go
Outdated
| return parseArpEntries(file), nil | ||
| } | ||
|
|
||
| func parseArpEntries(data *os.File) map[string]uint32 { |
There was a problem hiding this comment.
The only requirement is to pass something implementing the io.Reader interface, so I'd reflect that in the function signature.
collector/arp_linux.go
Outdated
| entries := make(map[string]uint32) | ||
|
|
||
| for scanner.Scan() { | ||
| columns := strings.Split(string(scanner.Text()), " ") |
There was a problem hiding this comment.
scanner.Text() returns a string. The type conversion is unnecessary.
collector/arp_linux.go
Outdated
| entries := make(map[string]uint32) | ||
|
|
||
| for scanner.Scan() { | ||
| columns := strings.Split(string(scanner.Text()), " ") |
|
Thanks for the insanely quick feedback @grobie! 🙇♂️ I've adopted the changes you suggested.
This PR implements only a tiny portion of what potentially needs to get parsed from |
|
You're lucky I had to push my hiking trip back by one day. Now I'm bored in
Patagonia and have time to review PRs ;-)
I'm fine with either merging the current state with a comment saying
something along the lines of "if more /proc/net/arp parsing support is
needed, move this to prometheus/procfs" or by adding full parsing support
to procfs now. Shouldn't be to hard to parse the whole line and return a
slice like []ARPEntry.
…On Sun, Apr 2, 2017 at 4:39 PM Sam Kottler ***@***.***> wrote:
Thanks for the insanely quick feedback @grobie <https://github.com/grobie>!
🙇 I've adopted the changes you suggested.
The consensus has been to handle procfs parsing in
https://github.com/prometheus/procfs and use that implementation here
though.
This PR implements only a tiny portion of what potentially needs to get
parsed from /proc/arp/net as it only covers what's needed to expose the
count per device. Is it okay to add a very much incomplete API to the
procfs package or would you prefer that more complete parsing support gets
implemented first?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#540 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAANaGCHJLZgjnK7MJcKmrMSgmEGoFuHks5rr_lvgaJpZM4Mw4_K>
.
|
collector/arp_linux.go
Outdated
| entries := make(map[string]uint32) | ||
|
|
||
| for scanner.Scan() { | ||
| if err := scanner.Err(); err != nil { |
There was a problem hiding this comment.
Err() will always be nil if Scan() is not nil. Check the example in https://golang.org/pkg/bufio/#example_Scanner_custom
I added a comment in that vain to the current parsing function. If you're comfortable merging this in its current state I'm happy to follow up with |
The tests look to be failing on netbsd with ARMv5. I hope that's a CI or build issue rather than actual failure because debugging that is gonna be...challenging 😂 |
collector/arp_linux.go
Outdated
| Factories["arp"] = NewArpCollector | ||
| } | ||
|
|
||
| // NewArpCollector returns a new Collector exposing ARP stats. |
There was a problem hiding this comment.
Arp -> ARP (https://github.com/golang/go/wiki/CodeReviewComments#initialisms)
Same below.
collector/arp_linux.go
Outdated
| return &arpCollector{ | ||
| count: prometheus.NewDesc( | ||
| prometheus.BuildFQName(Namespace, "arp", | ||
| "count"), "ARP entries by device", |
There was a problem hiding this comment.
This is kind of a confusing indentation/line break combination. If a function call is broken into multiple lines, I wouldn't then expect some other argument to follow it on the same line...
How about:
count: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, "arp", "count"),
"ARP entries by device",
[]string{"device"}, nil,
),
collector/arp_linux.go
Outdated
| return entries, nil | ||
| } | ||
|
|
||
| // This should get extracted to the github.com/prometheus/procfs package to |
There was a problem hiding this comment.
Add a TODO: to the beginning of this.
|
@skottler Regarding the test errors, I don't see how you could be causing them, given that you are not introducing any architecture-specific functionality, or even cgo stuff... |
| for scanner.Scan() { | ||
| columns := strings.Fields(scanner.Text()) | ||
|
|
||
| if columns[0] != "IP" { |
There was a problem hiding this comment.
This will panic if strings.Fields returns an empty slice, so it's probably worth adding a bounds check too.
https://play.golang.org/p/09sEiI2gEN
👋 Hey Sam!
collector/arp_linux.go
Outdated
| func NewARPCollector() (Collector, error) { | ||
| return &arpCollector{ | ||
| count: prometheus.NewDesc( | ||
| prometheus.BuildFQName(Namespace, "arp", "count"), |
There was a problem hiding this comment.
We don't include things like count in gauge metric names. I'd suggest node_arp_entries or maybe node_arp_hosts?
collector/arp_linux.go
Outdated
| for scanner.Scan() { | ||
| columns := strings.Fields(scanner.Text()) | ||
|
|
||
| if len(columns) > 0 { |
There was a problem hiding this comment.
Sorry for all the nitpicking. Idiomatic go tries to reduce the amount of nesting as much as possible, so if len(columns) == 0 { continue } would be more common here. Though, I think we should actually return an error here, such line would be completely unexpected and tell us about either a broken or changed ARP file. So I suggest:
if len(columns) < 6 {
return nil, fmt.Errorf("unexpected ARP table file")
}
// ...
collector/arp_linux.go
Outdated
| // to support more complete parsing of /proc/net/arp. Instead of adding | ||
| // more fields to this function's return values it should get moved and | ||
| // changed to support each field. | ||
| func parseArpEntries(data io.Reader) (map[string]uint32, error) { |
collector/arp_linux.go
Outdated
| }, nil | ||
| } | ||
|
|
||
| func getArpEntries() (map[string]uint32, error) { |
| return fmt.Errorf("could not get ARP entries: %s", err) | ||
| } | ||
|
|
||
| for device, entryCount := range entries { |
There was a problem hiding this comment.
As a note, it's common in go to use single letter variables in such short loops. I'm fine with the descriptive names though.
|
Seems like this would be a reasonable collector to enable by default as well. Thoughts on that from anyone? |
|
👍
Please also add it to the readme.
…On Sun, Apr 2, 2017, 21:19 Matt Layher ***@***.***> wrote:
Seems like this would be a reasonable collector to enable by default as
well. Thoughts on that from anyone?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#540 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAANaOGIDJtC4cUvesSdBasE9llh7T1_ks5rsDsWgaJpZM4Mw4_K>
.
|
|
I believe the test failures are the result of @juliusv latest change to build Prometheus components with go1.8 by default. Maybe our build yoda @sdurrheimer can help here? :-) |
discordianfish
left a comment
There was a problem hiding this comment.
This is great, thanks!
|
Build issues fixed in master. |
* Implement commonalities and linux support for ARP collection * Add ARP collector to fixtures and run as part of e2e tests * Bubble up scanner errors * Use single return values where it makes sense * Add missing annotation * Move arp_common into arp_linux * Add license header to arp_linux.go * Address initial feedback * Use strings.Fields instead of strings.Split * Deal with scanner.Err() rather than throwing away errors * Check for scan errors in-line before interacting with the entries map * Don't interact with potentially empty text from scan * Check for scan errors outside the scan loop * Add comment about moving procfs parsing * Add more direct comment * Update initialism style to match go style guide * Put function args on the same line * Add TODO in front of comment about procfs extraction * Guard against strings.Fields returning an empty slice * Be more defensive about ARP table format and use upcase more broadly * Enable the ARP collector by default * Add ARP collector to the README * Remove 'entry'
This introduces a simple ARP collector with initial support for Linux. It parses
/proc/net/arpand emits a count of ARP entries on a per-device basis./cc #535