clnrm_core/validation/
common.rs

1//! Common validation utilities shared across validators
2//!
3//! This module provides shared functionality to eliminate duplication
4//! in validation logic, error creation, and span processing.
5
6use crate::validation::span_validator::SpanData;
7
8/// Check if span is an error span
9///
10/// Checks multiple attributes to determine if a span represents an error:
11/// - `otel.status_code` == "ERROR"
12/// - `error` == true
13///
14/// # Arguments
15/// * `span` - The span to check
16///
17/// # Returns
18/// * `bool` - True if span represents an error
19pub fn is_error_span(span: &SpanData) -> bool {
20    span.attributes
21        .get("otel.status_code")
22        .and_then(|v| v.as_str())
23        .map(|s| s == "ERROR")
24        .unwrap_or(false)
25        || span
26            .attributes
27            .get("error")
28            .and_then(|v| v.as_bool())
29            .unwrap_or(false)
30}
31
32/// Get span status code
33///
34/// Extracts the OTEL status code from span attributes.
35/// Checks multiple attribute keys and defaults to "UNSET" if not found.
36///
37/// # Arguments
38/// * `span` - The span to extract status from
39///
40/// # Returns
41/// * `String` - Status code (UNSET, OK, or ERROR)
42pub fn get_span_status(span: &SpanData) -> String {
43    span.attributes
44        .get("otel.status_code")
45        .and_then(|v| v.as_str())
46        .map(|s| s.to_string())
47        .or_else(|| {
48            span.attributes
49                .get("status")
50                .and_then(|v| v.as_str())
51                .map(|s| s.to_string())
52        })
53        .unwrap_or_else(|| "UNSET".to_string())
54}
55
56/// Count spans by name
57///
58/// # Arguments
59/// * `spans` - Slice of spans to count
60/// * `name` - Name to count
61///
62/// # Returns
63/// * `usize` - Count of matching spans
64pub fn count_spans_by_name(spans: &[SpanData], name: &str) -> usize {
65    spans.iter().filter(|s| s.name == name).count()
66}
67
68/// Count error spans
69///
70/// # Arguments
71/// * `spans` - Slice of spans to count
72///
73/// # Returns
74/// * `usize` - Count of error spans
75pub fn count_error_spans(spans: &[SpanData]) -> usize {
76    spans.iter().filter(|s| is_error_span(s)).count()
77}