diff --git a/src/lib.rs b/src/lib.rs index 8119702..0011139 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod configurations; pub mod routes; pub mod startup; +pub mod telemetry; diff --git a/src/main.rs b/src/main.rs index a747986..5d34d56 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,17 @@ use sqlx::PgPool; use std::net::TcpListener; use tracing::subscriber::set_global_default; -use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_log::LogTracer; -use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; -use zero2prod::{configurations::get_configuration, startup::run}; +use zero2prod::{configurations::get_configuration, startup::run, telemetry::get_subscriber}; #[tokio::main] async fn main() -> Result<(), std::io::Error> { // Logger setup LogTracer::init().expect("Failed to set logger"); // Info or above will be logged if the RUST_LOG environment variable is not set - let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); - let foirmatting_layer = BunyanFormattingLayer::new("zero2prod".into(), std::io::stdout); - let subscriber = Registry::default() - .with(env_filter) - .with(JsonStorageLayer) - .with(foirmatting_layer); + let subscriber = get_subscriber("zero2prod".into(), "info".into()); set_global_default(subscriber).expect("Failed to set subscriber"); + // We want to panic if we cannot read the configuration let configuration = get_configuration().expect("Failed to read configurations"); let connection = PgPool::connect(&configuration.database.get_connnection_string()) diff --git a/src/telemetry.rs b/src/telemetry.rs new file mode 100644 index 0000000..420045e --- /dev/null +++ b/src/telemetry.rs @@ -0,0 +1,34 @@ +use tracing::{subscriber::set_global_default, Subscriber}; +use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; +use tracing_log::LogTracer; +use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; + +/// Compose multiple layers into a `tracing`'s subscriber. +/// +/// # Implementation Notes +/// +/// We are using `impl Subscriber` as return type to avoid having to +/// spell out the actual type of the returned subscriber, which is +/// indeed quite complex. +/// We need to explicitly call out that the returned subscriber is +/// `Send` and `Sync` to make it possible to pass it to `init_subscriber` +/// later on. +pub fn get_subscriber(name: String, env_filter: String) -> impl Subscriber + Send + Sync { + let env_filter = + EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter)); + let formatting_layer = BunyanFormattingLayer::new(name.into(), std::io::stdout); + Registry::default() + .with(env_filter) + .with(JsonStorageLayer) + .with(formatting_layer) +} + +/// Register a subscriber as global default to process span data.\ +/// +/// # Implementation Notes +/// +/// It is important to call this function only once. +pub fn inti_subscriber(subscriber: impl Subscriber + Send + Sync) { + LogTracer::init().expect("Failed to set logger"); + set_global_default(subscriber).expect("Failed to set subscriber"); +}