| 
									
										
										
										
											2021-02-02 13:40:59 -08:00
										 |  |  | // Copyright 2021 The Prometheus Authors
 | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | // 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.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 06:29:03 -07:00
										 |  |  | //go:build !nofibrechannel
 | 
					
						
							|  |  |  | // +build !nofibrechannel
 | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | package collector | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	"log/slog" | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							| 
									
										
										
										
											2024-07-10 06:58:57 -07:00
										 |  |  | 	"github.com/prometheus/node_exporter/collector/utils" | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 	"github.com/prometheus/procfs/sysfs" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const maxUint64 = ^uint64(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type fibrechannelCollector struct { | 
					
						
							|  |  |  | 	fs          sysfs.FS | 
					
						
							|  |  |  | 	metricDescs map[string]*prometheus.Desc | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 	logger      *slog.Logger | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 	subsystem   string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	registerCollector("fibrechannel", defaultEnabled, NewFibreChannelCollector) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewFibreChannelCollector returns a new Collector exposing FibreChannel stats.
 | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | func NewFibreChannelCollector(logger *slog.Logger) (Collector, error) { | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 	var i fibrechannelCollector | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i.fs, err = sysfs.NewFS(*sysPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("failed to open sysfs: %w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	i.logger = logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Detailed description for all metrics.
 | 
					
						
							|  |  |  | 	descriptions := map[string]string{ | 
					
						
							| 
									
										
										
										
											2020-07-13 09:00:43 -07:00
										 |  |  | 		"dumped_frames_total":            "Number of dumped frames", | 
					
						
							|  |  |  | 		"loss_of_signal_total":           "Number of times signal has been lost", | 
					
						
							|  |  |  | 		"loss_of_sync_total":             "Number of failures on either bit or transmission word boundaries", | 
					
						
							|  |  |  | 		"rx_frames_total":                "Number of frames received", | 
					
						
							|  |  |  | 		"error_frames_total":             "Number of errors in frames", | 
					
						
							| 
									
										
										
										
											2021-01-29 07:28:22 -08:00
										 |  |  | 		"invalid_tx_words_total":         "Number of invalid words transmitted by host port", | 
					
						
							| 
									
										
										
										
											2020-07-13 09:00:43 -07:00
										 |  |  | 		"seconds_since_last_reset_total": "Number of seconds since last host port reset", | 
					
						
							|  |  |  | 		"tx_words_total":                 "Number of words transmitted by host port", | 
					
						
							|  |  |  | 		"invalid_crc_total":              "Invalid Cyclic Redundancy Check count", | 
					
						
							|  |  |  | 		"nos_total":                      "Number Not_Operational Primitive Sequence received by host port", | 
					
						
							|  |  |  | 		"fcp_packet_aborts_total":        "Number of aborted packets", | 
					
						
							|  |  |  | 		"rx_words_total":                 "Number of words received by host port", | 
					
						
							|  |  |  | 		"tx_frames_total":                "Number of frames transmitted by host port", | 
					
						
							|  |  |  | 		"link_failure_total":             "Number of times the host port link has failed", | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i.metricDescs = make(map[string]*prometheus.Desc) | 
					
						
							|  |  |  | 	i.subsystem = "fibrechannel" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for metricName, description := range descriptions { | 
					
						
							|  |  |  | 		i.metricDescs[metricName] = prometheus.NewDesc( | 
					
						
							|  |  |  | 			prometheus.BuildFQName(namespace, i.subsystem, metricName), | 
					
						
							|  |  |  | 			description, | 
					
						
							| 
									
										
										
										
											2021-02-02 15:05:24 -08:00
										 |  |  | 			[]string{"fc_host"}, | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 			nil, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &i, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *fibrechannelCollector) pushMetric(ch chan<- prometheus.Metric, name string, value uint64, host string, valueType prometheus.ValueType) { | 
					
						
							|  |  |  | 	ch <- prometheus.MustNewConstMetric(c.metricDescs[name], valueType, float64(value), host) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *fibrechannelCollector) pushCounter(ch chan<- prometheus.Metric, name string, value uint64, host string) { | 
					
						
							|  |  |  | 	// Don't push counters that aren't implemented (a counter equal to maxUint64 is unimplemented by the HBA firmware)
 | 
					
						
							|  |  |  | 	if value != maxUint64 { | 
					
						
							|  |  |  | 		c.pushMetric(ch, name, value, host, prometheus.CounterValue) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *fibrechannelCollector) Update(ch chan<- prometheus.Metric) error { | 
					
						
							|  |  |  | 	hosts, err := c.fs.FibreChannelClass() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if os.IsNotExist(err) { | 
					
						
							| 
									
										
										
										
											2024-09-11 01:51:28 -07:00
										 |  |  | 			c.logger.Debug("fibrechannel statistics not found, skipping") | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 			return ErrNoData | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return fmt.Errorf("error obtaining FibreChannel class info: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, host := range hosts { | 
					
						
							|  |  |  | 		infoDesc := prometheus.NewDesc( | 
					
						
							|  |  |  | 			prometheus.BuildFQName(namespace, c.subsystem, "info"), | 
					
						
							|  |  |  | 			"Non-numeric data from /sys/class/fc_host/<host>, value is always 1.", | 
					
						
							| 
									
										
										
										
											2021-02-03 06:35:58 -08:00
										 |  |  | 			[]string{"fc_host", "speed", "port_state", "port_type", "port_id", "port_name", "fabric_name", "symbolic_name", "supported_classes", "supported_speeds", "dev_loss_tmo"}, | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 			nil, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 		infoValue := 1.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// First push the Host values
 | 
					
						
							| 
									
										
										
										
											2024-07-10 06:58:57 -07:00
										 |  |  | 		ch <- prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, infoValue, utils.SafeDereference( | 
					
						
							|  |  |  | 			host.Name, | 
					
						
							|  |  |  | 			host.Speed, | 
					
						
							|  |  |  | 			host.PortState, | 
					
						
							|  |  |  | 			host.PortType, | 
					
						
							|  |  |  | 			host.PortID, | 
					
						
							|  |  |  | 			host.PortName, | 
					
						
							|  |  |  | 			host.FabricName, | 
					
						
							|  |  |  | 			host.SymbolicName, | 
					
						
							|  |  |  | 			host.SupportedClasses, | 
					
						
							|  |  |  | 			host.SupportedSpeeds, | 
					
						
							|  |  |  | 			host.DevLossTMO, | 
					
						
							|  |  |  | 		)...) | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Then the counters
 | 
					
						
							| 
									
										
										
										
											2024-07-10 06:58:57 -07:00
										 |  |  | 		// Note: `procfs` guarantees these a safe dereference for these counters.
 | 
					
						
							|  |  |  | 		c.pushCounter(ch, "dumped_frames_total", *host.Counters.DumpedFrames, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "error_frames_total", *host.Counters.ErrorFrames, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "invalid_crc_total", *host.Counters.InvalidCRCCount, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "rx_frames_total", *host.Counters.RXFrames, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "rx_words_total", *host.Counters.RXWords, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "tx_frames_total", *host.Counters.TXFrames, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "tx_words_total", *host.Counters.TXWords, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "seconds_since_last_reset_total", *host.Counters.SecondsSinceLastReset, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "invalid_tx_words_total", *host.Counters.InvalidTXWordCount, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "link_failure_total", *host.Counters.LinkFailureCount, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "loss_of_sync_total", *host.Counters.LossOfSyncCount, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "loss_of_signal_total", *host.Counters.LossOfSignalCount, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "nos_total", *host.Counters.NosCount, *host.Name) | 
					
						
							|  |  |  | 		c.pushCounter(ch, "fcp_packet_aborts_total", *host.Counters.FCPPacketAborts, *host.Name) | 
					
						
							| 
									
										
										
										
											2020-07-13 05:41:04 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |