Skip to main content

valence_telemetry/
lib.rs

1//! Valence self-telemetry port.
2//!
3//! **Audience:** integrators installing metrics at boot and adapter authors
4//! implementing custom sinks.
5
6#![deny(missing_docs)]
7
8mod console;
9mod dispatch;
10mod noop;
11mod recording;
12
13pub use console::ConsoleSink;
14pub use dispatch::{
15    install_telemetry_sink, json_value_to_fields, telemetry_sink, try_log_event,
16    try_log_event_value, try_record_counter, try_record_gauge,
17};
18pub use noop::NoOpSink;
19pub use recording::{RecordedCounter, RecordedEvent, RecordedGauge, RecordingSink};
20
21/// Host-injectable telemetry sink for Valence ORM metrics and events.
22///
23/// Install with `ValenceBuilder::telemetry_sink` on the facade / `valence-core`.
24/// Instrumentation calls [`try_record_counter`], [`try_record_gauge`], and
25/// [`try_log_event_value`] — never a product SDK from upstream code.
26///
27/// Reference impls: [`NoOpSink`] (default), [`ConsoleSink`] (facade `telemetry-console`
28/// feature). Custom sinks belong in host crates.
29///
30/// # Examples
31///
32/// ```
33/// use valence_telemetry::{ConsoleSink, TelemetrySink};
34///
35/// let sink = ConsoleSink;
36/// sink.record_counter("valence_queries", &[("backend", "mem")], 1);
37/// sink.record_gauge("valence_active_connections", &[], 0.0);
38/// sink.log_event("valence.boot", &[("phase", "ready")]);
39/// ```
40pub trait TelemetrySink: Send + Sync {
41    /// Increment a counter metric by `delta` with optional label dimensions.
42    fn record_counter(&self, name: &str, labels: &[(&str, &str)], delta: u64);
43
44    /// Record a gauge sample with optional label dimensions.
45    fn record_gauge(&self, name: &str, labels: &[(&str, &str)], value: f64);
46
47    /// Emit a structured log event from flat field tuples.
48    fn log_event(&self, schema: &str, fields: &[(&str, &str)]);
49
50    /// Structured event with JSON payload (default flattens top-level object keys).
51    fn log_event_value(&self, schema: &str, payload: &serde_json::Value) {
52        let owned = json_value_to_fields(payload);
53        let refs: Vec<(&str, &str)> = owned
54            .iter()
55            .map(|(k, v)| (k.as_str(), v.as_str()))
56            .collect();
57        self.log_event(schema, &refs);
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn noop_sink_accepts_metrics() {
67        let sink = NoOpSink;
68        sink.record_counter("valence_queries", &[("backend", "mem")], 1);
69        sink.record_gauge("valence_active_connections", &[], 0.0);
70        sink.log_event("valence.record.created", &[("table", "user")]);
71    }
72
73    #[test]
74    fn console_sink_accepts_metrics() {
75        let sink = ConsoleSink;
76        sink.record_counter("valence_queries", &[], 1);
77    }
78}