udb/runtime/
observability.rs1use serde::{Deserialize, Serialize};
2#[cfg(feature = "runtime-logging")]
3use tracing_subscriber::EnvFilter;
4
5#[cfg(feature = "runtime-logging")]
6use super::pretty_log::PrettyLog;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
9pub struct TraceContext {
10 pub trace_id: String,
11 pub span_id: String,
12 pub parent_span_id: String,
13 pub correlation_id: String,
14}
15
16#[cfg(feature = "runtime-logging")]
17pub fn init_observability() {
18 let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
19
20 let json = std::env::var("UDB_LOG_JSON")
23 .map(|v| match v.to_ascii_lowercase().as_str() {
24 "1" | "true" | "yes" | "on" => true,
25 "0" | "false" | "no" | "off" => false,
26 other => {
27 eprintln!(
28 "unrecognized UDB_LOG_JSON value '{other}'; expected 1/0, true/false, yes/no, or on/off"
29 );
30 false
31 }
32 })
33 .unwrap_or(false);
34
35 if json {
36 let _ = tracing_subscriber::fmt()
37 .with_env_filter(filter)
38 .json()
39 .try_init();
40 } else {
41 let colors = std::env::var("NO_COLOR").is_err()
42 && std::env::var("UDB_NO_COLOR")
43 .map(|v| match v.to_ascii_lowercase().as_str() {
44 "1" | "true" | "yes" | "on" => false,
45 "0" | "false" | "no" | "off" => true,
46 other => {
47 eprintln!(
48 "unrecognized UDB_NO_COLOR value '{other}'; expected 1/0, true/false, yes/no, or on/off"
49 );
50 true
51 }
52 })
53 .unwrap_or(true);
54 let _ = tracing_subscriber::fmt()
55 .with_env_filter(filter)
56 .event_format(PrettyLog { colors })
57 .try_init();
58 }
59}
60
61#[cfg(not(feature = "runtime-logging"))]
62pub fn init_observability() {}
63
64impl TraceContext {
65 pub fn from_correlation(correlation_id: impl Into<String>) -> Self {
66 Self {
67 correlation_id: correlation_id.into(),
68 ..Self::default()
69 }
70 }
71
72 pub fn is_present(&self) -> bool {
73 !self.trace_id.is_empty()
74 || !self.span_id.is_empty()
75 || !self.parent_span_id.is_empty()
76 || !self.correlation_id.is_empty()
77 }
78
79 pub fn is_complete(&self) -> bool {
80 !self.trace_id.is_empty() && !self.span_id.is_empty()
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
85pub struct MetricLabels {
86 pub tier: String,
87 pub backend: String,
88 pub resource_kind: String,
89 pub operation: String,
90}