commonware_runtime/tokio/
telemetry.rs1use super::{
4 tracing::{export, Config},
5 Context,
6};
7use crate::{Metrics, Spawner};
8use axum::{
9 body::Body,
10 http::{header, Response, StatusCode},
11 routing::get,
12 serve, Extension, Router,
13};
14use std::net::SocketAddr;
15use tokio::net::TcpListener;
16use tracing::Level;
17use tracing_subscriber::{layer::SubscriberExt, Layer, Registry};
18
19pub struct Logging {
21 pub level: Level,
23
24 pub json: bool,
30}
31
32pub fn init(
34 context: Context,
35 logging: Logging,
36 metrics: Option<SocketAddr>,
37 traces: Option<Config>,
38) {
39 let filter = tracing_subscriber::EnvFilter::new(logging.level.to_string());
41
42 let log_layer = tracing_subscriber::fmt::layer()
44 .with_line_number(true)
45 .with_thread_ids(true)
46 .with_file(true)
47 .with_span_events(tracing_subscriber::fmt::format::FmtSpan::CLOSE);
48
49 let log_layer = if logging.json {
51 log_layer.json().boxed()
52 } else {
53 log_layer.pretty().boxed()
54 };
55
56 let trace_layer = traces.map(|cfg| {
58 let tracer = export(cfg).expect("Failed to initialize tracer");
59 tracing_opentelemetry::layer().with_tracer(tracer)
60 });
61
62 let registry = Registry::default()
64 .with(filter)
65 .with(log_layer)
66 .with(trace_layer);
67 tracing::subscriber::set_global_default(registry).expect("Failed to set subscriber");
68
69 if let Some(cfg) = metrics {
71 context
72 .with_label("metrics")
73 .spawn(move |context| async move {
74 let listener = TcpListener::bind(cfg)
80 .await
81 .expect("Failed to bind metrics server");
82
83 let app = Router::new()
85 .route(
86 "/metrics",
87 get(|Extension(ctx): Extension<Context>| async move {
88 Response::builder()
89 .status(StatusCode::OK)
90 .header(header::CONTENT_TYPE, "text/plain; version=0.0.4")
91 .body(Body::from(ctx.encode()))
92 .expect("Failed to create response")
93 }),
94 )
95 .layer(Extension(context));
96
97 serve(listener, app.into_make_service())
102 .await
103 .expect("Could not serve metrics");
104 });
105 }
106}