hydro_lang/telemetry/
mod.rs1use tracing::Subscriber;
3use tracing_subscriber::EnvFilter;
4use tracing_subscriber::fmt::{FormatEvent, FormatFields, FormattedFields};
5use tracing_subscriber::registry::LookupSpan;
6
7use crate::location::{LocationKey, LocationType};
8
9#[cfg(feature = "telemetry_emf")]
10pub mod emf;
11
12struct Formatter;
13
14impl<S, N> FormatEvent<S, N> for Formatter
15where
16 S: Subscriber + for<'a> LookupSpan<'a>,
17 N: for<'a> FormatFields<'a> + 'static,
18{
19 fn format_event(
20 &self,
21 ctx: &tracing_subscriber::fmt::FmtContext<'_, S, N>,
22 mut writer: tracing_subscriber::fmt::format::Writer<'_>,
23 event: &tracing::Event<'_>,
24 ) -> std::fmt::Result {
25 use colored::Colorize;
26
27 let metadata = event.metadata();
28
29 if writer.has_ansi_escapes() {
30 write!(
31 &mut writer,
32 "{} {} {}{} {} {}:{}: ",
33 chrono::Utc::now()
34 .format("%Y-%m-%dT%H:%M:%S%.f%:z")
35 .to_string()
36 .magenta()
37 .underline()
38 .on_white(),
39 metadata.level().as_str().red(),
40 std::thread::current()
41 .name()
42 .unwrap_or("unnamed-thread")
43 .blue(),
44 format!("({:?})", std::thread::current().id()).blue(),
45 metadata.target().green(),
47 metadata.file().unwrap_or("unknown-file").red(),
48 format!("{}", metadata.line().unwrap_or(0)).red(),
49 )?;
50 } else {
51 write!(
52 &mut writer,
53 "{} {} {}{:?} {} {}:{}: ",
54 chrono::Utc::now().format("%Y-%m-%dT%H:%M:%S%.f%:z"),
55 metadata.level().as_str().red(),
56 std::thread::current().name().unwrap_or("unnamed-thread"),
57 std::thread::current().id(),
58 metadata.target(),
60 metadata.file().unwrap_or("unknown-file"),
61 metadata.line().unwrap_or(0),
62 )?;
63 }
64
65 if let Some(scope) = ctx.event_scope() {
66 for span in scope.from_root() {
67 if writer.has_ansi_escapes() {
68 write!(writer, "{}", span.name().purple())?;
69 } else {
70 write!(writer, "{}", span.name())?;
71 }
72
73 let ext = span.extensions();
74 let fields = &ext.get::<FormattedFields<N>>().unwrap();
75
76 if !fields.is_empty() {
77 if writer.has_ansi_escapes() {
78 write!(writer, "{{{}}}", fields.cyan())?;
79 } else {
80 write!(writer, "{{{}}}", fields)?;
81 }
82 }
83
84 write!(writer, ": ")?;
85 }
86 }
87
88 if writer.has_ansi_escapes() {
89 write!(writer, "{}: ", metadata.name().yellow().bold().underline())?;
90 } else {
91 write!(writer, "{}: ", metadata.name())?;
92 }
93
94 ctx.field_format().format_fields(writer.by_ref(), event)?;
95
96 writeln!(writer)
97 }
98}
99
100pub fn initialize_tracing() {
102 let rust_log = std::env::var("RUST_LOG").unwrap_or_else(|err| {
103 match err {
104 std::env::VarError::NotPresent => {
105 "error".to_owned()
107 }
108 std::env::VarError::NotUnicode(v) => {
109 eprintln!(
111 "RUST_LOG is not unicode, defaulting to 'error' directive: {:?}",
112 v
113 );
114 "error".to_owned()
115 }
116 }
117 });
118
119 let filter = EnvFilter::try_new(&rust_log).unwrap_or_else(|err| {
120 eprintln!("Failed to parse RUST_LOG: {}, err: {:?}", rust_log, err);
122 "error".to_owned().parse().unwrap()
123 });
124
125 initialize_tracing_with_filter(filter)
126}
127
128pub fn initialize_tracing_with_filter(filter: EnvFilter) {
131 use tracing::subscriber::set_global_default;
132 use tracing_subscriber::fmt::format::FmtSpan;
133 use tracing_subscriber::prelude::*;
134 use tracing_subscriber::{Layer, fmt, registry};
135
136 set_global_default(
137 registry().with(
138 fmt::layer()
139 .with_writer(std::io::stderr)
140 .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
141 .event_format(Formatter)
142 .with_filter(filter.clone()),
143 ),
144 )
145 .unwrap();
146
147 #[expect(
148 non_snake_case,
149 reason = "this variable represents an env var which is in all caps"
150 )]
151 let RUST_LOG = std::env::var("RUST_LOG");
152
153 tracing::trace!(name: "Tracing Initialized", ?RUST_LOG, ?filter);
154}
155
156pub trait Sidecar {
158 fn to_expr(
162 &self,
163 flow_name: &str,
164 location_key: LocationKey,
165 location_type: LocationType,
166 location_name: &str,
167 dfir_ident: &syn::Ident,
168 ) -> syn::Expr;
169}