Compare commits
1 Commits
master
...
hugepages-
Author | SHA1 | Date |
---|---|---|
Russ Savage | af5017d3dc |
|
@ -0,0 +1,35 @@
|
|||
# Hugepages Input Plugin
|
||||
|
||||
The hugepages plugin gathers hugepages metrics including per NUMA node
|
||||
|
||||
### Configuration:
|
||||
|
||||
```toml
|
||||
# Description
|
||||
[[inputs.hugepages]]
|
||||
## Path to a NUMA nodes
|
||||
# numa_node_path = "/sys/devices/system/node"
|
||||
## Path to a meminfo file
|
||||
# meminfo_path = "/proc/meminfo"
|
||||
```
|
||||
|
||||
### Measurements & Fields:
|
||||
|
||||
- hugepages
|
||||
- free (int, kB)
|
||||
- nr (int, kB)
|
||||
- HugePages_Total (int, kB)
|
||||
- HugePages_Free (int, kB)
|
||||
|
||||
### Tags:
|
||||
|
||||
- hugepages has the following tags:
|
||||
- node
|
||||
|
||||
### Example Output:
|
||||
|
||||
```
|
||||
$ ./telegraf -config telegraf.conf -input-filter hugepages -test
|
||||
> hugepages,host=maxpc,node=node0 free=0i,nr=0i 1467618621000000000
|
||||
> hugepages,host=maxpc,name=meminfo HugePages_Free=0i,HugePages_Total=0i 1467618621000000000
|
||||
```
|
|
@ -0,0 +1,184 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
var (
|
||||
newlineByte = []byte("\n")
|
||||
colonByte = []byte(":")
|
||||
kbPrecisionByte = []byte("kB")
|
||||
)
|
||||
|
||||
// default file paths
|
||||
const (
|
||||
// the path where statistics are kept per NUMA nodes
|
||||
NUMA_NODE_PATH = "/sys/devices/system/node"
|
||||
// the path to the meminfo file which is produced by kernel
|
||||
MEMINFO_PATH = "/proc/meminfo"
|
||||
|
||||
// hugepages stat field names on meminfo file
|
||||
HUGE_PAGES_TOTAL = "HugePages_Total"
|
||||
HUGE_PAGES_FREE = "HugePages_Free"
|
||||
)
|
||||
|
||||
var hugepagesSampleConfig = `
|
||||
## Path to a NUMA nodes
|
||||
# numa_node_path = "/sys/devices/system/node"
|
||||
## Path to a meminfo file
|
||||
# meminfo_path = "/proc/meminfo"
|
||||
`
|
||||
|
||||
// Mem is the
|
||||
type Hugepages struct {
|
||||
NUMANodePath string `toml:"numa_node_path"`
|
||||
MeminfoPath string `toml:"meminfo_path"`
|
||||
}
|
||||
|
||||
func (mem *Hugepages) Description() string {
|
||||
return "Collects hugepages metrics from kernel and per NUMA node"
|
||||
}
|
||||
|
||||
func (mem *Hugepages) SampleConfig() string {
|
||||
return hugepagesSampleConfig
|
||||
}
|
||||
|
||||
func (mem *Hugepages) Gather(acc telegraf.Accumulator) error {
|
||||
mem.loadPaths()
|
||||
err := mem.GatherStatsPerNode(acc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mem.GatherStatsFromMeminfo(acc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GatherHugepagesStatsPerNode collects hugepages stats per NUMA nodes
|
||||
func (mem *Hugepages) GatherStatsPerNode(acc telegraf.Accumulator) error {
|
||||
numaNodeMetrics, err := statsPerNUMA(mem.NUMANodePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k, v := range numaNodeMetrics {
|
||||
metrics := make(map[string]interface{})
|
||||
tags := map[string]string{
|
||||
"node": k,
|
||||
}
|
||||
metrics["free"] = v.Free
|
||||
metrics["nr"] = v.NR
|
||||
acc.AddFields("hugepages", metrics, tags)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GatherHugepagesStatsFromMeminfo collects hugepages statistics from meminfo file
|
||||
func (mem *Hugepages) GatherStatsFromMeminfo(acc telegraf.Accumulator) error {
|
||||
tags := map[string]string{
|
||||
"name": "meminfo",
|
||||
}
|
||||
metrics := make(map[string]interface{})
|
||||
meminfoMetrics, err := statsFromMeminfo(mem.MeminfoPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k, v := range meminfoMetrics {
|
||||
metrics[k] = v
|
||||
}
|
||||
acc.AddFields("hugepages", metrics, tags)
|
||||
return nil
|
||||
}
|
||||
|
||||
type HugepagesNUMAStats struct {
|
||||
Free int
|
||||
NR int
|
||||
}
|
||||
|
||||
// statsPerNUMA gathers hugepages statistics from each NUMA node
|
||||
func statsPerNUMA(path string) (map[string]HugepagesNUMAStats, error) {
|
||||
var hugepagesStats = make(map[string]HugepagesNUMAStats)
|
||||
dirs, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return hugepagesStats, err
|
||||
}
|
||||
|
||||
for _, d := range dirs {
|
||||
if !(d.IsDir() && strings.HasPrefix(d.Name(), "node")) {
|
||||
continue
|
||||
}
|
||||
|
||||
hugepagesFree := fmt.Sprintf("%s/%s/hugepages/hugepages-2048kB/free_hugepages", path, d.Name())
|
||||
hugepagesNR := fmt.Sprintf("%s/%s/hugepages/hugepages-2048kB/nr_hugepages", path, d.Name())
|
||||
|
||||
free, err := ioutil.ReadFile(hugepagesFree)
|
||||
if err != nil {
|
||||
return hugepagesStats, err
|
||||
}
|
||||
|
||||
nr, err := ioutil.ReadFile(hugepagesNR)
|
||||
if err != nil {
|
||||
return hugepagesStats, err
|
||||
}
|
||||
|
||||
f, _ := strconv.Atoi(string(bytes.TrimSuffix(free, newlineByte)))
|
||||
n, _ := strconv.Atoi(string(bytes.TrimSuffix(nr, newlineByte)))
|
||||
|
||||
hugepagesStats[d.Name()] = HugepagesNUMAStats{Free: f, NR: n}
|
||||
|
||||
}
|
||||
return hugepagesStats, nil
|
||||
}
|
||||
|
||||
// statsFromMeminfo gathers hugepages statistics from kernel
|
||||
func statsFromMeminfo(path string) (map[string]interface{}, error) {
|
||||
stats := map[string]interface{}{}
|
||||
meminfo, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
lines := bytes.Split(meminfo, newlineByte)
|
||||
for _, l := range lines {
|
||||
if bytes.Contains(l, kbPrecisionByte) {
|
||||
continue
|
||||
}
|
||||
fields := bytes.Fields(l)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
fieldName := string(bytes.TrimSuffix(fields[0], colonByte))
|
||||
if fieldName == HUGE_PAGES_TOTAL || fieldName == HUGE_PAGES_FREE {
|
||||
val, _ := strconv.Atoi(string(fields[1]))
|
||||
stats[fieldName] = val
|
||||
}
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// loadPaths can be used to read paths firstly from config
|
||||
// if it is empty then try read from env variables
|
||||
func (mem *Hugepages) loadPaths() {
|
||||
if mem.NUMANodePath == "" {
|
||||
mem.NUMANodePath = NUMA_NODE_PATH
|
||||
}
|
||||
if mem.MeminfoPath == "" {
|
||||
mem.MeminfoPath = MEMINFO_PATH
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("hugepages", func() telegraf.Input {
|
||||
return &Hugepages{}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
var hugepages = Hugepages{
|
||||
NUMANodePath: "./testdata/node",
|
||||
MeminfoPath: "./testdata/meminfo",
|
||||
}
|
||||
|
||||
func init() {
|
||||
hugepages.loadPaths()
|
||||
}
|
||||
|
||||
func TestHugepagesStatsFromMeminfo(t *testing.T) {
|
||||
acc := &testutil.Accumulator{}
|
||||
err := hugepages.GatherStatsFromMeminfo(acc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"HugePages_Total": int(666),
|
||||
"HugePages_Free": int(999),
|
||||
}
|
||||
acc.AssertContainsFields(t, "hugepages", fields)
|
||||
}
|
||||
|
||||
func TestHugepagesStatsPerNode(t *testing.T) {
|
||||
acc := &testutil.Accumulator{}
|
||||
err := hugepages.GatherStatsPerNode(acc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fields := map[string]interface{}{
|
||||
"free": int(123),
|
||||
"nr": int(456),
|
||||
}
|
||||
acc.AssertContainsFields(t, "hugepages", fields)
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
MemTotal: 5961204 kB
|
||||
MemFree: 5201764 kB
|
||||
MemAvailable: 5761624 kB
|
||||
Buffers: 120248 kB
|
||||
Cached: 419660 kB
|
||||
SwapCached: 0 kB
|
||||
Active: 370656 kB
|
||||
Inactive: 247364 kB
|
||||
Active(anon): 79032 kB
|
||||
Inactive(anon): 552 kB
|
||||
Active(file): 291624 kB
|
||||
Inactive(file): 246812 kB
|
||||
Unevictable: 0 kB
|
||||
Mlocked: 0 kB
|
||||
SwapTotal: 0 kB
|
||||
SwapFree: 0 kB
|
||||
Dirty: 4 kB
|
||||
Writeback: 0 kB
|
||||
AnonPages: 78164 kB
|
||||
Mapped: 114164 kB
|
||||
Shmem: 1452 kB
|
||||
Slab: 77180 kB
|
||||
SReclaimable: 57676 kB
|
||||
SUnreclaim: 19504 kB
|
||||
KernelStack: 2832 kB
|
||||
PageTables: 8692 kB
|
||||
NFS_Unstable: 0 kB
|
||||
Bounce: 0 kB
|
||||
WritebackTmp: 0 kB
|
||||
CommitLimit: 2980600 kB
|
||||
Committed_AS: 555492 kB
|
||||
VmallocTotal: 34359738367 kB
|
||||
VmallocUsed: 0 kB
|
||||
VmallocChunk: 0 kB
|
||||
HardwareCorrupted: 0 kB
|
||||
AnonHugePages: 0 kB
|
||||
CmaTotal: 0 kB
|
||||
CmaFree: 0 kB
|
||||
HugePages_Total: 666
|
||||
HugePages_Free: 999
|
||||
HugePages_Rsvd: 0
|
||||
HugePages_Surp: 0
|
||||
Hugepagesize: 2048 kB
|
||||
DirectMap4k: 84224 kB
|
||||
DirectMap2M: 6055936 kB
|
1
plugins/inputs/system/testdata/node/node0/hugepages/hugepages-2048kB/free_hugepages
vendored
Normal file
1
plugins/inputs/system/testdata/node/node0/hugepages/hugepages-2048kB/free_hugepages
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
123
|
1
plugins/inputs/system/testdata/node/node0/hugepages/hugepages-2048kB/nr_hugepages
vendored
Normal file
1
plugins/inputs/system/testdata/node/node0/hugepages/hugepages-2048kB/nr_hugepages
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
456
|
Loading…
Reference in New Issue