From 9336235b642ca93ef3eaac4fd399a4c644a342ec Mon Sep 17 00:00:00 2001 From: minhtrannhat Date: Tue, 7 May 2024 21:36:16 -0400 Subject: [PATCH] feat(test): log for integration tests - log for test are configurable to either be spit into the void (cargo test default) or into `stdout`. --- Cargo.lock | 1 + Cargo.toml | 1 + src/main.rs | 6 +++++- src/telemetry.rs | 16 +++++++++++++--- tests/test_utils.rs | 18 +++++++++++++++++- 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dbd2bd..28c93bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,6 +613,7 @@ dependencies = [ "actix-web", "chrono", "config", + "once_cell", "reqwest", "serde", "sqlx", diff --git a/Cargo.toml b/Cargo.toml index 2b466ea..c14bfc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ tracing = { version = "0.1.40", features = ["log"] } tracing-subscriber = { version = "0.3.18", features = ["registry", "env-filter"] } tracing-bunyan-formatter = "0.3.9" tracing-log = "0.2.0" +once_cell = "1.19.0" [dependencies.sqlx] version = "0.7" diff --git a/src/main.rs b/src/main.rs index 71dfaeb..746e638 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,11 @@ use sqlx::PgPool; async fn main() -> Result<(), std::io::Error> { let configuration = get_configuration().expect("Failed to read configuration"); - let subscriber = get_subscriber("email_newsletter_api".into(), "info".into()); + let subscriber = get_subscriber( + "email_newsletter_api".into(), + "info".into(), + std::io::stdout, + ); init_subscriber(subscriber); let db_conn = PgPool::connect(&configuration.database.connection_string()) diff --git a/src/telemetry.rs b/src/telemetry.rs index 6c7fb0c..acf3f88 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -2,12 +2,19 @@ use tracing::subscriber::set_global_default; use tracing::Subscriber; use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; use tracing_log::LogTracer; -use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; +use tracing_subscriber::{fmt::MakeWriter, layer::SubscriberExt, EnvFilter, Registry}; -pub fn get_subscriber(name: String, env_filter: String) -> impl Subscriber + Send + Sync { +pub fn get_subscriber( + name: String, + env_filter: String, + sink: Sink, +) -> impl Subscriber + Send + Sync +where + Sink: for<'a> MakeWriter<'a> + Send + Sync + 'static, +{ let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter)); - let formatting_layer = BunyanFormattingLayer::new(name, std::io::stdout); + let formatting_layer = BunyanFormattingLayer::new(name, sink); Registry::default() .with(env_filter) .with(JsonStorageLayer) @@ -15,6 +22,9 @@ pub fn get_subscriber(name: String, env_filter: String) -> impl Subscriber + Sen } // init_subscriber should only be called once +// +// This is solved with the once_cell crate +// until the std::sync::SyncOnceCell is stable in the toolchain pub fn init_subscriber(subscriber: impl Subscriber + Send + Sync) { LogTracer::init().expect("Failed to set logger"); set_global_default(subscriber).expect("Failed to set subscriber"); diff --git a/tests/test_utils.rs b/tests/test_utils.rs index e0a4b13..d18aed7 100644 --- a/tests/test_utils.rs +++ b/tests/test_utils.rs @@ -1,8 +1,22 @@ -use email_newsletter_api::configuration::{get_configuration, DatabaseSettings}; +use email_newsletter_api::{ + configuration::{get_configuration, DatabaseSettings}, + telemetry::{get_subscriber, init_subscriber}, +}; +use once_cell::sync::Lazy; use sqlx::{Connection, Executor, PgConnection, PgPool}; use std::net::TcpListener; use uuid::Uuid; +static TRACING: Lazy<()> = Lazy::new(|| { + if std::env::var("TEST_LOG").is_ok() { + let subscriber = get_subscriber("test".into(), "info".into(), std::io::stdout); + init_subscriber(subscriber); + } else { + let subscriber = get_subscriber("test".into(), "debug".into(), std::io::sink); + init_subscriber(subscriber); + } +}); + pub struct TestApp { pub address: String, pub db_pool: PgPool, @@ -10,6 +24,8 @@ pub struct TestApp { #[allow(clippy::let_underscore_future)] pub async fn spawn_app() -> TestApp { + Lazy::force(&TRACING); + /* Spawn a app server with a TcpListener bound to localhost: * * Returns a valid IPv4 string (i.e localhost:8080)