|
|
|
// Copyright 2017 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.
|
|
|
|
|
|
|
|
//go:build !nomountstats
|
|
|
|
// +build !nomountstats
|
|
|
|
|
|
|
|
package collector
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log/slog"
|
|
|
|
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"github.com/prometheus/procfs"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// 64-bit float mantissa: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
|
|
|
|
float64Mantissa uint64 = 9007199254740992
|
|
|
|
)
|
|
|
|
|
|
|
|
type mountStatsCollector struct {
|
|
|
|
// General statistics
|
|
|
|
NFSAgeSecondsTotal *prometheus.Desc
|
|
|
|
|
|
|
|
// Byte statistics
|
|
|
|
NFSReadBytesTotal *prometheus.Desc
|
|
|
|
NFSWriteBytesTotal *prometheus.Desc
|
|
|
|
NFSDirectReadBytesTotal *prometheus.Desc
|
|
|
|
NFSDirectWriteBytesTotal *prometheus.Desc
|
|
|
|
NFSTotalReadBytesTotal *prometheus.Desc
|
|
|
|
NFSTotalWriteBytesTotal *prometheus.Desc
|
|
|
|
NFSReadPagesTotal *prometheus.Desc
|
|
|
|
NFSWritePagesTotal *prometheus.Desc
|
|
|
|
|
|
|
|
// Per-operation statistics
|
|
|
|
NFSOperationsRequestsTotal *prometheus.Desc
|
|
|
|
NFSOperationsTransmissionsTotal *prometheus.Desc
|
|
|
|
NFSOperationsMajorTimeoutsTotal *prometheus.Desc
|
|
|
|
NFSOperationsSentBytesTotal *prometheus.Desc
|
|
|
|
NFSOperationsReceivedBytesTotal *prometheus.Desc
|
|
|
|
NFSOperationsQueueTimeSecondsTotal *prometheus.Desc
|
|
|
|
NFSOperationsResponseTimeSecondsTotal *prometheus.Desc
|
|
|
|
NFSOperationsRequestTimeSecondsTotal *prometheus.Desc
|
|
|
|
|
|
|
|
// Transport statistics
|
|
|
|
NFSTransportBindTotal *prometheus.Desc
|
|
|
|
NFSTransportConnectTotal *prometheus.Desc
|
|
|
|
NFSTransportIdleTimeSeconds *prometheus.Desc
|
|
|
|
NFSTransportSendsTotal *prometheus.Desc
|
|
|
|
NFSTransportReceivesTotal *prometheus.Desc
|
|
|
|
NFSTransportBadTransactionIDsTotal *prometheus.Desc
|
|
|
|
NFSTransportBacklogQueueTotal *prometheus.Desc
|
|
|
|
NFSTransportMaximumRPCSlots *prometheus.Desc
|
|
|
|
NFSTransportSendingQueueTotal *prometheus.Desc
|
|
|
|
NFSTransportPendingQueueTotal *prometheus.Desc
|
|
|
|
|
|
|
|
// Event statistics
|
|
|
|
NFSEventInodeRevalidateTotal *prometheus.Desc
|
|
|
|
NFSEventDnodeRevalidateTotal *prometheus.Desc
|
|
|
|
NFSEventDataInvalidateTotal *prometheus.Desc
|
|
|
|
NFSEventAttributeInvalidateTotal *prometheus.Desc
|
|
|
|
NFSEventVFSOpenTotal *prometheus.Desc
|
|
|
|
NFSEventVFSLookupTotal *prometheus.Desc
|
|
|
|
NFSEventVFSAccessTotal *prometheus.Desc
|
|
|
|
NFSEventVFSUpdatePageTotal *prometheus.Desc
|
|
|
|
NFSEventVFSReadPageTotal *prometheus.Desc
|
|
|
|
NFSEventVFSReadPagesTotal *prometheus.Desc
|
|
|
|
NFSEventVFSWritePageTotal *prometheus.Desc
|
|
|
|
NFSEventVFSWritePagesTotal *prometheus.Desc
|
|
|
|
NFSEventVFSGetdentsTotal *prometheus.Desc
|
|
|
|
NFSEventVFSSetattrTotal *prometheus.Desc
|
|
|
|
NFSEventVFSFlushTotal *prometheus.Desc
|
|
|
|
NFSEventVFSFsyncTotal *prometheus.Desc
|
|
|
|
NFSEventVFSLockTotal *prometheus.Desc
|
|
|
|
NFSEventVFSFileReleaseTotal *prometheus.Desc
|
|
|
|
NFSEventTruncationTotal *prometheus.Desc
|
|
|
|
NFSEventWriteExtensionTotal *prometheus.Desc
|
|
|
|
NFSEventSillyRenameTotal *prometheus.Desc
|
|
|
|
NFSEventShortReadTotal *prometheus.Desc
|
|
|
|
NFSEventShortWriteTotal *prometheus.Desc
|
|
|
|
NFSEventJukeboxDelayTotal *prometheus.Desc
|
|
|
|
NFSEventPNFSReadTotal *prometheus.Desc
|
|
|
|
NFSEventPNFSWriteTotal *prometheus.Desc
|
|
|
|
|
|
|
|
proc procfs.Proc
|
|
|
|
|
|
|
|
logger *slog.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
// used to uniquely identify an NFS mount to prevent duplicates
|
|
|
|
type nfsDeviceIdentifier struct {
|
|
|
|
Device string
|
|
|
|
Protocol string
|
|
|
|
MountAddress string
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
registerCollector("mountstats", defaultDisabled, NewMountStatsCollector)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewMountStatsCollector returns a new Collector exposing NFS statistics.
|
|
|
|
func NewMountStatsCollector(logger *slog.Logger) (Collector, error) {
|
|
|
|
fs, err := procfs.NewFS(*procPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to open procfs: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
proc, err := fs.Self()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to open /proc/self: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
// For the time being, only NFS statistics are available via this mechanism.
|
|
|
|
subsystem = "mountstats_nfs"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
labels = []string{"export", "protocol", "mountaddr"}
|
|
|
|
opLabels = []string{"export", "protocol", "mountaddr", "operation"}
|
|
|
|
)
|
|
|
|
|
|
|
|
return &mountStatsCollector{
|
|
|
|
NFSAgeSecondsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "age_seconds_total"),
|
|
|
|
"The age of the NFS mount in seconds.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSReadBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "read_bytes_total"),
|
|
|
|
"Number of bytes read using the read() syscall.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSWriteBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "write_bytes_total"),
|
|
|
|
"Number of bytes written using the write() syscall.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSDirectReadBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "direct_read_bytes_total"),
|
|
|
|
"Number of bytes read using the read() syscall in O_DIRECT mode.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSDirectWriteBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "direct_write_bytes_total"),
|
|
|
|
"Number of bytes written using the write() syscall in O_DIRECT mode.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTotalReadBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "total_read_bytes_total"),
|
|
|
|
"Number of bytes read from the NFS server, in total.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTotalWriteBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "total_write_bytes_total"),
|
|
|
|
"Number of bytes written to the NFS server, in total.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSReadPagesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "read_pages_total"),
|
|
|
|
"Number of pages read directly via mmap()'d files.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSWritePagesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "write_pages_total"),
|
|
|
|
"Number of pages written directly via mmap()'d files.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportBindTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_bind_total"),
|
|
|
|
"Number of times the client has had to establish a connection from scratch to the NFS server.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportConnectTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_connect_total"),
|
|
|
|
"Number of times the client has made a TCP connection to the NFS server.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportIdleTimeSeconds: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_idle_time_seconds"),
|
|
|
|
"Duration since the NFS mount last saw any RPC traffic, in seconds.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportSendsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_sends_total"),
|
|
|
|
"Number of RPC requests for this mount sent to the NFS server.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportReceivesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_receives_total"),
|
|
|
|
"Number of RPC responses for this mount received from the NFS server.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportBadTransactionIDsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_bad_transaction_ids_total"),
|
|
|
|
"Number of times the NFS server sent a response with a transaction ID unknown to this client.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportBacklogQueueTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_backlog_queue_total"),
|
|
|
|
"Total number of items added to the RPC backlog queue.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportMaximumRPCSlots: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_maximum_rpc_slots"),
|
|
|
|
"Maximum number of simultaneously active RPC requests ever used.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportSendingQueueTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_sending_queue_total"),
|
|
|
|
"Total number of items added to the RPC transmission sending queue.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSTransportPendingQueueTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "transport_pending_queue_total"),
|
|
|
|
"Total number of items added to the RPC transmission pending queue.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsRequestsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_requests_total"),
|
|
|
|
"Number of requests performed for a given operation.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsTransmissionsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_transmissions_total"),
|
|
|
|
"Number of times an actual RPC request has been transmitted for a given operation.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsMajorTimeoutsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_major_timeouts_total"),
|
|
|
|
"Number of times a request has had a major timeout for a given operation.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsSentBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_sent_bytes_total"),
|
|
|
|
"Number of bytes sent for a given operation, including RPC headers and payload.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsReceivedBytesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_received_bytes_total"),
|
|
|
|
"Number of bytes received for a given operation, including RPC headers and payload.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsQueueTimeSecondsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_queue_time_seconds_total"),
|
|
|
|
"Duration all requests spent queued for transmission for a given operation before they were sent, in seconds.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsResponseTimeSecondsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_response_time_seconds_total"),
|
|
|
|
"Duration all requests took to get a reply back after a request for a given operation was transmitted, in seconds.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSOperationsRequestTimeSecondsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "operations_request_time_seconds_total"),
|
|
|
|
"Duration all requests took from when a request was enqueued to when it was completely handled for a given operation, in seconds.",
|
|
|
|
opLabels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventInodeRevalidateTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_inode_revalidate_total"),
|
|
|
|
"Number of times cached inode attributes are re-validated from the server.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventDnodeRevalidateTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_dnode_revalidate_total"),
|
|
|
|
"Number of times cached dentry nodes are re-validated from the server.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventDataInvalidateTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_data_invalidate_total"),
|
|
|
|
"Number of times an inode cache is cleared.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventAttributeInvalidateTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_attribute_invalidate_total"),
|
|
|
|
"Number of times cached inode attributes are invalidated.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSOpenTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_open_total"),
|
|
|
|
"Number of times cached inode attributes are invalidated.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSLookupTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_lookup_total"),
|
|
|
|
"Number of times a directory lookup has occurred.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSAccessTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_access_total"),
|
|
|
|
"Number of times permissions have been checked.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSUpdatePageTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_update_page_total"),
|
|
|
|
"Number of updates (and potential writes) to pages.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSReadPageTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_read_page_total"),
|
|
|
|
"Number of pages read directly via mmap()'d files.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSReadPagesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_read_pages_total"),
|
|
|
|
"Number of times a group of pages have been read.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSWritePageTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_write_page_total"),
|
|
|
|
"Number of pages written directly via mmap()'d files.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSWritePagesTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_write_pages_total"),
|
|
|
|
"Number of times a group of pages have been written.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSGetdentsTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_getdents_total"),
|
|
|
|
"Number of times directory entries have been read with getdents().",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSSetattrTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_setattr_total"),
|
|
|
|
"Number of times directory entries have been read with getdents().",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSFlushTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_flush_total"),
|
|
|
|
"Number of pending writes that have been forcefully flushed to the server.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSFsyncTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_fsync_total"),
|
|
|
|
"Number of times fsync() has been called on directories and files.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSLockTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_lock_total"),
|
|
|
|
"Number of times locking has been attempted on a file.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventVFSFileReleaseTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_vfs_file_release_total"),
|
|
|
|
"Number of times files have been closed and released.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventTruncationTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_truncation_total"),
|
|
|
|
"Number of times files have been truncated.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventWriteExtensionTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_write_extension_total"),
|
|
|
|
"Number of times a file has been grown due to writes beyond its existing end.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventSillyRenameTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_silly_rename_total"),
|
|
|
|
"Number of times a file was removed while still open by another process.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventShortReadTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_short_read_total"),
|
|
|
|
"Number of times the NFS server gave less data than expected while reading.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventShortWriteTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_short_write_total"),
|
|
|
|
"Number of times the NFS server wrote less data than expected while writing.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventJukeboxDelayTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_jukebox_delay_total"),
|
|
|
|
"Number of times the NFS server indicated EJUKEBOX; retrieving data from offline storage.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventPNFSReadTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_pnfs_read_total"),
|
|
|
|
"Number of NFS v4.1+ pNFS reads.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
NFSEventPNFSWriteTotal: prometheus.NewDesc(
|
|
|
|
prometheus.BuildFQName(namespace, subsystem, "event_pnfs_write_total"),
|
|
|
|
"Number of NFS v4.1+ pNFS writes.",
|
|
|
|
labels,
|
|
|
|
nil,
|
|
|
|
),
|
|
|
|
|
|
|
|
proc: proc,
|
|
|
|
logger: logger,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *mountStatsCollector) Update(ch chan<- prometheus.Metric) error {
|
|
|
|
mounts, err := c.proc.MountStats()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to parse mountstats: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
mountsInfo, err := c.proc.MountInfo()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to parse mountinfo: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// store all seen nfsDeviceIdentifiers for deduplication
|
|
|
|
deviceList := make(map[nfsDeviceIdentifier]bool)
|
|
|
|
|
|
|
|
for idx, m := range mounts {
|
|
|
|
// For the time being, only NFS statistics are available via this mechanism
|
|
|
|
stats, ok := m.Stats.(*procfs.MountStatsNFS)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var mountAddress string
|
|
|
|
if idx < len(mountsInfo) {
|
|
|
|
// The mount entry order in the /proc/self/mountstats and /proc/self/mountinfo is the same.
|
|
|
|
miStats := mountsInfo[idx]
|
|
|
|
mountAddress = miStats.SuperOptions["addr"]
|
|
|
|
}
|
|
|
|
|
|
|
|
for k := range stats.Transport {
|
|
|
|
deviceIdentifier := nfsDeviceIdentifier{m.Device, stats.Transport[k].Protocol, mountAddress}
|
|
|
|
i := deviceList[deviceIdentifier]
|
|
|
|
if i {
|
|
|
|
c.logger.Debug("Skipping duplicate device entry", "device", deviceIdentifier)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
deviceList[deviceIdentifier] = true
|
|
|
|
c.updateNFSStats(ch, stats, m.Device, stats.Transport[k].Protocol, mountAddress)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *mountStatsCollector) updateNFSStats(ch chan<- prometheus.Metric, s *procfs.MountStatsNFS, export, protocol, mountAddress string) {
|
|
|
|
labelValues := []string{export, protocol, mountAddress}
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSAgeSecondsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
s.Age.Seconds(),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSReadBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.Read),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSWriteBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.Write),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSDirectReadBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.DirectRead),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSDirectWriteBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.DirectWrite),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTotalReadBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.ReadTotal),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTotalWriteBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.WriteTotal),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSReadPagesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.ReadPages),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSWritePagesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Bytes.WritePages),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
for i := range s.Transport {
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportBindTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].Bind),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportConnectTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].Connect),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportIdleTimeSeconds,
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
float64(s.Transport[i].IdleTimeSeconds%float64Mantissa),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportSendsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].Sends),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportReceivesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].Receives),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportBadTransactionIDsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].BadTransactionIDs),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportBacklogQueueTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].CumulativeBacklog),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportMaximumRPCSlots,
|
|
|
|
prometheus.GaugeValue,
|
|
|
|
float64(s.Transport[i].MaximumRPCSlotsUsed),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportSendingQueueTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].CumulativeSendingQueue),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSTransportPendingQueueTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Transport[i].CumulativePendingQueue),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, op := range s.Operations {
|
|
|
|
opLabelValues := []string{export, protocol, mountAddress, op.Operation}
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsRequestsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.Requests),
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsTransmissionsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.Transmissions),
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsMajorTimeoutsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.MajorTimeouts),
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsSentBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.BytesSent),
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsReceivedBytesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.BytesReceived),
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsQueueTimeSecondsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.CumulativeQueueMilliseconds%float64Mantissa)/1000.0,
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsResponseTimeSecondsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.CumulativeTotalResponseMilliseconds%float64Mantissa)/1000.0,
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSOperationsRequestTimeSecondsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(op.CumulativeTotalRequestMilliseconds%float64Mantissa)/1000.0,
|
|
|
|
opLabelValues...,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventInodeRevalidateTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.InodeRevalidate),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventDnodeRevalidateTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.DnodeRevalidate),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventDataInvalidateTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.DataInvalidate),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventAttributeInvalidateTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.AttributeInvalidate),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSOpenTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSOpen),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSLookupTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSLookup),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSAccessTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSAccess),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSUpdatePageTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSUpdatePage),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSReadPageTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSReadPage),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSReadPagesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSReadPages),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSWritePageTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSWritePage),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSWritePagesTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSWritePages),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSGetdentsTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSGetdents),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSSetattrTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSSetattr),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSFlushTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSFlush),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSFsyncTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSFsync),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSLockTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSLock),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventVFSFileReleaseTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.VFSFileRelease),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventTruncationTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.Truncation),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventWriteExtensionTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.WriteExtension),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventSillyRenameTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.SillyRename),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventShortReadTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.ShortRead),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventShortWriteTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.ShortWrite),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventJukeboxDelayTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.JukeboxDelay),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventPNFSReadTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.PNFSRead),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
c.NFSEventPNFSWriteTotal,
|
|
|
|
prometheus.CounterValue,
|
|
|
|
float64(s.Events.PNFSWrite),
|
|
|
|
labelValues...,
|
|
|
|
)
|
|
|
|
}
|