#[must_use]
pub const fn scope() -> &'static str {
"phase-2-v1"
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum HealthState {
Ready,
Live,
NotReady,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HealthSnapshot<'a> {
pub component: &'a str,
pub readiness: HealthState,
pub liveness: HealthState,
pub degradation_reason: Option<&'a str>,
pub checked_at_epoch_seconds: u64,
}
impl<'a> HealthSnapshot<'a> {
#[must_use]
pub const fn degraded(
component: &'a str,
degradation_reason: &'a str,
checked_at_epoch_seconds: u64,
) -> Self {
Self {
component,
readiness: HealthState::NotReady,
liveness: HealthState::Live,
degradation_reason: Some(degradation_reason),
checked_at_epoch_seconds,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MetricKind {
Counter,
Gauge,
Histogram,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MetricSpec {
pub name: &'static str,
pub kind: MetricKind,
pub unit: &'static str,
pub description: &'static str,
pub required_tags: &'static [&'static str],
}
const BASELINE_METRICS: [MetricSpec; 3] = [
MetricSpec {
name: "alloy.build.info",
kind: MetricKind::Gauge,
unit: "build",
description: "Build and version provenance for the emitting surface.",
required_tags: &["crate", "version", "commit", "maturity_tier"],
},
MetricSpec {
name: "alloy.operation.duration_ms",
kind: MetricKind::Histogram,
unit: "milliseconds",
description: "Duration for externally visible operations.",
required_tags: &["surface", "operation", "outcome"],
},
MetricSpec {
name: "alloy.cache.requests",
kind: MetricKind::Counter,
unit: "requests",
description: "Cache interactions for artifact and storage seams.",
required_tags: &["surface", "cache_name", "outcome"],
},
];
const SERVICE_METRICS: [MetricSpec; 4] = [
MetricSpec {
name: "alloy.service.requests_total",
kind: MetricKind::Counter,
unit: "requests",
description: "Total externally visible service requests handled by the surface.",
required_tags: &["service", "route", "method", "outcome"],
},
MetricSpec {
name: "alloy.service.request_duration_ms",
kind: MetricKind::Histogram,
unit: "milliseconds",
description: "Latency distribution for externally visible service requests.",
required_tags: &["service", "route", "method", "outcome"],
},
MetricSpec {
name: "alloy.service.in_flight_requests",
kind: MetricKind::Gauge,
unit: "requests",
description: "Current concurrent externally visible requests for the service surface.",
required_tags: &["service"],
},
MetricSpec {
name: "alloy.service.exporter_failures_total",
kind: MetricKind::Counter,
unit: "failures",
description: "Exporter failures observed while publishing telemetry from the surface.",
required_tags: &["service", "exporter", "failure_kind"],
},
];
#[must_use]
pub const fn baseline_metric_catalog() -> &'static [MetricSpec] {
&BASELINE_METRICS
}
#[must_use]
pub const fn service_metric_catalog() -> &'static [MetricSpec] {
&SERVICE_METRICS
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExporterMode {
Log,
Prometheus,
OpenTelemetry,
}
impl ExporterMode {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Log => "log",
Self::Prometheus => "prometheus",
Self::OpenTelemetry => "opentelemetry",
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ExporterSpec<'a> {
pub mode: ExporterMode,
pub endpoint: &'a str,
pub service_name: &'a str,
}
impl<'a> ExporterSpec<'a> {
#[must_use]
pub const fn new(mode: ExporterMode, endpoint: &'a str, service_name: &'a str) -> Self {
Self {
mode,
endpoint,
service_name,
}
}
#[must_use]
pub fn is_enabled(&self) -> bool {
!self.endpoint.is_empty()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ServiceTraceSpec<'a> {
pub service_name: &'a str,
pub route: &'a str,
pub method: &'a str,
}
impl<'a> ServiceTraceSpec<'a> {
#[must_use]
pub const fn new(service_name: &'a str, route: &'a str, method: &'a str) -> Self {
Self {
service_name,
route,
method,
}
}
#[must_use]
pub fn span_name(&self) -> String {
format!("{}.{}.{}", self.service_name, self.method, self.route)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TraceContext<'a> {
pub operation: &'a str,
pub trace_id: &'a str,
pub span_id: &'a str,
pub parent_span_id: Option<&'a str>,
pub correlation_id: Option<&'a str>,
}
impl<'a> TraceContext<'a> {
#[must_use]
pub const fn child(
operation: &'a str,
trace_id: &'a str,
span_id: &'a str,
parent_span_id: &'a str,
correlation_id: Option<&'a str>,
) -> Self {
Self {
operation,
trace_id,
span_id,
parent_span_id: Some(parent_span_id),
correlation_id,
}
}
}
#[cfg(test)]
mod tests {
use super::{
ExporterMode, ExporterSpec, HealthSnapshot, HealthState, MetricKind, ServiceTraceSpec,
TraceContext, baseline_metric_catalog, scope, service_metric_catalog,
};
#[test]
fn sprint_4_scope_is_exposed() {
assert_eq!(scope(), "phase-2-v1");
}
#[test]
fn baseline_catalog_covers_required_metric_groups() {
let catalog = baseline_metric_catalog();
assert!(
catalog
.iter()
.any(|metric| metric.name == "alloy.build.info")
);
assert!(
catalog
.iter()
.any(|metric| metric.name == "alloy.operation.duration_ms")
);
assert!(
catalog
.iter()
.any(|metric| metric.name == "alloy.cache.requests")
);
assert!(
catalog
.iter()
.any(|metric| metric.kind == MetricKind::Histogram)
);
}
#[test]
fn degraded_health_snapshot_carries_reason() {
let snapshot =
HealthSnapshot::degraded("iridium-evaluator", "cache warmup in progress", 42);
assert_eq!(snapshot.component, "iridium-evaluator");
assert_eq!(snapshot.readiness, HealthState::NotReady);
assert_eq!(snapshot.liveness, HealthState::Live);
assert_eq!(
snapshot.degradation_reason,
Some("cache warmup in progress")
);
}
#[test]
fn trace_context_formats_parent_relationship() {
let trace = TraceContext::child(
"embedded-query",
"trace-001",
"span-002",
"span-001",
Some("scenario-abc"),
);
assert_eq!(trace.operation, "embedded-query");
assert_eq!(trace.parent_span_id, Some("span-001"));
assert_eq!(trace.correlation_id, Some("scenario-abc"));
}
#[test]
fn service_metric_catalog_covers_request_and_exporter_paths() {
let catalog = service_metric_catalog();
assert!(
catalog
.iter()
.any(|metric| metric.name == "alloy.service.requests_total")
);
assert!(
catalog
.iter()
.any(|metric| metric.name == "alloy.service.request_duration_ms")
);
assert!(
catalog
.iter()
.any(|metric| metric.name == "alloy.service.exporter_failures_total")
);
}
#[test]
fn exporter_spec_tracks_enabled_state() {
let enabled = ExporterSpec::new(
ExporterMode::Prometheus,
"127.0.0.1:9090",
"iridium-service",
);
let disabled = ExporterSpec::new(ExporterMode::Log, "", "iridium-service");
assert!(enabled.is_enabled());
assert!(!disabled.is_enabled());
assert_eq!(enabled.mode.as_str(), "prometheus");
}
#[test]
fn service_trace_spec_builds_canonical_span_name() {
let trace = ServiceTraceSpec::new("iridium", "query", "post");
assert_eq!(trace.span_name(), "iridium.post.query");
}
}