| 
									
										
										
										
											2015-09-26 08:36:40 -07:00
										 |  |  | // Copyright 2015 The Prometheus Authors
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-03 04:35:24 -07:00
										 |  |  | //go:build !nointerrupts
 | 
					
						
							| 
									
										
										
										
											2015-05-12 04:06:41 -07:00
										 |  |  | // +build !nointerrupts
 | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | package collector | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2015-09-26 05:53:46 -07:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-01 22:55:46 -08:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2018-03-08 06:04:49 -08:00
										 |  |  | 	interruptLabelNames = []string{"cpu", "type", "info", "devices"} | 
					
						
							| 
									
										
										
										
											2015-11-01 22:55:46 -08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 07:16:43 -07:00
										 |  |  | func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) (err error) { | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 	interrupts, err := getInterrupts() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-15 13:27:14 -07:00
										 |  |  | 		return fmt.Errorf("couldn't get interrupts: %w", err) | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	for name, interrupt := range interrupts { | 
					
						
							|  |  |  | 		for cpuNo, value := range interrupt.values { | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 			filterName := name + ";" + interrupt.info + ";" + interrupt.devices | 
					
						
							|  |  |  | 			if c.nameFilter.ignored(filterName) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 				c.logger.Debug("ignoring interrupt name", "filter_name", filterName) | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 			fv, err := strconv.ParseFloat(value, 64) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-15 13:27:14 -07:00
										 |  |  | 				return fmt.Errorf("invalid value %s in interrupts: %w", value, err) | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 			if !c.includeZeros && fv == 0.0 { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 				c.logger.Debug("ignoring interrupt with zero value", "filter_name", filterName, "cpu", cpuNo) | 
					
						
							| 
									
										
										
										
											2024-07-14 07:17:20 -07:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-12-28 06:21:31 -08:00
										 |  |  | 			ch <- c.desc.mustNewConstMetric(fv, strconv.Itoa(cpuNo), name, interrupt.info, interrupt.devices) | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-29 07:16:43 -07:00
										 |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type interrupt struct { | 
					
						
							|  |  |  | 	info    string | 
					
						
							|  |  |  | 	devices string | 
					
						
							|  |  |  | 	values  []string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func getInterrupts() (map[string]interrupt, error) { | 
					
						
							| 
									
										
										
										
											2015-09-26 05:53:46 -07:00
										 |  |  | 	file, err := os.Open(procFilePath("interrupts")) | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-24 15:30:07 -08:00
										 |  |  | 	defer file.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 	return parseInterrupts(file) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-24 15:30:07 -08:00
										 |  |  | func parseInterrupts(r io.Reader) (map[string]interrupt, error) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		interrupts = map[string]interrupt{} | 
					
						
							|  |  |  | 		scanner    = bufio.NewScanner(r) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 	if !scanner.Scan() { | 
					
						
							| 
									
										
										
										
											2015-09-26 05:53:46 -07:00
										 |  |  | 		return nil, errors.New("interrupts empty") | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-28 09:42:43 -08:00
										 |  |  | 	cpuNum := len(strings.Fields(scanner.Text())) // one header per cpu
 | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for scanner.Scan() { | 
					
						
							| 
									
										
										
										
											2023-03-10 04:02:33 -08:00
										 |  |  | 		// On aarch64 there can be zero space between the name/label
 | 
					
						
							|  |  |  | 		// and the values, so we need to split on `:` before using
 | 
					
						
							|  |  |  | 		// strings.Fields() to split on fields.
 | 
					
						
							|  |  |  | 		group := strings.SplitN(scanner.Text(), ":", 2) | 
					
						
							|  |  |  | 		if len(group) > 1 { | 
					
						
							|  |  |  | 			parts := strings.Fields(group[1]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if len(parts) < cpuNum+1 { // irq + one column per cpu + details,
 | 
					
						
							|  |  |  | 				continue // we ignore ERR and MIS for now
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			intName := strings.TrimLeft(group[0], " ") | 
					
						
							|  |  |  | 			intr := interrupt{ | 
					
						
							|  |  |  | 				values: parts[0:cpuNum], | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-10 04:02:33 -08:00
										 |  |  | 			if _, err := strconv.Atoi(intName); err == nil { // numeral interrupt
 | 
					
						
							|  |  |  | 				intr.info = parts[cpuNum] | 
					
						
							|  |  |  | 				intr.devices = strings.Join(parts[cpuNum+1:], " ") | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				intr.info = strings.Join(parts[cpuNum:], " ") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			interrupts[intName] = intr | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-24 15:30:07 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 10:31:35 -08:00
										 |  |  | 	return interrupts, scanner.Err() | 
					
						
							| 
									
										
										
										
											2014-06-04 04:12:34 -07:00
										 |  |  | } |