diff --git a/meilisearch/src/lib.rs b/meilisearch/src/lib.rs index 435a6518b..2ebed39a3 100644 --- a/meilisearch/src/lib.rs +++ b/meilisearch/src/lib.rs @@ -39,6 +39,7 @@ use meilisearch_types::versioning::{check_version_file, create_version_file}; use meilisearch_types::{compression, milli, VERSION_FILE_NAME}; pub use option::Opt; use option::ScheduleSnapshot; +use tracing_subscriber::filter::Targets; use crate::error::MeilisearchHttpError; @@ -89,9 +90,10 @@ fn is_empty_db(db_path: impl AsRef) -> bool { /// The handle used to update the logs at runtime. Must be accessible from the `main.rs` and the `route/logs.rs`. pub type LogRouteHandle = tracing_subscriber::reload::Handle; + pub type LogRouteType = tracing_subscriber::filter::Filtered< Option + Send + Sync>>, - tracing_subscriber::filter::LevelFilter, + Targets, tracing_subscriber::Registry, >; diff --git a/meilisearch/src/main.rs b/meilisearch/src/main.rs index 23e1aab5a..097a4d9bb 100644 --- a/meilisearch/src/main.rs +++ b/meilisearch/src/main.rs @@ -12,7 +12,9 @@ use anyhow::Context; use index_scheduler::IndexScheduler; use is_terminal::IsTerminal; use meilisearch::analytics::Analytics; -use meilisearch::{analytics, create_app, prototype_name, setup_meilisearch, LogRouteHandle, Opt}; +use meilisearch::{ + analytics, create_app, prototype_name, setup_meilisearch, LogRouteHandle, LogRouteType, Opt, +}; use meilisearch_auth::{generate_master_key, AuthController, MASTER_KEY_MIN_SIZE}; use mimalloc::MiMalloc; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; @@ -28,9 +30,8 @@ static ALLOC: MiMalloc = MiMalloc; #[global_allocator] static ALLOC: stats_alloc::StatsAlloc = stats_alloc::StatsAlloc::new(MiMalloc); -fn default_layer( -) -> tracing_subscriber::filter::Filtered + Send + Sync>>, LevelFilter, S> { - None.with_filter(tracing_subscriber::filter::LevelFilter::OFF) +fn default_layer() -> LogRouteType { + None.with_filter(tracing_subscriber::filter::Targets::new().with_target("", LevelFilter::OFF)) } /// does all the setup before meilisearch is launched diff --git a/meilisearch/src/routes/logs.rs b/meilisearch/src/routes/logs.rs index f8fa5a301..b40a34b91 100644 --- a/meilisearch/src/routes/logs.rs +++ b/meilisearch/src/routes/logs.rs @@ -2,6 +2,7 @@ use std::fmt; use std::io::Write; use std::ops::ControlFlow; use std::str::FromStr; +use std::sync::Arc; use actix_web::web::{Bytes, Data}; use actix_web::{web, HttpRequest, HttpResponse}; @@ -13,6 +14,7 @@ use meilisearch_types::error::deserr_codes::*; use meilisearch_types::error::ResponseError; use tokio::sync::mpsc::{self, UnboundedSender}; use tracing::instrument::WithSubscriber; +use tracing_subscriber::filter::Targets; use tracing_subscriber::Layer; use crate::error::MeilisearchHttpError; @@ -48,7 +50,7 @@ pub enum LogMode { #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct GetLogs { #[deserr(default, error = DeserrJsonError)] - pub level: LogLevel, + pub target: String, #[deserr(default, error = DeserrJsonError)] pub mode: LogMode, @@ -70,6 +72,12 @@ struct LogWriter { sender: mpsc::UnboundedSender>, } +impl Drop for LogWriter { + fn drop(&mut self) { + println!("hello"); + } +} + impl Write for LogWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { self.sender.send(buf.to_vec()).map_err(std::io::Error::other)?; @@ -83,6 +91,17 @@ impl Write for LogWriter { struct LogStreamer { receiver: mpsc::UnboundedReceiver>, + /// We need to keep an handle on the logs to make it available again when the streamer is dropped + logs: Arc, +} + +impl Drop for LogStreamer { + fn drop(&mut self) { + println!("log streamer being dropped"); + if let Err(e) = self.logs.modify(|layer| *layer.inner_mut() = None) { + tracing::error!("Could not free the logs route: {e}"); + } + } } impl LogStreamer { @@ -142,50 +161,16 @@ pub async fn get_logs( _req: HttpRequest, ) -> Result { let opt = body.into_inner(); - - // #[cfg(not(feature = "stats_alloc"))] - // let (mut trace, layer) = tracing_trace::Trace::new(file); - // #[cfg(feature = "stats_alloc")] - // let (mut trace, layer) = tracing_trace::Trace::with_stats_alloc(file, &ALLOC); - let (sender, receiver) = tokio::sync::mpsc::unbounded_channel(); - // let fmt_layer = tracing_subscriber::fmt::layer() - // .with_line_number(true) - // .with_writer(move || LogWriter { sender: sender.clone() }) - // .with_span_events(tracing_subscriber::fmt::format::FmtSpan::ACTIVE) - // .with_filter( - // tracing_subscriber::filter::LevelFilter::from_str(&opt.level.to_string()).unwrap(), - // ); - // let subscriber = tracing_subscriber::registry().with(fmt_layer); - // let subscriber = Box::new(subscriber) as Box + Send + Sync>; - let mut was_available = false; logs.modify(|layer| match layer.inner_mut() { None => { // there is no one getting logs was_available = true; - match opt.mode { - LogMode::Fmt => { - *layer.filter_mut() = - tracing_subscriber::filter::LevelFilter::from_str(&opt.level.to_string()) - .unwrap(); - } - LogMode::Profile => { - *layer.filter_mut() = - tracing_subscriber::filter::LevelFilter::from_str(&opt.level.to_string()) - .unwrap(); - // *layer.filter_mut() = tracing_subscriber::filter::Targets::new() - // .with_target("indexing::", tracing::Level::TRACE) - // .with_filter( - // tracing_subscriber::filter::LevelFilter::from_str( - // &opt.level.to_string(), - // ) - // .unwrap(), - // ) - } - } + *layer.filter_mut() = + tracing_subscriber::filter::Targets::from_str(&opt.target).unwrap(); let new_layer = make_layer(&opt, sender); *layer.inner_mut() = Some(new_layer) @@ -198,7 +183,8 @@ pub async fn get_logs( .unwrap(); if was_available { - Ok(HttpResponse::Ok().streaming(LogStreamer { receiver }.into_stream())) + Ok(HttpResponse::Ok() + .streaming(LogStreamer { receiver, logs: logs.into_inner() }.into_stream())) } else { Err(MeilisearchHttpError::AlreadyUsedLogRoute.into()) }