Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add vmstat interface #59

Merged
merged 13 commits into from
Aug 21, 2019
Merged

Conversation

fearful-symmetry
Copy link
Contributor

@fearful-symmetry fearful-symmetry commented Aug 8, 2019

See elastic/beats#13175 This took me longer than expected, as I needed to figure out how this library actually works, and it's a tad different from how gosigar works. This should hopefully be fine; I've attempted to run it against the test suite and the unit tests works, but I still need to put together some "IRL" tests on a normal linux host. Also not entirely sure the test suite is working.

We also need godocs for a bunch of the types, but that's a separate PR.

@fearful-symmetry
Copy link
Contributor Author

Okay, down to the actual code issues now. Fixing.

@fearful-symmetry
Copy link
Contributor Author

Okay, lets try that.

README.md Show resolved Hide resolved
providers/linux/host_linux.go Show resolved Hide resolved
types/host.go Outdated
ThpSwpout uint64 `vmstat:"thp_swpout"`
ThpSwpoutFallback uint64 `vmstat:"thp_swpout_fallback"`
SwapRa uint64 `vmstat:"swap_ra"`
SwapRaHit uint64 `vmstat:"swap_ra_hit"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this is too much info? 😬 Should we have an struct that can be more easily implemented for other OSs?
Even if other OSs don't have a /proc/vmstat, I guess that they will have some similar virtual memory stats.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yah, I was thinking of this. The thing is, this library makes an effort to be highly cross-platform, and we already have a lot of platform-independent higher-level memory APIs, I figured it couldn't hurt to have some more bare-metal stats. Also, I didn't want to add overhead to the main Memory() Call by adding extra sources to it that most users won't need. I'm not sold on it though, since it might be a pain for clients to handle this for multiple OSes if we come up with similar low-level APIs for other OSes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we did it some other way, how would the user get platform-dependent stats?

return true
}
return false
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice.

types/host.go Outdated Show resolved Hide resolved
// Search The struct object to see if we have a field with a tag that matches the raw key coming off the file input
// This is the best way I've found to "search" for a a struct field based on a struct tag value.
// In this case, the /proc/vmstat keys are struct tags.
fieldToSet := refVal.FieldByNameFunc(func(name string) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it would make sense to iterate over the fields and read their tags just once to build up a map of tag to Value. This looks likes it's O(n^2) now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, yah, I think you're right. This is gonna end up getting called by metricbeat on every Fetch, so I'll see what I can do.

README.md Show resolved Hide resolved

// parseVMStat parses the contents of /proc/vmstat
func parseVMStat(content []byte) (*types.VMStatInfo, error) {
vmStat := &types.VMStatInfo{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about something like this where you bootstrap a mapping just once?

// vmstatTagToFieldIndex contains a mapping of json struct tags to struct field indices.
var vmstatTagToFieldIndex map[string]int

func init(){
	var vmstat VMStatInfo
	val := reflect.ValueOf(vmstat)
	typ := reflect.TypeOf(vmstat)

	vmstatTagToFieldIndex = map[string]int{}
	for i := 0; i < val.NumField(); i++ {
		field := typ.Field(i)
		if tag := field.Tag.Get("json"); tag != "" {
			vmstatTagToFieldIndex[tag] = i
		}
	}
}
	var vmStat VMStatInfo
	val := reflect.ValueOf(&vmStat).Elem()

	if idx, found := vmstatTagToFieldIndex["my_key"]; found {
		f := val.Field(idx)
		if f.CanSet() {
			f.SetUint(42)
		}
	}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I briefly thought of that but decided against it, but it didn't occur to me to use the struct index instead of the raw Value. Let's try that.

@fearful-symmetry
Copy link
Contributor Author

Alright, this moves it to an init(). We already have a lot of init functions in that library, but considering the performance implications of how often the VMStat thing will be called, it might be worth it.

Copy link
Member

@andrewkroh andrewkroh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM


// parseVMStat parses the contents of /proc/vmstat
func parseVMStat(content []byte) (*types.VMStatInfo, error) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you drop this newline please.

Copy link
Member

@andrewkroh andrewkroh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. My comments are just some redlines I notice while making a final pass.

providers/linux/vmstat.go Outdated Show resolved Hide resolved
providers/linux/host_linux.go Outdated Show resolved Hide resolved
providers/linux/vmstat.go Outdated Show resolved Hide resolved
types/host.go Outdated Show resolved Hide resolved
types/host.go Outdated Show resolved Hide resolved
types/host.go Outdated Show resolved Hide resolved
@fearful-symmetry fearful-symmetry merged commit 985ae85 into elastic:master Aug 21, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants