diff --git a/plugins/inputs/irqstat/README.md b/plugins/inputs/irqstat/README.md
index b3da55b92589a..3bc83a04195c6 100644
--- a/plugins/inputs/irqstat/README.md
+++ b/plugins/inputs/irqstat/README.md
@@ -1,22 +1,34 @@
# Irqstat Input Plugin
-The irqstat plugin gathers metrics about the interrupt types and associated values for each CPU present on a system.
+The irqstat plugin gathers metrics about the interrupt types and associated values from `/proc/interrupts` and `/proc/softirqs` for each CPU present on a system.
### Configuration
```
[[inputs.irqstat]]
- include = ["0", "1"]
+ include = ["0", "1", "30", "NET_RX"]
```
The above configuration would result in an output similar to:
```
./telegraf -config ~/irqstat_config.conf -test
* Plugin: inputs.irqstat, Collection 1
-> irqstat,host=hostname,cpu=CPU0 1=9i,0=22i 1488751337000000000
+> interrupts,irq=30,type=PCI-MSI,device=65537-edge\ virtio1-input.0,host=hostname CPU0=1i,total=1i 1489346531000000000
+> interrupts,irq=1,host=hostname,type=IO-APIC,device=1-edge\ i8042 CPU0=9i,total=9i 1489346531000000000
+> soft_interrupts,irq=NET_RX,host=hostname CPU0=280879i,total=280879i 1489346531000000000
+> interrupts,irq=0,type=IO-APIC,device=2-edge\ timer,host=hostname CPU0=23i,total=23i 1489346531000000000
```
# Measurements
-There is only one measurement reported by this plugin, `irqstat`:
-- Fields: IRQs
-- Tags: CPUs
+There are two measurements reported by this plugin.
+- `interrupts` reports metrics from the `/proc/interrupts` file
+- `soft_interrupts` reports metrics from the `/proc/softirqs` file
+
+Depending on the content of each file there will multiple tags and fields for each measurement
+- Fields:
+ - CPUx: the IRQ value based on CPU number
+ - Total: total IRQ value of all CPUs
+- Tags:
+ - IRQ: the IRQ
+ - Type: the type associated with the IRQ
+ - Device: the device associated with the IRQ
diff --git a/plugins/inputs/irqstat/irqstat.go b/plugins/inputs/irqstat/irqstat.go
index 130577414d6f2..2b6015e41e77a 100644
--- a/plugins/inputs/irqstat/irqstat.go
+++ b/plugins/inputs/irqstat/irqstat.go
@@ -13,7 +13,6 @@ import (
type Irqstat struct {
Include []string
- Path string
Irqmap map[string]map[string]interface{}
}
@@ -27,13 +26,10 @@ const sampleConfig = `
## A list of IRQs to include for metric ingestion, if not specified
## will default to collecting all IRQs.
# include = ["0", "1"]
- #
- ## The location of the interrupts file, defaults to /proc/interrupts.
- # path = "/some/path/interrupts"
`
func (s *Irqstat) Description() string {
- return "This plugin gathers IRQ types and associated values from /proc/interrupts for each CPU."
+ return "This plugin gathers IRQ types and associated values from /proc/interrupts and /proc/softirqs for each CPU."
}
func (s *Irqstat) SampleConfig() string {
@@ -46,35 +42,51 @@ func (s *Irqstat) ParseIrqFile(path string) {
if err != nil {
log.Fatal(err)
}
-
scanner := bufio.NewScanner(file)
for scanner.Scan() {
+ var irqval int64
+ var irqtotal int64
+ irqdesc := "none"
+ irqdevice := "none"
fields := strings.Fields(scanner.Text())
ff := fields[0]
-
if ff == "CPU0" {
cpucount = len(fields)
}
if ff[len(ff)-1:] == ":" {
- irqtype := ff[:len(ff)-1]
fields = fields[1:len(fields)]
+ irqtype := ff[:len(ff)-1]
+ if path == "/proc/softirqs" {
+ irqtype = irqtype + "_softirq"
+ }
+ _, err := strconv.ParseInt(irqtype, 10, 64)
+ if err == nil {
+ irqdesc = fields[cpucount]
+ irqdevice = strings.Join(fields[cpucount+1:], " ")
+ } else {
+ if len(fields) > cpucount {
+ irqdesc = strings.Join(fields[cpucount:], " ")
+ }
+ }
for i := 0; i < cpucount; i++ {
cpukey := fmt.Sprintf("CPU%d", i)
-
- if s.Irqmap[cpukey] == nil {
- s.Irqmap[cpukey] = make(map[string]interface{})
+ if s.Irqmap[irqtype] == nil {
+ s.Irqmap[irqtype] = make(map[string]interface{})
}
-
- irqval := 0 // Default an IRQ's value to 0
+ irqval = 0
if i < len(fields) {
- irqval, err = strconv.Atoi(fields[i])
+ irqval, err = strconv.ParseInt(fields[i], 10, 64)
if err != nil {
log.Fatal(err)
}
}
- s.Irqmap[cpukey][irqtype] = irqval
+ s.Irqmap[irqtype][cpukey] = irqval
+ irqtotal = irqval + irqtotal
}
+ s.Irqmap[irqtype]["type"] = irqdesc
+ s.Irqmap[irqtype]["device"] = irqdevice
+ s.Irqmap[irqtype]["total"] = irqtotal
}
}
file.Close()
@@ -89,36 +101,44 @@ func stringInSlice(x string, list []string) bool {
return false
}
-func (s *Irqstat) ParseIrqMap(include []string) {
- for cpukey, irqfields := range s.Irqmap {
- s.Irqmap[cpukey] = make(map[string]interface{})
- for irqtype, irqval := range irqfields {
- if stringInSlice(irqtype, include) {
- s.Irqmap[cpukey][irqtype] = irqval
- }
- }
- }
-}
-
func (s *Irqstat) Gather(acc telegraf.Accumulator) error {
- cputags := make(map[string]string)
- path := s.Path
- include := s.Include
-
- if len(path) == 0 {
- path = "/proc/interrupts"
- }
-
- if len(include) == 0 {
- s.ParseIrqFile(path)
- } else {
- s.ParseIrqFile(path)
- s.ParseIrqMap(include)
+ irqtags := make(map[string]string)
+ irqfields := make(map[string]interface{})
+ files := []string{"/proc/interrupts", "/proc/softirqs"}
+ for _, file := range files {
+ s.ParseIrqFile(file)
}
-
- for cpukey, irqfields := range s.Irqmap {
- cputags["cpu"] = cpukey
- acc.AddFields("irqstat", irqfields, cputags)
+ for irq, fields := range s.Irqmap {
+ irqtype := strings.Split(irq, "_softirq")[0]
+ irqtags["irq"] = irqtype
+ for k, v := range fields {
+ switch t := v.(type) {
+ case int64:
+ irqfields[k] = t
+ case string:
+ irqtags[k] = t
+ }
+ }
+ for k, _ := range irqtags {
+ if irqtags[k] == "none" {
+ delete(irqtags, k)
+ }
+ }
+ if len(s.Include) == 0 {
+ if strings.HasSuffix(irq, "_softirq") {
+ acc.AddFields("soft_interrupts", irqfields, irqtags)
+ } else {
+ acc.AddFields("interrupts", irqfields, irqtags)
+ }
+ } else {
+ if stringInSlice(irqtype, s.Include) {
+ if strings.HasSuffix(irq, "_softirq") {
+ acc.AddFields("soft_interrupts", irqfields, irqtags)
+ } else {
+ acc.AddFields("interrupts", irqfields, irqtags)
+ }
+ }
+ }
}
return nil
}