Skip to content

Collector for interrupts fails to parse lines with many interrupts #2557

@dveeden

Description

@dveeden

Host operating system: output of uname -a

This happens on CentOS 7, but looking at the code this is likely to happen on all operating systems.

node_exporter version: output of node_exporter --version

master at 4484f18 but also in older release versions

node_exporter command line flags

--collector.interrupts

node_exporter log output

level=error msg="ERROR: interrupts collector failed after 0.001310s: invalid value Rescheduling in interrupts: strconv.ParseFloat: parsing \"Rescheduling\": invalid syntax" source="collector.go:132"

Are you running node_exporter in Docker?

What did you do that produced an error?

The collector fails on this line of /proc/interrupts:

IPI0:2768808080 2844211768 2878602432 2730576120 2723524623 3349096412 2717389879 2154252810       Rescheduling interrupts

What did you expect to see?

The name of the interrupt being set to IPI0 and the first value to 2768808080.

What did you see instead?

The name of the interrupt being set to IPI0:276880808 and the first value to 2844211768.

Further info

The error happens here: https://github.com/prometheus/node_exporter/blob/master/collector/interrupts_linux.go

With a copy of the problematic /proc/interrupts saved as /tmp/interrupts:

$ go run int.go
CPU Count: 8
Old: Can't parse value as float.
intName: IPI0:276880808
error: strconv.ParseFloat: parsing "Rescheduling": invalid syntax
parts: []string{"IPI0:2768808080", "2844211768", "2878602432", "2730576120", "2723524623", "3349096412", "2717389879", "2154252810", "Rescheduling", "interrupts"}
line: IPI0:2768808080 2844211768 2878602432 2730576120 2723524623 3349096412 2717389879 2154252810       Rescheduling interrupts
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	file, _ := os.Open("/tmp/interrupts")

	scanner := bufio.NewScanner(file)
	scanner.Scan()

	cpuNum := len(strings.Fields(scanner.Text()))
	fmt.Printf("CPU Count: %d\n", cpuNum)

	for scanner.Scan() {
		parts := strings.Fields(scanner.Text())
		if len(parts) > 2 {
			intName := parts[0][:len(parts[0])-1]
			_, err := strconv.ParseFloat(parts[cpuNum], 64)
			if err != nil {
				fmt.Printf("Old: Can't parse value as float.\nintName: %s\nerror: %s\nparts: %#v\nline: %s\n",
					intName, err, parts, scanner.Text())
			}
		}

		p := strings.SplitN(scanner.Text(), ":", 2)
		if len(p) > 1 {
			parts = strings.Fields(p[1])
			if len(parts) > 2 {
				intName := p[0]
				_, err := strconv.ParseFloat(parts[cpuNum-1], 64)
				if err != nil {
					fmt.Printf("New: Can't parse value as float.\nintName: %s\nerror: %s\nparts: %#v\nline: %s\n",
						intName, err, parts, scanner.Text())
				}
			}
		}
	}
}

So it looks like first splitting the line on : and then parsing it into fields might be a solution.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions