From 2983c4a31d840ed4a2d39594f28c7f589c43110f Mon Sep 17 00:00:00 2001 From: Johannes 'fish' Ziemke Date: Tue, 27 Dec 2016 12:46:25 +0100 Subject: [PATCH 1/2] Refactor meminfo collector similar to filesystem Instead of doing the whole metric exposition in a platform specific collector implementation, this creates and updates the metrics in meminfo.go and expected a platform specific implementation of getMemInfo on *meminfoCollector. --- collector/meminfo.go | 60 +++++++++++++++++++++++++++++++++++++ collector/meminfo_bsd.go | 61 +++++++++++++------------------------- collector/meminfo_linux.go | 40 +------------------------ 3 files changed, 82 insertions(+), 79 deletions(-) create mode 100644 collector/meminfo.go diff --git a/collector/meminfo.go b/collector/meminfo.go new file mode 100644 index 00000000..f5315683 --- /dev/null +++ b/collector/meminfo.go @@ -0,0 +1,60 @@ +// Copyright 2015 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !nomeminfo + +package collector + +import ( + "fmt" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/log" +) + +const ( + memInfoSubsystem = "memory" +) + +type meminfoCollector struct{} + +func init() { + Factories["meminfo"] = NewMeminfoCollector +} + +// Takes a prometheus registry and returns a new Collector exposing +// memory stats. +func NewMeminfoCollector() (Collector, error) { + return &meminfoCollector{}, nil +} + +// Update calls (*meminfoCollector).getMemInfo to get the platform specific +// memory metrics. +func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) (err error) { + memInfo, err := c.getMemInfo() + if err != nil { + return fmt.Errorf("couldn't get meminfo: %s", err) + } + log.Debugf("Set node_mem: %#v", memInfo) + for k, v := range memInfo { + ch <- prometheus.MustNewConstMetric( + prometheus.NewDesc( + prometheus.BuildFQName(Namespace, memInfoSubsystem, k), + fmt.Sprintf("Memory information field %s.", k), + nil, nil, + ), + prometheus.GaugeValue, v, + ) + } + return nil +} diff --git a/collector/meminfo_bsd.go b/collector/meminfo_bsd.go index bcdc3879..b1b2b7a4 100644 --- a/collector/meminfo_bsd.go +++ b/collector/meminfo_bsd.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build freebsd darwin,amd64 dragonfly +// +build darwin freebsd dragonfly // +build !nomeminfo package collector @@ -19,52 +19,33 @@ package collector import ( "fmt" - "github.com/prometheus/client_golang/prometheus" "golang.org/x/sys/unix" ) -const ( - memInfoSubsystem = "memory" -) - -type meminfoCollector struct{} - -func init() { - Factories["meminfo"] = NewMeminfoCollector -} - -// Takes a prometheus registry and returns a new Collector exposing -// Memory stats. -func NewMeminfoCollector() (Collector, error) { - return &meminfoCollector{}, nil -} - -func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) (err error) { - pages := make(map[string]uint32) +func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { + info := make(map[string]float64) size, err := unix.SysctlUint32("vm.stats.vm.v_page_size") if err != nil { - return fmt.Errorf("sysctl(vm.stats.vm.v_page_size) failed: %s", err) + return nil, fmt.Errorf("sysctl(vm.stats.vm.v_page_size) failed: %s", err) } - pages["active"], _ = unix.SysctlUint32("vm.stats.vm.v_active_count") - pages["inactive"], _ = unix.SysctlUint32("vm.stats.vm.v_inactive_count") - pages["wire"], _ = unix.SysctlUint32("vm.stats.vm.v_wire_count") - pages["cache"], _ = unix.SysctlUint32("vm.stats.vm.v_cache_count") - pages["free"], _ = unix.SysctlUint32("vm.stats.vm.v_free_count") - pages["swappgsin"], _ = unix.SysctlUint32("vm.stats.vm.v_swappgsin") - pages["swappgsout"], _ = unix.SysctlUint32("vm.stats.vm.v_swappgsout") - pages["total"], _ = unix.SysctlUint32("vm.stats.vm.v_page_count") - for k, v := range pages { - ch <- prometheus.MustNewConstMetric( - prometheus.NewDesc( - prometheus.BuildFQName(Namespace, memInfoSubsystem, k), - k+" from sysctl()", - nil, nil, - ), - // Convert metrics to kB (same as Linux meminfo). - prometheus.UntypedValue, float64(v)*float64(size), - ) + for key, v := range map[string]string{ + "active": "vm.stats.vm.v_active_count", + "inactive": "vm.stats.vm.v_inactive_count", + "wire": "vm.stats.vm.v_wire_count", + "cache": "vm.stats.vm.v_cache_count", + "free": "vm.stats.vm.v_free_count", + "swappgsin": "vm.stats.vm.v_swappgsin", + "swappgsout": "vm.stats.vm.v_swappgsout", + "total": "vm.stats.vm.v_page_count", + } { + value, err := unix.SysctlUint32(v) + if err != nil { + return nil, err + } + // Convert metrics to kB (same as Linux meminfo). + info[key] = float64(value) * float64(size) } - return err + return info, nil } diff --git a/collector/meminfo_linux.go b/collector/meminfo_linux.go index d1ebe26c..1a8556fd 100644 --- a/collector/meminfo_linux.go +++ b/collector/meminfo_linux.go @@ -23,47 +23,9 @@ import ( "regexp" "strconv" "strings" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/common/log" ) -const ( - memInfoSubsystem = "memory" -) - -type meminfoCollector struct{} - -func init() { - Factories["meminfo"] = NewMeminfoCollector -} - -// Takes a prometheus registry and returns a new Collector exposing -// memory stats. -func NewMeminfoCollector() (Collector, error) { - return &meminfoCollector{}, nil -} - -func (c *meminfoCollector) Update(ch chan<- prometheus.Metric) (err error) { - memInfo, err := getMemInfo() - if err != nil { - return fmt.Errorf("couldn't get meminfo: %s", err) - } - log.Debugf("Set node_mem: %#v", memInfo) - for k, v := range memInfo { - ch <- prometheus.MustNewConstMetric( - prometheus.NewDesc( - prometheus.BuildFQName(Namespace, memInfoSubsystem, k), - fmt.Sprintf("Memory information field %s.", k), - nil, nil, - ), - prometheus.GaugeValue, v, - ) - } - return nil -} - -func getMemInfo() (map[string]float64, error) { +func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { file, err := os.Open(procFilePath("meminfo")) if err != nil { return nil, err From c21c59dfeb49c90f34eff7b2ef17c3ed21b7151a Mon Sep 17 00:00:00 2001 From: Johannes 'fish' Ziemke Date: Tue, 27 Dec 2016 18:14:17 +0100 Subject: [PATCH 2/2] Add meminfo stats for Darwin --- collector/meminfo.go | 3 +- collector/meminfo_bsd.go | 2 +- collector/meminfo_darwin.go | 59 +++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 collector/meminfo_darwin.go diff --git a/collector/meminfo.go b/collector/meminfo.go index f5315683..4322470c 100644 --- a/collector/meminfo.go +++ b/collector/meminfo.go @@ -32,8 +32,7 @@ func init() { Factories["meminfo"] = NewMeminfoCollector } -// Takes a prometheus registry and returns a new Collector exposing -// memory stats. +// NewMeminfoCollector returns a new Collector exposing memory stats. func NewMeminfoCollector() (Collector, error) { return &meminfoCollector{}, nil } diff --git a/collector/meminfo_bsd.go b/collector/meminfo_bsd.go index b1b2b7a4..be17d7a9 100644 --- a/collector/meminfo_bsd.go +++ b/collector/meminfo_bsd.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build darwin freebsd dragonfly +// +build freebsd dragonfly // +build !nomeminfo package collector diff --git a/collector/meminfo_darwin.go b/collector/meminfo_darwin.go new file mode 100644 index 00000000..0aa35ce0 --- /dev/null +++ b/collector/meminfo_darwin.go @@ -0,0 +1,59 @@ +// Copyright 2015 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !nomeminfo + +package collector + +// #include +import "C" + +import ( + "encoding/binary" + "fmt" + "syscall" + "unsafe" + + "golang.org/x/sys/unix" +) + +func (c *meminfoCollector) getMemInfo() (map[string]float64, error) { + infoCount := C.mach_msg_type_number_t(C.HOST_VM_INFO_COUNT) + vmstat := C.vm_statistics_data_t{} + ret := C.host_statistics( + C.host_t(C.mach_host_self()), + C.HOST_VM_INFO, + C.host_info_t(unsafe.Pointer(&vmstat)), + &infoCount, + ) + if ret != C.KERN_SUCCESS { + return nil, fmt.Errorf("Couldn't get memory statistics, host_statistics returned %d", ret) + } + totalb, err := unix.Sysctl("hw.memsize") + if err != nil { + return nil, err + } + // Syscall removes terminating NUL which we need to cast to uint64 + total := binary.LittleEndian.Uint64([]byte(totalb + "\x00")) + + ps := C.natural_t(syscall.Getpagesize()) + return map[string]float64{ + "active_bytes_total": float64(ps * vmstat.active_count), + "inactive_bytes_total": float64(ps * vmstat.inactive_count), + "wired_bytes_total": float64(ps * vmstat.wire_count), + "free_bytes_total": float64(ps * vmstat.free_count), + "swapped_in_pages_total": float64(ps * vmstat.pageins), + "swapped_out_pages_total": float64(ps * vmstat.pageouts), + "bytes_total": float64(total), + }, nil +}