pub mod metric_names {
pub const REQUESTS_TOTAL: &str = "stateset_requests_total";
pub const REQUEST_ERRORS_TOTAL: &str = "stateset_request_errors_total";
pub const REQUEST_DURATION_MS_TOTAL: &str = "stateset_request_duration_ms_total";
}
pub mod metric_labels {
pub const SERVICE: &str = "service";
pub const OPERATION: &str = "operation";
pub const ENVIRONMENT: &str = "environment";
pub const REGION: &str = "region";
pub const OUTCOME: &str = "outcome";
}
pub mod span_fields {
pub const SERVICE: &str = "stateset.service";
pub const ENVIRONMENT: &str = "stateset.environment";
pub const REGION: &str = "stateset.region";
pub const OPERATION: &str = "stateset.operation";
pub const OUTCOME: &str = "stateset.outcome";
pub const ERROR: &str = "stateset.error";
}
#[must_use]
pub fn normalize_name(raw: &str) -> String {
let mut normalized = String::with_capacity(raw.len());
let mut last_was_sep = false;
for ch in raw.chars() {
let c = ch.to_ascii_lowercase();
if c.is_ascii_alphanumeric() {
normalized.push(c);
last_was_sep = false;
} else if !last_was_sep {
normalized.push('_');
last_was_sep = true;
}
}
let trimmed = normalized.trim_matches('_');
if trimmed.is_empty() { "unknown".to_string() } else { trimmed.to_string() }
}
#[must_use]
pub fn operation_span_name(operation: &str) -> String {
format!("stateset.{}", normalize_name(operation))
}
#[must_use]
pub fn operation_metric_label(operation: &str) -> String {
normalize_name(operation)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normalize_name_lowercases_and_sanitizes() {
assert_eq!(normalize_name("Order.Created"), "order_created");
assert_eq!(normalize_name(" checkout / start "), "checkout_start");
assert_eq!(normalize_name("A---B___C"), "a_b_c");
}
#[test]
fn normalize_name_falls_back_to_unknown() {
assert_eq!(normalize_name(""), "unknown");
assert_eq!(normalize_name("___"), "unknown");
assert_eq!(normalize_name(" "), "unknown");
}
#[test]
fn operation_names_use_normalized_suffix() {
assert_eq!(operation_span_name("Order Paid"), "stateset.order_paid");
assert_eq!(operation_metric_label("Order Paid"), "order_paid");
}
#[test]
fn normalize_name_single_word() {
assert_eq!(normalize_name("hello"), "hello");
}
#[test]
fn normalize_name_uppercase() {
assert_eq!(normalize_name("HELLO"), "hello");
}
#[test]
fn normalize_name_mixed_case() {
assert_eq!(normalize_name("hElLo"), "hello");
}
#[test]
fn normalize_name_alphanumeric() {
assert_eq!(normalize_name("order123"), "order123");
}
#[test]
fn normalize_name_numbers_only() {
assert_eq!(normalize_name("12345"), "12345");
}
#[test]
fn normalize_name_leading_trailing_separators() {
assert_eq!(normalize_name("---hello---"), "hello");
}
#[test]
fn normalize_name_dots() {
assert_eq!(normalize_name("a.b.c"), "a_b_c");
}
#[test]
fn normalize_name_slashes() {
assert_eq!(normalize_name("a/b/c"), "a_b_c");
}
#[test]
fn normalize_name_colons() {
assert_eq!(normalize_name("a:b:c"), "a_b_c");
}
#[test]
fn normalize_name_tabs_and_newlines() {
assert_eq!(normalize_name("a\tb\nc"), "a_b_c");
}
#[test]
fn normalize_name_consecutive_separators_collapse() {
assert_eq!(normalize_name("a...b///c---d"), "a_b_c_d");
}
#[test]
fn normalize_name_single_separator() {
assert_eq!(normalize_name("."), "unknown");
assert_eq!(normalize_name("-"), "unknown");
assert_eq!(normalize_name("/"), "unknown");
}
#[test]
fn normalize_name_unicode_non_ascii() {
assert_eq!(normalize_name("order\u{00e9}created"), "order_created");
}
#[test]
fn normalize_name_single_char() {
assert_eq!(normalize_name("a"), "a");
assert_eq!(normalize_name("Z"), "z");
assert_eq!(normalize_name("5"), "5");
}
#[test]
fn normalize_name_very_long() {
let long = "a".repeat(10_000);
let result = normalize_name(&long);
assert_eq!(result.len(), 10_000);
}
#[test]
fn operation_span_name_empty_input() {
assert_eq!(operation_span_name(""), "stateset.unknown");
}
#[test]
fn operation_span_name_with_dots() {
assert_eq!(operation_span_name("order.create"), "stateset.order_create");
}
#[test]
fn operation_span_name_preserves_numbers() {
assert_eq!(operation_span_name("api/v2/orders"), "stateset.api_v2_orders");
}
#[test]
fn operation_metric_label_empty_input() {
assert_eq!(operation_metric_label(""), "unknown");
}
#[test]
fn operation_metric_label_already_normalized() {
assert_eq!(operation_metric_label("order_create"), "order_create");
}
#[test]
fn operation_metric_label_complex() {
assert_eq!(operation_metric_label("API/v1/Checkout---Start"), "api_v1_checkout_start");
}
#[test]
fn metric_names_have_stateset_prefix() {
assert!(metric_names::REQUESTS_TOTAL.starts_with("stateset_"));
assert!(metric_names::REQUEST_ERRORS_TOTAL.starts_with("stateset_"));
assert!(metric_names::REQUEST_DURATION_MS_TOTAL.starts_with("stateset_"));
}
#[test]
fn metric_names_are_distinct() {
let names = [
metric_names::REQUESTS_TOTAL,
metric_names::REQUEST_ERRORS_TOTAL,
metric_names::REQUEST_DURATION_MS_TOTAL,
];
for i in 0..names.len() {
for j in (i + 1)..names.len() {
assert_ne!(names[i], names[j], "Metric names must be unique");
}
}
}
#[test]
fn metric_labels_are_distinct() {
let labels = [
metric_labels::SERVICE,
metric_labels::OPERATION,
metric_labels::ENVIRONMENT,
metric_labels::REGION,
metric_labels::OUTCOME,
];
for i in 0..labels.len() {
for j in (i + 1)..labels.len() {
assert_ne!(labels[i], labels[j], "Metric labels must be unique");
}
}
}
#[test]
fn span_fields_have_stateset_prefix() {
assert!(span_fields::SERVICE.starts_with("stateset."));
assert!(span_fields::ENVIRONMENT.starts_with("stateset."));
assert!(span_fields::REGION.starts_with("stateset."));
assert!(span_fields::OPERATION.starts_with("stateset."));
assert!(span_fields::OUTCOME.starts_with("stateset."));
assert!(span_fields::ERROR.starts_with("stateset."));
}
#[test]
fn span_fields_are_distinct() {
let fields = [
span_fields::SERVICE,
span_fields::ENVIRONMENT,
span_fields::REGION,
span_fields::OPERATION,
span_fields::OUTCOME,
span_fields::ERROR,
];
for i in 0..fields.len() {
for j in (i + 1)..fields.len() {
assert_ne!(fields[i], fields[j], "Span fields must be unique");
}
}
}
}