Skip to content

Commit

Permalink
Add a "kernel" plugin for /proc/stat statistics
Browse files Browse the repository at this point in the history
see #235
  • Loading branch information
sparrc committed Mar 10, 2016
1 parent 0752879 commit 2bc8728
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
66 changes: 66 additions & 0 deletions plugins/inputs/system/KERNEL_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Kernel Input Plugin

This plugin is only available on Linux.

The kernel plugin gathers info about the kernel that doesn't fit into other
plugins. In general, it is the statistics available in `/proc/stat` that are
not covered by other plugins.

The metrics are documented in `man proc` under the `/proc/stat` section.

```
/proc/stat
kernel/system statistics. Varies with architecture. Common entries include:
page 5741 1808
The number of pages the system paged in and the number that were paged out (from disk).
swap 1 0
The number of swap pages that have been brought in and out.
intr 1462898
This line shows counts of interrupts serviced since boot time, for each of
the possible system interrupts. The first column is the total of all
interrupts serviced; each subsequent column is the total for a particular interrupt.
ctxt 115315
The number of context switches that the system underwent.
btime 769041601
boot time, in seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
processes 86031
Number of forks since boot.
```

### Configuration:

```toml
# Get kernel statistics from /proc/stat
[[inputs.kernel]]
# no configuration
```

### Measurements & Fields:

- kernel
- boot_time (integer, seconds since epoch, `btime`)
- context_switches (integer, `ctxt`)
- disk_pages_in (integer, `page (0)`)
- disk_pages_out (integer, `page (1)`)
- interrupts (integer, `intr`)
- processes_forked (integer, `processes`)
- swap_pages_in (integer, `swap (0)`)
- swap_pages_out (integer, `swap (1)`)

### Tags:

None

### Example Output:

```
$ telegraf -config ~/ws/telegraf.conf -input-filter kernel -test
* Plugin: kernel, Collection 1
> kernel boot_time=1457505775i,context_switches=2626618i,disk_pages_in=5741i,disk_pages_out=1808i,interrupts=1472736i,processes_forked=10673i,swap_pages_in=1i,swap_pages_out=0i 1457613402960879816
```
122 changes: 122 additions & 0 deletions plugins/inputs/system/kernel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package system

// TODO add // +build linux

import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strconv"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)

// /proc/stat file line prefixes to gather stats on:
var (
interrupts = []byte("intr")
context_switches = []byte("ctxt")
processes_forked = []byte("processes")
disk_pages = []byte("page")
swap_pages = []byte("swap")
boot_time = []byte("btime")
)

type Kernel struct {
statFile string
}

func (k *Kernel) Description() string {
return "Get kernel statistics from /proc/stat"
}

func (k *Kernel) SampleConfig() string { return "" }

func (k *Kernel) Gather(acc telegraf.Accumulator) error {
data, err := k.getProcStat()
if err != nil {
return err
}

fields := make(map[string]interface{})

dataFields := bytes.Fields(data)
for i, field := range dataFields {
switch {
case bytes.Equal(field, interrupts):
m, err := strconv.Atoi(string(dataFields[i+1]))
if err != nil {
return err
}
fields["interrupts"] = m
case bytes.Equal(field, context_switches):
m, err := strconv.Atoi(string(dataFields[i+1]))
if err != nil {
return err
}
fields["context_switches"] = m
case bytes.Equal(field, processes_forked):
m, err := strconv.Atoi(string(dataFields[i+1]))
if err != nil {
return err
}
fields["processes_forked"] = m
case bytes.Equal(field, boot_time):
m, err := strconv.Atoi(string(dataFields[i+1]))
if err != nil {
return err
}
fields["boot_time"] = m
case bytes.Equal(field, disk_pages):
in, err := strconv.Atoi(string(dataFields[i+1]))
if err != nil {
return err
}
out, err := strconv.Atoi(string(dataFields[i+2]))
if err != nil {
return err
}
fields["disk_pages_in"] = in
fields["disk_pages_out"] = out
case bytes.Equal(field, swap_pages):
in, err := strconv.Atoi(string(dataFields[i+1]))
if err != nil {
return err
}
out, err := strconv.Atoi(string(dataFields[i+2]))
if err != nil {
return err
}
fields["swap_pages_in"] = in
fields["swap_pages_out"] = out
}
}

acc.AddFields("kernel", fields, map[string]string{})

return nil
}

func (k *Kernel) getProcStat() ([]byte, error) {
if _, err := os.Stat(k.statFile); os.IsNotExist(err) {
return nil, fmt.Errorf("kernel: %s does not exist!", k.statFile)
} else if err != nil {
return nil, err
}

data, err := ioutil.ReadFile(k.statFile)
if err != nil {
return nil, err
}

return data, nil
}

func init() {
inputs.Add("kernel", func() telegraf.Input {
return &Kernel{
statFile: "/proc/stat",
}
})
}
1 change: 1 addition & 0 deletions plugins/inputs/system/kernel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package system

0 comments on commit 2bc8728

Please sign in to comment.