// Copyright 2024 RustFS Team // // 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. use crate::{MetricName, MetricNamespace, MetricSubsystem, MetricType}; use std::collections::HashSet; /// MetricDescriptor - Metric descriptors #[derive(Debug, Clone)] pub struct MetricDescriptor { pub name: MetricName, pub metric_type: MetricType, pub help: String, pub variable_labels: Vec, pub namespace: MetricNamespace, pub subsystem: MetricSubsystem, // Internal management values label_set: Option>, } impl MetricDescriptor { /// Create a new metric descriptor pub fn new( name: MetricName, metric_type: MetricType, help: String, variable_labels: Vec, namespace: MetricNamespace, subsystem: impl Into, // Modify the parameter type ) -> Self { Self { name, metric_type, help, variable_labels, namespace, subsystem: subsystem.into(), label_set: None, } } /// Get the full metric name in Prometheus style: __ pub fn get_full_metric_name(&self) -> String { let namespace = self.namespace.as_str(); let formatted_subsystem = self.subsystem.as_str(); format!("{}_{}_{}", namespace, formatted_subsystem, self.name.as_str()) } /// check whether the label is in the label set pub fn has_label(&mut self, label: &str) -> bool { self.get_label_set().contains(label) } /// Gets a collection of tags and creates them if they don't exist pub fn get_label_set(&mut self) -> &HashSet { if self.label_set.is_none() { let mut set = HashSet::with_capacity(self.variable_labels.len()); for label in &self.variable_labels { set.insert(label.clone()); } self.label_set = Some(set); } self.label_set.as_ref().unwrap() } } #[cfg(test)] mod tests { use super::*; #[test] fn full_metric_name_uses_prometheus_convention_without_type_prefix() { let descriptor = MetricDescriptor::new( MetricName::ApiRequestsTotal, MetricType::Counter, "test help".to_string(), vec![], MetricNamespace::RustFS, MetricSubsystem::ApiRequests, ); assert_eq!(descriptor.get_full_metric_name(), "rustfs_api_requests_total"); } #[test] fn full_metric_name_formats_custom_subsystems_without_type_prefix() { let descriptor = MetricDescriptor::new( MetricName::Custom("latency_seconds".to_string()), MetricType::Histogram, "test help".to_string(), vec![], MetricNamespace::RustFS, MetricSubsystem::new("/custom/path-metrics"), ); assert_eq!(descriptor.get_full_metric_name(), "rustfs_custom_path_metrics_latency_seconds"); } }