Merge remote-tracking branch 'influxdata/master'
This commit is contained in:
commit
1bf03fb168
|
@ -1,4 +1,4 @@
|
||||||
## v0.10.5 [unreleased]
|
## v0.11.0 [unreleased]
|
||||||
|
|
||||||
### Release Notes
|
### Release Notes
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
- [#776](https://github.com/influxdata/telegraf/pull/776): Add Zookeeper chroot option to kafka_consumer. Thanks @prune998!
|
- [#776](https://github.com/influxdata/telegraf/pull/776): Add Zookeeper chroot option to kafka_consumer. Thanks @prune998!
|
||||||
- [#811](https://github.com/influxdata/telegraf/pull/811): Add processes plugin for classifying total procs on system. Thanks @titilambert!
|
- [#811](https://github.com/influxdata/telegraf/pull/811): Add processes plugin for classifying total procs on system. Thanks @titilambert!
|
||||||
- [#235](https://github.com/influxdata/telegraf/issues/235): Add number of users to the `system` input plugin.
|
- [#235](https://github.com/influxdata/telegraf/issues/235): Add number of users to the `system` input plugin.
|
||||||
|
- [#826](https://github.com/influxdata/telegraf/pull/826): "kernel" linux plugin for /proc/stat metrics (context switches, interrupts, etc.)
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- [#748](https://github.com/influxdata/telegraf/issues/748): Fix sensor plugin split on ":"
|
- [#748](https://github.com/influxdata/telegraf/issues/748): Fix sensor plugin split on ":"
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
- [#708](https://github.com/influxdata/telegraf/issues/708): packaging: build ARM package
|
- [#708](https://github.com/influxdata/telegraf/issues/708): packaging: build ARM package
|
||||||
- [#713](https://github.com/influxdata/telegraf/issues/713): packaging: insecure permissions error on log directory
|
- [#713](https://github.com/influxdata/telegraf/issues/713): packaging: insecure permissions error on log directory
|
||||||
- [#816](https://github.com/influxdata/telegraf/issues/816): Fix phpfpm panic if fcgi endpoint unreachable.
|
- [#816](https://github.com/influxdata/telegraf/issues/816): Fix phpfpm panic if fcgi endpoint unreachable.
|
||||||
|
- [#828](https://github.com/influxdata/telegraf/issues/828): fix net_response plugin overwriting host tag.
|
||||||
|
|
||||||
## v0.10.4.1
|
## v0.10.4.1
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,7 @@ Currently implemented sources:
|
||||||
* diskio
|
* diskio
|
||||||
* swap
|
* swap
|
||||||
* processes
|
* processes
|
||||||
|
* kernel (/proc/stat)
|
||||||
|
|
||||||
Telegraf can also collect metrics via the following service plugins:
|
Telegraf can also collect metrics via the following service plugins:
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,10 @@
|
||||||
# Uncomment the following line if you do not need disk serial numbers.
|
# Uncomment the following line if you do not need disk serial numbers.
|
||||||
# skip_serial_number = true
|
# skip_serial_number = true
|
||||||
|
|
||||||
|
# Get kernel statistics from /proc/stat
|
||||||
|
[[inputs.kernel]]
|
||||||
|
# no configuration
|
||||||
|
|
||||||
# Read metrics about memory usage
|
# Read metrics about memory usage
|
||||||
[[inputs.mem]]
|
[[inputs.mem]]
|
||||||
# no configuration
|
# no configuration
|
||||||
|
|
|
@ -52,7 +52,7 @@ It can also check response text.
|
||||||
### Tags:
|
### Tags:
|
||||||
|
|
||||||
- All measurements have the following tags:
|
- All measurements have the following tags:
|
||||||
- host
|
- server
|
||||||
- port
|
- port
|
||||||
- protocol
|
- protocol
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ It can also check response text.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ./telegraf -config telegraf.conf -input-filter net_response -test
|
$ ./telegraf -config telegraf.conf -input-filter net_response -test
|
||||||
net_response,host=127.0.0.1,port=22,protocol=tcp response_time=0.18070360500000002,string_found=true 1454785464182527094
|
net_response,server=192.168.2.2,port=22,protocol=tcp response_time=0.18070360500000002,string_found=true 1454785464182527094
|
||||||
net_response,host=127.0.0.1,port=2222,protocol=tcp response_time=1.090124776,string_found=false 1454784433658942325
|
net_response,server=192.168.2.2,port=2222,protocol=tcp response_time=1.090124776,string_found=false 1454784433658942325
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -169,7 +169,7 @@ func (c *NetResponse) Gather(acc telegraf.Accumulator) error {
|
||||||
return errors.New("Bad port")
|
return errors.New("Bad port")
|
||||||
}
|
}
|
||||||
// Prepare data
|
// Prepare data
|
||||||
tags := map[string]string{"host": host, "port": port}
|
tags := map[string]string{"server": host, "port": port}
|
||||||
var fields map[string]interface{}
|
var fields map[string]interface{}
|
||||||
// Gather data
|
// Gather data
|
||||||
if c.Protocol == "tcp" {
|
if c.Protocol == "tcp" {
|
||||||
|
|
|
@ -69,7 +69,7 @@ func TestTCPOK1(t *testing.T) {
|
||||||
"string_found": true,
|
"string_found": true,
|
||||||
"response_time": 1.0,
|
"response_time": 1.0,
|
||||||
},
|
},
|
||||||
map[string]string{"host": "127.0.0.1",
|
map[string]string{"server": "127.0.0.1",
|
||||||
"port": "2004",
|
"port": "2004",
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
},
|
},
|
||||||
|
@ -109,7 +109,7 @@ func TestTCPOK2(t *testing.T) {
|
||||||
"string_found": false,
|
"string_found": false,
|
||||||
"response_time": 1.0,
|
"response_time": 1.0,
|
||||||
},
|
},
|
||||||
map[string]string{"host": "127.0.0.1",
|
map[string]string{"server": "127.0.0.1",
|
||||||
"port": "2004",
|
"port": "2004",
|
||||||
"protocol": "tcp",
|
"protocol": "tcp",
|
||||||
},
|
},
|
||||||
|
@ -164,7 +164,7 @@ func TestUDPOK1(t *testing.T) {
|
||||||
"string_found": true,
|
"string_found": true,
|
||||||
"response_time": 1.0,
|
"response_time": 1.0,
|
||||||
},
|
},
|
||||||
map[string]string{"host": "127.0.0.1",
|
map[string]string{"server": "127.0.0.1",
|
||||||
"port": "2004",
|
"port": "2004",
|
||||||
"protocol": "udp",
|
"protocol": "udp",
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,13 @@ type Snmp struct {
|
||||||
Table []Table
|
Table []Table
|
||||||
Subtable []Subtable
|
Subtable []Subtable
|
||||||
SnmptranslateFile string
|
SnmptranslateFile string
|
||||||
|
|
||||||
|
nameToOid map[string]string
|
||||||
|
initNode Node
|
||||||
|
subTableMap map[string]Subtable
|
||||||
|
|
||||||
|
// TODO change as unexportable
|
||||||
|
//OidInstanceMapping map[string]map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Host struct {
|
type Host struct {
|
||||||
|
@ -110,16 +117,7 @@ type Node struct {
|
||||||
subnodes map[string]Node
|
subnodes map[string]Node
|
||||||
}
|
}
|
||||||
|
|
||||||
var initNode = Node{
|
// TODO move this var to snmp struct
|
||||||
id: "1",
|
|
||||||
name: "",
|
|
||||||
subnodes: make(map[string]Node),
|
|
||||||
}
|
|
||||||
|
|
||||||
var SubTableMap = make(map[string]Subtable)
|
|
||||||
|
|
||||||
var NameToOid = make(map[string]string)
|
|
||||||
|
|
||||||
var OidInstanceMapping = make(map[string]map[string]string)
|
var OidInstanceMapping = make(map[string]map[string]string)
|
||||||
|
|
||||||
var sampleConfig = `
|
var sampleConfig = `
|
||||||
|
@ -286,14 +284,24 @@ func findnodename(node Node, ids []string) (string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Snmp) Gather(acc telegraf.Accumulator) error {
|
func (s *Snmp) Gather(acc telegraf.Accumulator) error {
|
||||||
|
// TODO put this in cache on first run
|
||||||
// Create subtables mapping
|
// Create subtables mapping
|
||||||
if len(SubTableMap) == 0 {
|
if len(s.subTableMap) == 0 {
|
||||||
|
s.subTableMap = make(map[string]Subtable)
|
||||||
for _, sb := range s.Subtable {
|
for _, sb := range s.Subtable {
|
||||||
SubTableMap[sb.Name] = sb
|
s.subTableMap[sb.Name] = sb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO put this in cache on first run
|
||||||
// Create oid tree
|
// Create oid tree
|
||||||
if s.SnmptranslateFile != "" && len(initNode.subnodes) == 0 {
|
if s.SnmptranslateFile != "" && len(s.initNode.subnodes) == 0 {
|
||||||
|
s.nameToOid = make(map[string]string)
|
||||||
|
s.initNode = Node{
|
||||||
|
id: "1",
|
||||||
|
name: "",
|
||||||
|
subnodes: make(map[string]Node),
|
||||||
|
}
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(s.SnmptranslateFile)
|
data, err := ioutil.ReadFile(s.SnmptranslateFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Reading SNMPtranslate file error: %s", err)
|
log.Printf("Reading SNMPtranslate file error: %s", err)
|
||||||
|
@ -305,8 +313,8 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
|
||||||
if oids[2] != "" {
|
if oids[2] != "" {
|
||||||
oid_name := oids[1]
|
oid_name := oids[1]
|
||||||
oid := oids[2]
|
oid := oids[2]
|
||||||
fillnode(initNode, oid_name, strings.Split(string(oid), "."))
|
fillnode(s.initNode, oid_name, strings.Split(string(oid), "."))
|
||||||
NameToOid[oid_name] = oid
|
s.nameToOid[oid_name] = oid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,7 +338,7 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
|
||||||
// Get Easy GET oids
|
// Get Easy GET oids
|
||||||
for _, oidstring := range host.GetOids {
|
for _, oidstring := range host.GetOids {
|
||||||
oid := Data{}
|
oid := Data{}
|
||||||
if val, ok := NameToOid[oidstring]; ok {
|
if val, ok := s.nameToOid[oidstring]; ok {
|
||||||
// TODO should we add the 0 instance ?
|
// TODO should we add the 0 instance ?
|
||||||
oid.Name = oidstring
|
oid.Name = oidstring
|
||||||
oid.Oid = val
|
oid.Oid = val
|
||||||
|
@ -351,7 +359,7 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
|
||||||
// Get GET oids
|
// Get GET oids
|
||||||
for _, oid := range s.Get {
|
for _, oid := range s.Get {
|
||||||
if oid.Name == oid_name {
|
if oid.Name == oid_name {
|
||||||
if val, ok := NameToOid[oid.Oid]; ok {
|
if val, ok := s.nameToOid[oid.Oid]; ok {
|
||||||
// TODO should we add the 0 instance ?
|
// TODO should we add the 0 instance ?
|
||||||
if oid.Instance != "" {
|
if oid.Instance != "" {
|
||||||
oid.rawOid = "." + val + "." + oid.Instance
|
oid.rawOid = "." + val + "." + oid.Instance
|
||||||
|
@ -367,7 +375,7 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
|
||||||
// Get GETBULK oids
|
// Get GETBULK oids
|
||||||
for _, oid := range s.Bulk {
|
for _, oid := range s.Bulk {
|
||||||
if oid.Name == oid_name {
|
if oid.Name == oid_name {
|
||||||
if val, ok := NameToOid[oid.Oid]; ok {
|
if val, ok := s.nameToOid[oid.Oid]; ok {
|
||||||
oid.rawOid = "." + val
|
oid.rawOid = "." + val
|
||||||
} else {
|
} else {
|
||||||
oid.rawOid = oid.Oid
|
oid.rawOid = oid.Oid
|
||||||
|
@ -389,26 +397,27 @@ func (s *Snmp) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Launch Mapping
|
// Launch Mapping
|
||||||
|
// TODO put this in cache on first run
|
||||||
// TODO save mapping and computed oids
|
// TODO save mapping and computed oids
|
||||||
// to do it only the first time
|
// to do it only the first time
|
||||||
// only if len(OidInstanceMapping) == 0
|
// only if len(s.OidInstanceMapping) == 0
|
||||||
if len(OidInstanceMapping) >= 0 {
|
if len(OidInstanceMapping) >= 0 {
|
||||||
if err := host.SNMPMap(acc); err != nil {
|
if err := host.SNMPMap(acc, s.nameToOid, s.subTableMap); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Launch Get requests
|
// Launch Get requests
|
||||||
if err := host.SNMPGet(acc); err != nil {
|
if err := host.SNMPGet(acc, s.initNode); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := host.SNMPBulk(acc); err != nil {
|
if err := host.SNMPBulk(acc, s.initNode); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) SNMPMap(acc telegraf.Accumulator) error {
|
func (h *Host) SNMPMap(acc telegraf.Accumulator, nameToOid map[string]string, subTableMap map[string]Subtable) error {
|
||||||
// Get snmp client
|
// Get snmp client
|
||||||
snmpClient, err := h.GetSNMPClient()
|
snmpClient, err := h.GetSNMPClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -426,7 +435,7 @@ func (h *Host) SNMPMap(acc telegraf.Accumulator) error {
|
||||||
// This is just a bulk request
|
// This is just a bulk request
|
||||||
oid := Data{}
|
oid := Data{}
|
||||||
oid.Oid = table.oid
|
oid.Oid = table.oid
|
||||||
if val, ok := NameToOid[oid.Oid]; ok {
|
if val, ok := nameToOid[oid.Oid]; ok {
|
||||||
oid.rawOid = "." + val
|
oid.rawOid = "." + val
|
||||||
} else {
|
} else {
|
||||||
oid.rawOid = oid.Oid
|
oid.rawOid = oid.Oid
|
||||||
|
@ -441,7 +450,7 @@ func (h *Host) SNMPMap(acc telegraf.Accumulator) error {
|
||||||
// ... we create a new Data (oid) object
|
// ... we create a new Data (oid) object
|
||||||
oid := Data{}
|
oid := Data{}
|
||||||
// Looking for more information about this subtable
|
// Looking for more information about this subtable
|
||||||
ssb, exists := SubTableMap[sb]
|
ssb, exists := subTableMap[sb]
|
||||||
if exists {
|
if exists {
|
||||||
// We found a subtable section in config files
|
// We found a subtable section in config files
|
||||||
oid.Oid = ssb.Oid
|
oid.Oid = ssb.Oid
|
||||||
|
@ -528,7 +537,7 @@ func (h *Host) SNMPMap(acc telegraf.Accumulator) error {
|
||||||
// Add table oid in bulk oid list
|
// Add table oid in bulk oid list
|
||||||
oid := Data{}
|
oid := Data{}
|
||||||
oid.Oid = table.oid
|
oid.Oid = table.oid
|
||||||
if val, ok := NameToOid[oid.Oid]; ok {
|
if val, ok := nameToOid[oid.Oid]; ok {
|
||||||
oid.rawOid = "." + val
|
oid.rawOid = "." + val
|
||||||
} else {
|
} else {
|
||||||
oid.rawOid = oid.Oid
|
oid.rawOid = oid.Oid
|
||||||
|
@ -545,7 +554,7 @@ func (h *Host) SNMPMap(acc telegraf.Accumulator) error {
|
||||||
// ... we create a new Data (oid) object
|
// ... we create a new Data (oid) object
|
||||||
oid := Data{}
|
oid := Data{}
|
||||||
// Looking for more information about this subtable
|
// Looking for more information about this subtable
|
||||||
ssb, exists := SubTableMap[sb]
|
ssb, exists := subTableMap[sb]
|
||||||
if exists {
|
if exists {
|
||||||
// We found a subtable section in config files
|
// We found a subtable section in config files
|
||||||
oid.Oid = ssb.Oid + key
|
oid.Oid = ssb.Oid + key
|
||||||
|
@ -587,7 +596,7 @@ func (h *Host) SNMPMap(acc telegraf.Accumulator) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) SNMPGet(acc telegraf.Accumulator) error {
|
func (h *Host) SNMPGet(acc telegraf.Accumulator, initNode Node) error {
|
||||||
// Get snmp client
|
// Get snmp client
|
||||||
snmpClient, err := h.GetSNMPClient()
|
snmpClient, err := h.GetSNMPClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -620,7 +629,7 @@ func (h *Host) SNMPGet(acc telegraf.Accumulator) error {
|
||||||
return err3
|
return err3
|
||||||
}
|
}
|
||||||
// Handle response
|
// Handle response
|
||||||
_, err = h.HandleResponse(oidsList, result, acc)
|
_, err = h.HandleResponse(oidsList, result, acc, initNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -628,7 +637,7 @@ func (h *Host) SNMPGet(acc telegraf.Accumulator) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) SNMPBulk(acc telegraf.Accumulator) error {
|
func (h *Host) SNMPBulk(acc telegraf.Accumulator, initNode Node) error {
|
||||||
// Get snmp client
|
// Get snmp client
|
||||||
snmpClient, err := h.GetSNMPClient()
|
snmpClient, err := h.GetSNMPClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -663,7 +672,7 @@ func (h *Host) SNMPBulk(acc telegraf.Accumulator) error {
|
||||||
return err3
|
return err3
|
||||||
}
|
}
|
||||||
// Handle response
|
// Handle response
|
||||||
last_oid, err := h.HandleResponse(oidsList, result, acc)
|
last_oid, err := h.HandleResponse(oidsList, result, acc, initNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -715,7 +724,7 @@ func (h *Host) GetSNMPClient() (*gosnmp.GoSNMP, error) {
|
||||||
return snmpClient, nil
|
return snmpClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Host) HandleResponse(oids map[string]Data, result *gosnmp.SnmpPacket, acc telegraf.Accumulator) (string, error) {
|
func (h *Host) HandleResponse(oids map[string]Data, result *gosnmp.SnmpPacket, acc telegraf.Accumulator, initNode Node) (string, error) {
|
||||||
var lastOid string
|
var lastOid string
|
||||||
for _, variable := range result.Variables {
|
for _, variable := range result.Variables {
|
||||||
lastOid = variable.Name
|
lastOid = variable.Name
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
# 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`)
|
||||||
|
|
||||||
|
### 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 1457613402960879816
|
||||||
|
```
|
|
@ -0,0 +1,110 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
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")
|
||||||
|
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"] = int64(m)
|
||||||
|
case bytes.Equal(field, context_switches):
|
||||||
|
m, err := strconv.Atoi(string(dataFields[i+1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fields["context_switches"] = int64(m)
|
||||||
|
case bytes.Equal(field, processes_forked):
|
||||||
|
m, err := strconv.Atoi(string(dataFields[i+1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fields["processes_forked"] = int64(m)
|
||||||
|
case bytes.Equal(field, boot_time):
|
||||||
|
m, err := strconv.Atoi(string(dataFields[i+1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fields["boot_time"] = int64(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"] = int64(in)
|
||||||
|
fields["disk_pages_out"] = int64(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",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf/testutil"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFullProcFile(t *testing.T) {
|
||||||
|
tmpfile := makeFakeStatFile([]byte(statFile_Full))
|
||||||
|
defer os.Remove(tmpfile)
|
||||||
|
|
||||||
|
k := Kernel{
|
||||||
|
statFile: tmpfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
acc := testutil.Accumulator{}
|
||||||
|
err := k.Gather(&acc)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"boot_time": int64(1457505775),
|
||||||
|
"context_switches": int64(2626618),
|
||||||
|
"disk_pages_in": int64(5741),
|
||||||
|
"disk_pages_out": int64(1808),
|
||||||
|
"interrupts": int64(1472736),
|
||||||
|
"processes_forked": int64(10673),
|
||||||
|
}
|
||||||
|
acc.AssertContainsFields(t, "kernel", fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPartialProcFile(t *testing.T) {
|
||||||
|
tmpfile := makeFakeStatFile([]byte(statFile_Partial))
|
||||||
|
defer os.Remove(tmpfile)
|
||||||
|
|
||||||
|
k := Kernel{
|
||||||
|
statFile: tmpfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
acc := testutil.Accumulator{}
|
||||||
|
err := k.Gather(&acc)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
fields := map[string]interface{}{
|
||||||
|
"boot_time": int64(1457505775),
|
||||||
|
"context_switches": int64(2626618),
|
||||||
|
"disk_pages_in": int64(5741),
|
||||||
|
"disk_pages_out": int64(1808),
|
||||||
|
"interrupts": int64(1472736),
|
||||||
|
}
|
||||||
|
acc.AssertContainsFields(t, "kernel", fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidProcFile1(t *testing.T) {
|
||||||
|
tmpfile := makeFakeStatFile([]byte(statFile_Invalid))
|
||||||
|
defer os.Remove(tmpfile)
|
||||||
|
|
||||||
|
k := Kernel{
|
||||||
|
statFile: tmpfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
acc := testutil.Accumulator{}
|
||||||
|
err := k.Gather(&acc)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidProcFile2(t *testing.T) {
|
||||||
|
tmpfile := makeFakeStatFile([]byte(statFile_Invalid2))
|
||||||
|
defer os.Remove(tmpfile)
|
||||||
|
|
||||||
|
k := Kernel{
|
||||||
|
statFile: tmpfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
acc := testutil.Accumulator{}
|
||||||
|
err := k.Gather(&acc)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoProcFile(t *testing.T) {
|
||||||
|
tmpfile := makeFakeStatFile([]byte(statFile_Invalid2))
|
||||||
|
os.Remove(tmpfile)
|
||||||
|
|
||||||
|
k := Kernel{
|
||||||
|
statFile: tmpfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
acc := testutil.Accumulator{}
|
||||||
|
err := k.Gather(&acc)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
const statFile_Full = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||||
|
ctxt 2626618
|
||||||
|
btime 1457505775
|
||||||
|
processes 10673
|
||||||
|
procs_running 2
|
||||||
|
procs_blocked 0
|
||||||
|
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||||
|
page 5741 1808
|
||||||
|
swap 1 0
|
||||||
|
`
|
||||||
|
|
||||||
|
const statFile_Partial = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||||
|
ctxt 2626618
|
||||||
|
btime 1457505775
|
||||||
|
procs_running 2
|
||||||
|
procs_blocked 0
|
||||||
|
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||||
|
page 5741 1808
|
||||||
|
`
|
||||||
|
|
||||||
|
// missing btime measurement
|
||||||
|
const statFile_Invalid = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||||
|
ctxt 2626618
|
||||||
|
btime
|
||||||
|
processes 10673
|
||||||
|
procs_running 2
|
||||||
|
procs_blocked 0
|
||||||
|
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||||
|
page 5741 1808
|
||||||
|
swap 1 0
|
||||||
|
`
|
||||||
|
|
||||||
|
// missing second page measurement
|
||||||
|
const statFile_Invalid2 = `cpu 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
cpu0 6796 252 5655 10444977 175 0 101 0 0 0
|
||||||
|
intr 1472736 57 10 0 0 0 0 0 0 0 0 0 0 156 0 0 0 0 0 0 111551 42541 12356 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||||
|
ctxt 2626618
|
||||||
|
processes 10673
|
||||||
|
procs_running 2
|
||||||
|
page 5741
|
||||||
|
procs_blocked 0
|
||||||
|
softirq 1031662 0 649485 20946 111071 11620 0 1 0 994 237545
|
||||||
|
`
|
||||||
|
|
||||||
|
func makeFakeStatFile(content []byte) string {
|
||||||
|
tmpfile, err := ioutil.TempFile("", "kerneltest")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := tmpfile.Write(content); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := tmpfile.Close(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpfile.Name()
|
||||||
|
}
|
Loading…
Reference in New Issue