add metric info

This commit is contained in:
houseme
2025-05-14 19:00:15 +08:00
parent cdd285dec8
commit 9e9f721c08
15 changed files with 720 additions and 147 deletions
@@ -1,12 +0,0 @@
use crate::metrics::{MetricName, MetricNamespace, MetricSubsystem, MetricType};
/// The metric description describes the metric
/// It contains the namespace, subsystem, name, help text, and type of the metric
#[derive(Debug, Clone)]
pub struct MetricDescription {
pub namespace: MetricNamespace,
pub subsystem: MetricSubsystem,
pub name: MetricName,
pub help: String,
pub metric_type: MetricType,
}
+29 -7
View File
@@ -1,36 +1,58 @@
use crate::metrics::{MetricName, MetricType};
use crate::metrics::{MetricName, MetricNamespace, MetricSubsystem, MetricType};
use std::collections::HashSet;
/// MetricDescriptor - Indicates the metric descriptor
/// MetricDescriptor - 指标描述符
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MetricDescriptor {
pub name: MetricName,
pub metric_type: MetricType,
pub help: String,
pub variable_labels: Vec<String>,
pub namespace: MetricNamespace,
pub subsystem: MetricSubsystem, // 从 String 修改为 MetricSubsystem
// internal values for management
// 内部管理值
label_set: Option<HashSet<String>>,
}
impl MetricDescriptor {
/// Create a new metric descriptor
pub fn new(name: MetricName, metric_type: MetricType, help: String, variable_labels: Vec<String>) -> Self {
/// 创建新的指标描述符
pub fn new(
name: MetricName,
metric_type: MetricType,
help: String,
variable_labels: Vec<String>,
namespace: MetricNamespace,
subsystem: impl Into<MetricSubsystem>, // 修改参数类型
) -> Self {
Self {
name,
metric_type,
help,
variable_labels,
namespace,
subsystem: subsystem.into(),
label_set: None,
}
}
/// Check whether the label is in the label set
/// 获取完整的指标名称,包含前缀和格式化路径
pub fn get_full_metric_name(&self) -> String {
let prefix = self.metric_type.to_prom();
let namespace = self.namespace.as_str();
let formatted_subsystem = self.subsystem.as_str();
format!("{}{}_{}_{}", prefix, namespace, formatted_subsystem, self.name.as_str())
}
/// 检查标签是否在标签集中
#[allow(dead_code)]
pub fn has_label(&mut self, label: &str) -> bool {
self.get_label_set().contains(label)
}
/// Gets a collection of tags, and creates if it doesn't exist
/// 获取标签集合,如果不存在则创建
pub fn get_label_set(&mut self) -> &HashSet<String> {
if self.label_set.is_none() {
let mut set = HashSet::with_capacity(self.variable_labels.len());
@@ -1,4 +1,5 @@
/// The metric name is the individual name of the metric
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MetricName {
// 通用指标名称
@@ -158,6 +159,15 @@ pub enum MetricName {
ApiTrafficSentBytes,
ApiTrafficRecvBytes,
// 审计指标
AuditFailedMessages,
AuditTargetQueueLength,
AuditTotalMessages,
// 集群配置相关指标
ConfigRRSParity,
ConfigStandardParity,
// 自定义指标
Custom(String),
}
@@ -303,6 +313,14 @@ impl MetricName {
Self::ApiTrafficSentBytes => "traffic_sent_bytes".to_string(),
Self::ApiTrafficRecvBytes => "traffic_received_bytes".to_string(),
Self::AuditFailedMessages => "failed_messages".to_string(),
Self::AuditTargetQueueLength => "target_queue_length".to_string(),
Self::AuditTotalMessages => "total_messages".to_string(),
/// metrics related to cluster configurations
Self::ConfigRRSParity => "rrs_parity".to_string(),
Self::ConfigStandardParity => "standard_parity".to_string(),
Self::Custom(name) => name.clone(),
}
}
+5 -3
View File
@@ -1,4 +1,5 @@
/// MetricType - Indicates the type of indicator
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MetricType {
Counter,
@@ -8,6 +9,7 @@ pub enum MetricType {
impl MetricType {
/// convert the metric type to a string representation
#[allow(dead_code)]
pub fn as_str(&self) -> &'static str {
match self {
Self::Counter => "counter",
@@ -20,9 +22,9 @@ impl MetricType {
/// In a Rust implementation, this might return the corresponding Prometheus Rust client type
pub fn to_prom(&self) -> &'static str {
match self {
Self::Counter => "counter_value",
Self::Gauge => "gauge_value",
Self::Histogram => "counter_value", // 直方图在 Prometheus 中仍使用 counter 值
Self::Counter => "counter.",
Self::Gauge => "gauge.",
Self::Histogram => "histogram.", // Histograms still use the counter value in Prometheus
}
}
}
+92 -9
View File
@@ -1,32 +1,115 @@
use crate::metrics::{MetricDescriptor, MetricName, MetricType};
use crate::metrics::{MetricDescriptor, MetricName, MetricNamespace, MetricSubsystem, MetricType};
pub(crate) mod description;
pub(crate) mod descriptor;
pub(crate) mod metric_name;
pub(crate) mod metric_type;
pub(crate) mod namespace;
mod path_utils;
pub(crate) mod subsystem;
/// Represents a range label constant
pub const RANGE_LABEL: &str = "range";
pub const SERVER_NAME: &str = "server";
/// Create a new counter metric descriptor
pub fn new_counter_md(name: impl Into<MetricName>, help: impl Into<String>, labels: &[&str]) -> MetricDescriptor {
pub fn new_counter_md(
name: impl Into<MetricName>,
help: impl Into<String>,
labels: &[&str],
subsystem: impl Into<MetricSubsystem>,
) -> MetricDescriptor {
MetricDescriptor::new(
name.into(),
MetricType::Counter,
help.into(),
labels.iter().map(|&s| s.to_string()).collect(),
MetricNamespace::RustFS,
subsystem,
)
}
/// Create a new gauge metric descriptor
pub fn new_gauge_md(name: impl Into<MetricName>, help: impl Into<String>, labels: &[&str]) -> MetricDescriptor {
/// create a new dashboard metric descriptor
pub fn new_gauge_md(
name: impl Into<MetricName>,
help: impl Into<String>,
labels: &[&str],
subsystem: impl Into<MetricSubsystem>,
) -> MetricDescriptor {
MetricDescriptor::new(
name.into(),
MetricType::Gauge,
help.into(),
labels.iter().map(|&s| s.to_string()).collect(),
MetricNamespace::RustFS,
subsystem,
)
}
/// create a new histogram indicator descriptor
#[allow(dead_code)]
pub fn new_histogram_md(
name: impl Into<MetricName>,
help: impl Into<String>,
labels: &[&str],
subsystem: impl Into<MetricSubsystem>,
) -> MetricDescriptor {
MetricDescriptor::new(
name.into(),
MetricType::Histogram,
help.into(),
labels.iter().map(|&s| s.to_string()).collect(),
MetricNamespace::RustFS,
subsystem,
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::metrics::subsystems;
#[test]
fn test_new_histogram_md() {
// create a histogram indicator descriptor
let histogram_md = new_histogram_md(
MetricName::TtfbDistribution,
"test the response time distribution",
&["api", "method", "le"],
subsystems::API_REQUESTS,
);
// verify that the metric type is correct
assert_eq!(histogram_md.metric_type, MetricType::Histogram);
// verify that the metric name is correct
assert_eq!(histogram_md.name.as_str(), "seconds_distribution");
// verify that the help information is correct
assert_eq!(histogram_md.help, "test the response time distribution");
// Verify that the label is correct
assert_eq!(histogram_md.variable_labels.len(), 3);
assert!(histogram_md.variable_labels.contains(&"api".to_string()));
assert!(histogram_md.variable_labels.contains(&"method".to_string()));
assert!(histogram_md.variable_labels.contains(&"le".to_string()));
// Verify that the namespace is correct
assert_eq!(histogram_md.namespace, MetricNamespace::RustFS);
// Verify that the subsystem is correct
assert_eq!(histogram_md.subsystem, MetricSubsystem::ApiRequests);
// Verify that the full metric name generated is formatted correctly
assert_eq!(histogram_md.get_full_metric_name(), "histogram.rustfs_api_requests_seconds_distribution");
// Tests use custom subsystems
let custom_histogram_md = new_histogram_md(
"custom_latency_distribution",
"custom latency distribution",
&["endpoint", "le"],
MetricSubsystem::new("/custom/path-metrics"),
);
// Verify the custom name and subsystem
assert_eq!(
custom_histogram_md.get_full_metric_name(),
"histogram.rustfs_custom_path_metrics_custom_latency_distribution"
);
}
}
+1 -13
View File
@@ -1,25 +1,13 @@
/// The metric namespace is the top-level grouping created by the metric name
/// The metric namespace, which represents the top-level grouping of the metric
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MetricNamespace {
Bucket,
Cluster,
Heal,
InterNode,
Node,
RustFS,
S3,
}
impl MetricNamespace {
pub fn as_str(&self) -> &'static str {
match self {
Self::Bucket => "rustfs_bucket",
Self::Cluster => "rustfs_cluster",
Self::Heal => "rustfs_heal",
Self::InterNode => "rustfs_inter_node",
Self::Node => "rustfs_node",
Self::RustFS => "rustfs",
Self::S3 => "rustfs_s3",
}
}
}
@@ -0,0 +1,18 @@
/// Format the path to the metric name format
/// Replace '/' and '-' with '_'
pub fn format_path_to_metric_name(path: &str) -> String {
path.trim_start_matches('/').replace('/', "_").replace('-', "_")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_path_to_metric_name() {
assert_eq!(format_path_to_metric_name("/api/requests"), "api_requests");
assert_eq!(format_path_to_metric_name("/system/network/internode"), "system_network_internode");
assert_eq!(format_path_to_metric_name("/bucket-api"), "bucket_api");
assert_eq!(format_path_to_metric_name("cluster/health"), "cluster_health");
}
}
+219 -68
View File
@@ -1,79 +1,230 @@
use crate::metrics::entry::path_utils::format_path_to_metric_name;
/// The metrics subsystem is a subgroup of metrics within a namespace
#[derive(Debug, Clone, PartialEq, Eq)]
/// 指标子系统,表示命名空间内指标的子分组
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MetricSubsystem {
Cache,
CapacityRaw,
CapacityUsable,
Drive,
Interface,
Memory,
CpuAvg,
StorageClass,
FileDescriptor,
GoRoutine,
Io,
Nodes,
Objects,
Bucket,
Process,
Replication,
Requests,
RequestsRejected,
Time,
Ttfb,
Traffic,
Software,
Syscall,
Usage,
Quota,
// API 相关子系统
ApiRequests,
// 桶相关子系统
BucketApi,
BucketReplication,
// 系统相关子系统
SystemNetworkInternode,
SystemDrive,
SystemMemory,
SystemCpu,
SystemProcess,
// 调试相关子系统
DebugGo,
// 集群相关子系统
ClusterHealth,
ClusterUsageObjects,
ClusterUsageBuckets,
ClusterErasureSet,
ClusterIam,
ClusterConfig,
// 其他服务相关子系统
Ilm,
Tier,
Scanner,
Iam,
Kms,
Notify,
Lambda,
Audit,
Webhook,
LoggerWebhook,
Replication,
Notification,
Scanner,
// 自定义路径
Custom(String),
}
impl MetricSubsystem {
pub fn as_str(&self) -> &'static str {
/// 获取原始路径字符串
pub fn path(&self) -> &str {
match self {
Self::Cache => "cache",
Self::CapacityRaw => "capacity_raw",
Self::CapacityUsable => "capacity_usable",
Self::Drive => "drive",
Self::Interface => "if",
Self::Memory => "mem",
Self::CpuAvg => "cpu_avg",
Self::StorageClass => "storage_class",
Self::FileDescriptor => "file_descriptor",
Self::GoRoutine => "go_routine",
Self::Io => "io",
Self::Nodes => "nodes",
Self::Objects => "objects",
Self::Bucket => "bucket",
Self::Process => "process",
Self::Replication => "replication",
Self::Requests => "requests",
Self::RequestsRejected => "requests_rejected",
Self::Time => "time",
Self::Ttfb => "requests_ttfb",
Self::Traffic => "traffic",
Self::Software => "software",
Self::Syscall => "syscall",
Self::Usage => "usage",
Self::Quota => "quota",
Self::Ilm => "ilm",
Self::Tier => "tier",
Self::Scanner => "scanner",
Self::Iam => "iam",
Self::Kms => "kms",
Self::Notify => "notify",
Self::Lambda => "lambda",
Self::Audit => "audit",
Self::Webhook => "webhook",
// API 相关子系统
Self::ApiRequests => "/api/requests",
// 桶相关子系统
Self::BucketApi => "/bucket/api",
Self::BucketReplication => "/bucket/replication",
// 系统相关子系统
Self::SystemNetworkInternode => "/system/network/internode",
Self::SystemDrive => "/system/drive",
Self::SystemMemory => "/system/memory",
Self::SystemCpu => "/system/cpu",
Self::SystemProcess => "/system/process",
// 调试相关子系统
Self::DebugGo => "/debug/go",
// 集群相关子系统
Self::ClusterHealth => "/cluster/health",
Self::ClusterUsageObjects => "/cluster/usage/objects",
Self::ClusterUsageBuckets => "/cluster/usage/buckets",
Self::ClusterErasureSet => "/cluster/erasure-set",
Self::ClusterIam => "/cluster/iam",
Self::ClusterConfig => "/cluster/config",
// 其他服务相关子系统
Self::Ilm => "/ilm",
Self::Audit => "/audit",
Self::LoggerWebhook => "/logger/webhook",
Self::Replication => "/replication",
Self::Notification => "/notification",
Self::Scanner => "/scanner",
// 自定义路径
Self::Custom(path) => path,
}
}
/// 获取格式化后的指标名称格式字符串
pub fn as_str(&self) -> String {
format_path_to_metric_name(self.path())
}
/// 从路径字符串创建子系统枚举
pub fn from_path(path: &str) -> Self {
match path {
// API 相关子系统
"/api/requests" => Self::ApiRequests,
// 桶相关子系统
"/bucket/api" => Self::BucketApi,
"/bucket/replication" => Self::BucketReplication,
// 系统相关子系统
"/system/network/internode" => Self::SystemNetworkInternode,
"/system/drive" => Self::SystemDrive,
"/system/memory" => Self::SystemMemory,
"/system/cpu" => Self::SystemCpu,
"/system/process" => Self::SystemProcess,
// 调试相关子系统
"/debug/go" => Self::DebugGo,
// 集群相关子系统
"/cluster/health" => Self::ClusterHealth,
"/cluster/usage/objects" => Self::ClusterUsageObjects,
"/cluster/usage/buckets" => Self::ClusterUsageBuckets,
"/cluster/erasure-set" => Self::ClusterErasureSet,
"/cluster/iam" => Self::ClusterIam,
"/cluster/config" => Self::ClusterConfig,
// 其他服务相关子系统
"/ilm" => Self::Ilm,
"/audit" => Self::Audit,
"/logger/webhook" => Self::LoggerWebhook,
"/replication" => Self::Replication,
"/notification" => Self::Notification,
"/scanner" => Self::Scanner,
// 其他路径作为自定义处理
_ => Self::Custom(path.to_string()),
}
}
// 便利方法,直接创建自定义子系统
pub fn new(path: impl Into<String>) -> Self {
Self::Custom(path.into())
}
}
// 便于与字符串相互转换的实现
impl From<&str> for MetricSubsystem {
fn from(s: &str) -> Self {
Self::from_path(s)
}
}
impl From<String> for MetricSubsystem {
fn from(s: String) -> Self {
Self::from_path(&s)
}
}
impl std::fmt::Display for MetricSubsystem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.path())
}
}
#[allow(dead_code)]
pub mod subsystems {
use super::MetricSubsystem;
// 集群基本路径常量
pub const CLUSTER_BASE_PATH: &str = "/cluster";
// 快捷访问各子系统的常量
pub const API_REQUESTS: MetricSubsystem = MetricSubsystem::ApiRequests;
pub const BUCKET_API: MetricSubsystem = MetricSubsystem::BucketApi;
pub const BUCKET_REPLICATION: MetricSubsystem = MetricSubsystem::BucketReplication;
pub const SYSTEM_NETWORK_INTERNODE: MetricSubsystem = MetricSubsystem::SystemNetworkInternode;
pub const SYSTEM_DRIVE: MetricSubsystem = MetricSubsystem::SystemDrive;
pub const SYSTEM_MEMORY: MetricSubsystem = MetricSubsystem::SystemMemory;
pub const SYSTEM_CPU: MetricSubsystem = MetricSubsystem::SystemCpu;
pub const SYSTEM_PROCESS: MetricSubsystem = MetricSubsystem::SystemProcess;
pub const DEBUG_GO: MetricSubsystem = MetricSubsystem::DebugGo;
pub const CLUSTER_HEALTH: MetricSubsystem = MetricSubsystem::ClusterHealth;
pub const CLUSTER_USAGE_OBJECTS: MetricSubsystem = MetricSubsystem::ClusterUsageObjects;
pub const CLUSTER_USAGE_BUCKETS: MetricSubsystem = MetricSubsystem::ClusterUsageBuckets;
pub const CLUSTER_ERASURE_SET: MetricSubsystem = MetricSubsystem::ClusterErasureSet;
pub const CLUSTER_IAM: MetricSubsystem = MetricSubsystem::ClusterIam;
pub const CLUSTER_CONFIG: MetricSubsystem = MetricSubsystem::ClusterConfig;
pub const ILM: MetricSubsystem = MetricSubsystem::Ilm;
pub const AUDIT: MetricSubsystem = MetricSubsystem::Audit;
pub const LOGGER_WEBHOOK: MetricSubsystem = MetricSubsystem::LoggerWebhook;
pub const REPLICATION: MetricSubsystem = MetricSubsystem::Replication;
pub const NOTIFICATION: MetricSubsystem = MetricSubsystem::Notification;
pub const SCANNER: MetricSubsystem = MetricSubsystem::Scanner;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::metrics::MetricType;
use crate::metrics::{MetricDescriptor, MetricName, MetricNamespace};
#[test]
fn test_metric_subsystem_formatting() {
assert_eq!(MetricSubsystem::ApiRequests.as_str(), "api_requests");
assert_eq!(MetricSubsystem::SystemNetworkInternode.as_str(), "system_network_internode");
assert_eq!(MetricSubsystem::BucketApi.as_str(), "bucket_api");
assert_eq!(MetricSubsystem::ClusterHealth.as_str(), "cluster_health");
// 测试自定义路径
let custom = MetricSubsystem::new("/custom/path-test");
assert_eq!(custom.as_str(), "custom_path_test");
}
#[test]
fn test_metric_descriptor_name_generation() {
let md = MetricDescriptor::new(
MetricName::ApiRequestsTotal,
MetricType::Counter,
"Test help".to_string(),
vec!["label1".to_string(), "label2".to_string()],
MetricNamespace::RustFS,
MetricSubsystem::ApiRequests,
);
assert_eq!(md.get_full_metric_name(), "counter.rustfs_api_requests_total");
let custom_md = MetricDescriptor::new(
MetricName::Custom("test_metric".to_string()),
MetricType::Gauge,
"Test help".to_string(),
vec!["label1".to_string()],
MetricNamespace::RustFS,
MetricSubsystem::new("/custom/path-with-dash"),
);
assert_eq!(custom_md.get_full_metric_name(), "gauge.rustfs_custom_path_with_dash_test_metric");
}
}