| 
									
										
										
										
											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.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 08:44:53 -08:00
										 |  |  | // Package collector includes all individual collectors to gather and export system metrics.
 | 
					
						
							| 
									
										
										
										
											2014-02-18 03:35:11 -08:00
										 |  |  | package collector | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 07:16:43 -07:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-02-19 07:11:29 -08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	"log/slog" | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-07 00:25:05 -08:00
										 |  |  | 	"github.com/alecthomas/kingpin/v2" | 
					
						
							| 
									
										
										
										
											2014-10-29 07:16:43 -07:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 08:44:53 -08:00
										 |  |  | // Namespace defines the common namespace to be used by all metrics.
 | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | const namespace = "node" | 
					
						
							| 
									
										
										
										
											2014-02-18 03:35:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	scrapeDurationDesc = prometheus.NewDesc( | 
					
						
							|  |  |  | 		prometheus.BuildFQName(namespace, "scrape", "collector_duration_seconds"), | 
					
						
							|  |  |  | 		"node_exporter: Duration of a collector scrape.", | 
					
						
							|  |  |  | 		[]string{"collector"}, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	scrapeSuccessDesc = prometheus.NewDesc( | 
					
						
							|  |  |  | 		prometheus.BuildFQName(namespace, "scrape", "collector_success"), | 
					
						
							|  |  |  | 		"node_exporter: Whether a collector succeeded.", | 
					
						
							|  |  |  | 		[]string{"collector"}, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-02-18 03:35:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	defaultEnabled  = true | 
					
						
							|  |  |  | 	defaultDisabled = false | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	factories              = make(map[string]func(logger *slog.Logger) (Collector, error)) | 
					
						
							| 
									
										
										
										
											2021-06-04 01:56:42 -07:00
										 |  |  | 	initiatedCollectorsMtx = sync.Mutex{} | 
					
						
							|  |  |  | 	initiatedCollectors    = make(map[string]Collector) | 
					
						
							|  |  |  | 	collectorState         = make(map[string]*bool) | 
					
						
							|  |  |  | 	forcedCollectors       = map[string]bool{} // collectors which have been explicitly enabled or disabled
 | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | func registerCollector(collector string, isDefaultEnabled bool, factory func(logger *slog.Logger) (Collector, error)) { | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	var helpDefaultState string | 
					
						
							|  |  |  | 	if isDefaultEnabled { | 
					
						
							|  |  |  | 		helpDefaultState = "enabled" | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		helpDefaultState = "disabled" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	flagName := fmt.Sprintf("collector.%s", collector) | 
					
						
							|  |  |  | 	flagHelp := fmt.Sprintf("Enable the %s collector (default: %s).", collector, helpDefaultState) | 
					
						
							|  |  |  | 	defaultValue := fmt.Sprintf("%v", isDefaultEnabled) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 02:03:33 -08:00
										 |  |  | 	flag := kingpin.Flag(flagName, flagHelp).Default(defaultValue).Action(collectorFlagAction(collector)).Bool() | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	collectorState[collector] = flag | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	factories[collector] = factory | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NodeCollector implements the prometheus.Collector interface.
 | 
					
						
							| 
									
										
										
										
											2018-10-26 12:39:33 -07:00
										 |  |  | type NodeCollector struct { | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	Collectors map[string]Collector | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	logger     *slog.Logger | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 02:03:33 -08:00
										 |  |  | // DisableDefaultCollectors sets the collector state to false for all collectors which
 | 
					
						
							|  |  |  | // have not been explicitly enabled on the command line.
 | 
					
						
							|  |  |  | func DisableDefaultCollectors() { | 
					
						
							|  |  |  | 	for c := range collectorState { | 
					
						
							|  |  |  | 		if _, ok := forcedCollectors[c]; !ok { | 
					
						
							|  |  |  | 			*collectorState[c] = false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // collectorFlagAction generates a new action function for the given collector
 | 
					
						
							|  |  |  | // to track whether it has been explicitly enabled or disabled from the command line.
 | 
					
						
							|  |  |  | // A new action function is needed for each collector flag because the ParseContext
 | 
					
						
							|  |  |  | // does not contain information about which flag called the action.
 | 
					
						
							|  |  |  | // See: https://github.com/alecthomas/kingpin/issues/294
 | 
					
						
							|  |  |  | func collectorFlagAction(collector string) func(ctx *kingpin.ParseContext) error { | 
					
						
							|  |  |  | 	return func(ctx *kingpin.ParseContext) error { | 
					
						
							|  |  |  | 		forcedCollectors[collector] = true | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-26 12:39:33 -07:00
										 |  |  | // NewNodeCollector creates a new NodeCollector.
 | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | func NewNodeCollector(logger *slog.Logger, filters ...string) (*NodeCollector, error) { | 
					
						
							| 
									
										
										
										
											2017-10-14 05:23:42 -07:00
										 |  |  | 	f := make(map[string]bool) | 
					
						
							|  |  |  | 	for _, filter := range filters { | 
					
						
							|  |  |  | 		enabled, exist := collectorState[filter] | 
					
						
							|  |  |  | 		if !exist { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("missing collector: %s", filter) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !*enabled { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("disabled collector: %s", filter) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		f[filter] = true | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	collectors := make(map[string]Collector) | 
					
						
							| 
									
										
										
										
											2021-06-04 01:56:42 -07:00
										 |  |  | 	initiatedCollectorsMtx.Lock() | 
					
						
							|  |  |  | 	defer initiatedCollectorsMtx.Unlock() | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	for key, enabled := range collectorState { | 
					
						
							| 
									
										
										
										
											2021-06-04 02:35:07 -07:00
										 |  |  | 		if !*enabled || (len(f) > 0 && !f[key]) { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if collector, ok := initiatedCollectors[key]; ok { | 
					
						
							|  |  |  | 			collectors[key] = collector | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 			collector, err := factories[key](logger.With("collector", key)) | 
					
						
							| 
									
										
										
										
											2021-06-04 02:35:07 -07:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							| 
									
										
										
										
											2017-10-14 05:23:42 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-06-04 02:35:07 -07:00
										 |  |  | 			collectors[key] = collector | 
					
						
							|  |  |  | 			initiatedCollectors[key] = collector | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-31 08:19:37 -08:00
										 |  |  | 	return &NodeCollector{Collectors: collectors, logger: logger}, nil | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Describe implements the prometheus.Collector interface.
 | 
					
						
							| 
									
										
										
										
											2018-10-26 12:39:33 -07:00
										 |  |  | func (n NodeCollector) Describe(ch chan<- *prometheus.Desc) { | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	ch <- scrapeDurationDesc | 
					
						
							|  |  |  | 	ch <- scrapeSuccessDesc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Collect implements the prometheus.Collector interface.
 | 
					
						
							| 
									
										
										
										
											2018-10-26 12:39:33 -07:00
										 |  |  | func (n NodeCollector) Collect(ch chan<- prometheus.Metric) { | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	wg := sync.WaitGroup{} | 
					
						
							|  |  |  | 	wg.Add(len(n.Collectors)) | 
					
						
							|  |  |  | 	for name, c := range n.Collectors { | 
					
						
							|  |  |  | 		go func(name string, c Collector) { | 
					
						
							| 
									
										
										
										
											2019-12-31 08:19:37 -08:00
										 |  |  | 			execute(name, c, ch, n.logger) | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 			wg.Done() | 
					
						
							|  |  |  | 		}(name, c) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	wg.Wait() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | func execute(name string, c Collector, ch chan<- prometheus.Metric, logger *slog.Logger) { | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 	begin := time.Now() | 
					
						
							|  |  |  | 	err := c.Update(ch) | 
					
						
							|  |  |  | 	duration := time.Since(begin) | 
					
						
							|  |  |  | 	var success float64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-02-19 07:11:29 -08:00
										 |  |  | 		if IsNoDataError(err) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 			logger.Debug("collector returned no data", "name", name, "duration_seconds", duration.Seconds(), "err", err) | 
					
						
							| 
									
										
										
										
											2020-02-19 07:11:29 -08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 			logger.Error("collector failed", "name", name, "duration_seconds", duration.Seconds(), "err", err) | 
					
						
							| 
									
										
										
										
											2020-02-19 07:11:29 -08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 		success = 0 | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 		logger.Debug("collector succeeded", "name", name, "duration_seconds", duration.Seconds()) | 
					
						
							| 
									
										
										
										
											2017-09-28 06:06:26 -07:00
										 |  |  | 		success = 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ch <- prometheus.MustNewConstMetric(scrapeDurationDesc, prometheus.GaugeValue, duration.Seconds(), name) | 
					
						
							|  |  |  | 	ch <- prometheus.MustNewConstMetric(scrapeSuccessDesc, prometheus.GaugeValue, success, name) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 08:44:53 -08:00
										 |  |  | // Collector is the interface a collector has to implement.
 | 
					
						
							| 
									
										
										
										
											2014-02-18 03:35:11 -08:00
										 |  |  | type Collector interface { | 
					
						
							|  |  |  | 	// Get new metrics and expose them via prometheus registry.
 | 
					
						
							| 
									
										
										
										
											2017-02-28 10:47:20 -08:00
										 |  |  | 	Update(ch chan<- prometheus.Metric) error | 
					
						
							| 
									
										
										
										
											2014-02-18 03:35:11 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-12-28 06:21:31 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type typedDesc struct { | 
					
						
							|  |  |  | 	desc      *prometheus.Desc | 
					
						
							|  |  |  | 	valueType prometheus.ValueType | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *typedDesc) mustNewConstMetric(value float64, labels ...string) prometheus.Metric { | 
					
						
							|  |  |  | 	return prometheus.MustNewConstMetric(d.desc, d.valueType, value, labels...) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-02-19 07:11:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ErrNoData indicates the collector found no data to collect, but had no other error.
 | 
					
						
							|  |  |  | var ErrNoData = errors.New("collector returned no data") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func IsNoDataError(err error) bool { | 
					
						
							|  |  |  | 	return err == ErrNoData | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-29 02:22:25 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // pushMetric helps construct and convert a variety of value types into Prometheus float64 metrics.
 | 
					
						
							|  |  |  | func pushMetric(ch chan<- prometheus.Metric, fieldDesc *prometheus.Desc, name string, value interface{}, valueType prometheus.ValueType, labelValues ...string) { | 
					
						
							|  |  |  | 	var fVal float64 | 
					
						
							|  |  |  | 	switch val := value.(type) { | 
					
						
							|  |  |  | 	case uint8: | 
					
						
							|  |  |  | 		fVal = float64(val) | 
					
						
							|  |  |  | 	case uint16: | 
					
						
							|  |  |  | 		fVal = float64(val) | 
					
						
							|  |  |  | 	case uint32: | 
					
						
							|  |  |  | 		fVal = float64(val) | 
					
						
							|  |  |  | 	case uint64: | 
					
						
							|  |  |  | 		fVal = float64(val) | 
					
						
							|  |  |  | 	case int64: | 
					
						
							|  |  |  | 		fVal = float64(val) | 
					
						
							|  |  |  | 	case *uint8: | 
					
						
							|  |  |  | 		if val == nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fVal = float64(*val) | 
					
						
							|  |  |  | 	case *uint16: | 
					
						
							|  |  |  | 		if val == nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fVal = float64(*val) | 
					
						
							|  |  |  | 	case *uint32: | 
					
						
							|  |  |  | 		if val == nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fVal = float64(*val) | 
					
						
							|  |  |  | 	case *uint64: | 
					
						
							|  |  |  | 		if val == nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fVal = float64(*val) | 
					
						
							|  |  |  | 	case *int64: | 
					
						
							|  |  |  | 		if val == nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fVal = float64(*val) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ch <- prometheus.MustNewConstMetric(fieldDesc, valueType, fVal, labelValues...) | 
					
						
							|  |  |  | } |