You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
6.1 KiB
150 lines
6.1 KiB
4 years ago
|
// Copyright 2017-2019 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.
|
||
|
|
||
|
// +build linux
|
||
|
// +build !nofibrechannel
|
||
|
|
||
|
package collector
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
|
||
|
"github.com/go-kit/kit/log"
|
||
|
"github.com/go-kit/kit/log/level"
|
||
|
"github.com/prometheus/client_golang/prometheus"
|
||
|
"github.com/prometheus/procfs/sysfs"
|
||
|
)
|
||
|
|
||
|
const maxUint64 = ^uint64(0)
|
||
|
|
||
|
type fibrechannelCollector struct {
|
||
|
fs sysfs.FS
|
||
|
metricDescs map[string]*prometheus.Desc
|
||
|
logger log.Logger
|
||
|
subsystem string
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
registerCollector("fibrechannel", defaultEnabled, NewFibreChannelCollector)
|
||
|
}
|
||
|
|
||
|
// NewFibreChannelCollector returns a new Collector exposing FibreChannel stats.
|
||
|
func NewFibreChannelCollector(logger log.Logger) (Collector, error) {
|
||
|
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{
|
||
|
"dumped_frames": "",
|
||
|
"loss_of_signal_count": "Number of times signal has been lost",
|
||
|
"loss_of_sync_count": "Number of failures on either bit or transmission word boundaries",
|
||
|
"rx_frames": "Number of frames received",
|
||
|
"error_frames": "Number of errors in frames",
|
||
|
"invalid_tx_word_count": "Number of invalid words transmitted by host port",
|
||
|
"seconds_since_last_reset": "Number of seconds since last host port reset",
|
||
|
"tx_words": "Number of words transmitted by host port",
|
||
|
"invalid_crc_count": "Invalid Cyclic Redundancy Check count",
|
||
|
"nos_count": "Number Not_Operational Primitive Sequence received by host port",
|
||
|
"fcp_packet_aborts": "Number of aborted packets",
|
||
|
"rx_words": "Number of words received by host port",
|
||
|
"tx_frames": "Number of frames transmitted by host port",
|
||
|
"link_failure_count": "Number of times the host port link has failed",
|
||
|
"name": "Name of Fibre Channel HBA",
|
||
|
"speed": "Current operating speed",
|
||
|
"port_state": "Current port state",
|
||
|
"port_type": "Port type, what the port is connected to",
|
||
|
"symbolic_name": "Symoblic Name",
|
||
|
"node_name": "Node Name as hexadecimal string",
|
||
|
"port_id": "Port ID as string",
|
||
|
"port_name": "Port Name as hexadecimal string",
|
||
|
"fabric_name": "Fabric Name; 0 if PTP",
|
||
|
"dev_loss_tmo": "Device Loss Timeout in seconds",
|
||
|
"supported_classes": "The FC classes supported",
|
||
|
"supported_speeds": "The FC speeds supported",
|
||
|
}
|
||
|
|
||
|
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,
|
||
|
[]string{"host"},
|
||
|
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) {
|
||
|
level.Debug(c.logger).Log("msg", "fibrechannel statistics not found, skipping")
|
||
|
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.",
|
||
|
[]string{"host", "speed", "port_state", "port_type", "port_id", "port_name", "fabric_name", "symbolic_name", "supported_classes", "supported_speeds", "dev_loss_tmo"},
|
||
|
nil,
|
||
|
)
|
||
|
infoValue := 1.0
|
||
|
|
||
|
// First push the Host values
|
||
|
ch <- prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, infoValue, host.Name, host.Speed, host.PortState, host.PortType, host.PortID, host.PortName, host.FabricName, host.SymbolicName, host.SupportedClasses, host.SupportedSpeeds, host.DevLossTMO)
|
||
|
|
||
|
// Then the counters
|
||
|
c.pushCounter(ch, "dumped_frames", host.Counters.DumpedFrames, host.Name)
|
||
|
c.pushCounter(ch, "error_frames", host.Counters.ErrorFrames, host.Name)
|
||
|
c.pushCounter(ch, "invalid_crc_count", host.Counters.InvalidCRCCount, host.Name)
|
||
|
c.pushCounter(ch, "rx_frames", host.Counters.RXFrames, host.Name)
|
||
|
c.pushCounter(ch, "rx_words", host.Counters.RXWords, host.Name)
|
||
|
c.pushCounter(ch, "tx_frames", host.Counters.TXFrames, host.Name)
|
||
|
c.pushCounter(ch, "tx_words", host.Counters.TXWords, host.Name)
|
||
|
c.pushCounter(ch, "seconds_since_last_reset", host.Counters.SecondsSinceLastReset, host.Name)
|
||
|
c.pushCounter(ch, "invalid_tx_word_count", host.Counters.InvalidTXWordCount, host.Name)
|
||
|
c.pushCounter(ch, "link_failure_count", host.Counters.LinkFailureCount, host.Name)
|
||
|
c.pushCounter(ch, "loss_of_sync_count", host.Counters.LossOfSyncCount, host.Name)
|
||
|
c.pushCounter(ch, "loss_of_signal_count", host.Counters.LossOfSignalCount, host.Name)
|
||
|
c.pushCounter(ch, "nos_count", host.Counters.NosCount, host.Name)
|
||
|
c.pushCounter(ch, "fcp_packet_aborts", host.Counters.FCPPacketAborts, host.Name)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|