diff --git a/src/interpreter/clickhouse.rs b/src/interpreter/clickhouse.rs index e34a4a4..0258d58 100644 --- a/src/interpreter/clickhouse.rs +++ b/src/interpreter/clickhouse.rs @@ -655,7 +655,7 @@ impl ClickHouse { pub async fn get_query_logs( &self, - query_ids: &[String], + query_ids: &Option>, start_microseconds: DateTime, end_microseconds: Option>, ) -> Result { @@ -689,7 +689,7 @@ impl ClickHouse { WHERE event_date >= toDate(start_time_) AND event_time > toDateTime(start_time_) AND event_time_microseconds > start_time_ AND event_date <= toDate(end_time_) AND event_time <= toDateTime(end_time_) AND event_time_microseconds <= end_time_ - AND query_id IN ('{}') + {} // TODO: if query finished, add filter for event_time end range ORDER BY event_date, event_time, event_time_microseconds "#, @@ -701,7 +701,11 @@ impl ClickHouse { .timestamp_nanos_opt() .ok_or(Error::msg("Invalid end time"))?, dbtable, - query_ids.join("','"), + if let Some(query_ids) = query_ids { + format!("AND query_id IN ('{}')", query_ids.join("','")) + } else { + "".into() + } ) .as_str(), ) diff --git a/src/interpreter/options.rs b/src/interpreter/options.rs index 1d03086..200c790 100644 --- a/src/interpreter/options.rs +++ b/src/interpreter/options.rs @@ -80,6 +80,8 @@ pub enum ChDigViews { Backups, /// Show information about dictionaries (system.dictionaries) Dictionaries, + /// Show server logs (system.text_log) + ServerLogs, } #[derive(Parser, Clone)] diff --git a/src/interpreter/worker.rs b/src/interpreter/worker.rs index a0657ec..a4aede8 100644 --- a/src/interpreter/worker.rs +++ b/src/interpreter/worker.rs @@ -24,8 +24,13 @@ pub enum Event { UpdateSlowQueryLog(String, DateTime, DateTime, u64), // [filter, start, end, limit] UpdateLastQueryLog(String, DateTime, DateTime, u64), - // ([query_ids], start, end) - GetQueryTextLog(Vec, DateTime, Option>), + // (view_name, [query_ids], start, end) + GetQueryTextLog( + &'static str, + Option>, + DateTime, + Option>, + ), // [bool (true - show in TUI, false - open in browser), type, start, end] ShowServerFlameGraph(bool, TraceType, DateTime, DateTime), // (type, bool (true - show in TUI, false - open in browser), start time, end time, [query_ids]) @@ -275,14 +280,14 @@ async fn process_event(context: ContextArc, event: Event, need_clear: &mut bool) })) .map_err(|_| anyhow!("Cannot send message to UI"))?; } - Event::GetQueryTextLog(query_ids, start_microseconds, end_microseconds) => { + Event::GetQueryTextLog(view_name, query_ids, start_microseconds, end_microseconds) => { let block = clickhouse .get_query_logs(&query_ids, start_microseconds, end_microseconds) .await?; cb_sink .send(Box::new(move |siv: &mut cursive::Cursive| { siv.call_on_name_or_render_error( - "query_log", + view_name, move |view: &mut view::TextLogView| { return view.update(block); }, diff --git a/src/view/navigation.rs b/src/view/navigation.rs index c6df65f..7f051b4 100644 --- a/src/view/navigation.rs +++ b/src/view/navigation.rs @@ -4,7 +4,7 @@ use crate::{ options::{parse_datetime, ChDigViews}, ContextArc, WorkerEvent, }, - view, + view::{self, TextLogView}, }; use anyhow::Result; #[cfg(not(target_family = "windows"))] @@ -78,6 +78,7 @@ pub trait Navigation { fn show_clickhouse_errors(&mut self, context: ContextArc); fn show_clickhouse_backups(&mut self, context: ContextArc); fn show_clickhouse_dictionaries(&mut self, context: ContextArc); + fn show_clickhouse_server_logs(&mut self, context: ContextArc); #[allow(clippy::too_many_arguments)] fn show_query_result_view( @@ -262,6 +263,7 @@ impl Navigation for Cursive { ChDigViews::Errors => self.show_clickhouse_errors(context.clone()), ChDigViews::Backups => self.show_clickhouse_backups(context.clone()), ChDigViews::Dictionaries => self.show_clickhouse_dictionaries(context.clone()), + ChDigViews::ServerLogs => self.show_clickhouse_server_logs(context.clone()), } } @@ -372,6 +374,12 @@ impl Navigation for Cursive { siv.show_clickhouse_dictionaries(ctx.clone()) }); } + { + let ctx = context.clone(); + c.add_view("Server logs", move |siv| { + siv.show_clickhouse_server_logs(ctx.clone()) + }); + } { let ctx = context.clone(); c.add_view("Errors", move |siv| siv.show_clickhouse_errors(ctx.clone())); @@ -968,6 +976,33 @@ impl Navigation for Cursive { ); } + fn show_clickhouse_server_logs(&mut self, context: ContextArc) { + if self.has_view("server_logs") { + return; + } + + let view_options = context.clone().lock().unwrap().options.view.clone(); + + self.drop_main_view(); + self.set_main_view( + LinearLayout::vertical() + .child(TextView::new("Server logs:").center()) + .child(DummyView.fixed_height(1)) + .child( + TextLogView::new( + "server_logs", + context, + view_options.start, + Some(view_options.end), + None, + ) + .with_name("server_logs") + .full_screen(), + ), + ); + self.focus_name("server_logs").unwrap(); + } + fn show_query_result_view( &mut self, context: ContextArc, diff --git a/src/view/processes_view.rs b/src/view/processes_view.rs index 0aa999b..a132b90 100644 --- a/src/view/processes_view.rs +++ b/src/view/processes_view.rs @@ -956,10 +956,11 @@ impl ProcessesView { .child(views::NamedView::new( "query_log", TextLogView::new( + "query_log", context_copy, min_query_start_microseconds, max_query_end_microseconds, - query_ids, + Some(query_ids), ), )), )); diff --git a/src/view/text_log_view.rs b/src/view/text_log_view.rs index 8c5f918..af1d3eb 100644 --- a/src/view/text_log_view.rs +++ b/src/view/text_log_view.rs @@ -25,10 +25,11 @@ const FLUSH_INTERVAL_MILLISECONDS: i64 = 7500; impl TextLogView { pub fn new( + view_name: &'static str, context: ContextArc, min_query_start_microseconds: DateTime64, max_query_end_microseconds: Option, - query_ids: Vec, + query_ids: Option>, ) -> Self { let flush_interval_milliseconds = Duration::try_milliseconds(FLUSH_INTERVAL_MILLISECONDS).unwrap(); @@ -52,6 +53,7 @@ impl TextLogView { .unwrap() .worker .send(WorkerEvent::GetQueryTextLog( + view_name, query_ids.clone(), query_start_microseconds, max_query_end_microseconds, @@ -64,6 +66,7 @@ impl TextLogView { move || { update_callback_context.lock().unwrap().worker.send( WorkerEvent::GetQueryTextLog( + view_name, update_query_ids.clone(), *update_last_event_time_microseconds.lock().unwrap(), max_query_end_microseconds,