From 0da3a45312b989240a790675eeca287bbedb112a Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 17 Aug 2025 19:22:16 -0500 Subject: [PATCH] Finish basic logging setup with tracing --- crates/djls-dev/src/bin/djls-tmux.rs | 14 ++++-- crates/djls-server/src/logging.rs | 71 ++++++---------------------- crates/djls-server/src/server.rs | 35 +++++++------- 3 files changed, 40 insertions(+), 80 deletions(-) diff --git a/crates/djls-dev/src/bin/djls-tmux.rs b/crates/djls-dev/src/bin/djls-tmux.rs index 11c4537..a645177 100644 --- a/crates/djls-dev/src/bin/djls-tmux.rs +++ b/crates/djls-dev/src/bin/djls-tmux.rs @@ -36,19 +36,23 @@ fn main() -> Result<()> { )?; // Split the right pane horizontally for server logs (50/50 split) + // Updated to handle dated log files properly writeln!( stdin, - "split-window -t djls-debug:0.1 -v -p 50 'tail -f /tmp/djls.log'" + r#"split-window -t djls-debug:0.1 -v -p 50 'bash -c "log=\$(ls -t /tmp/djls.log.* 2>/dev/null | head -1); if [ -z \"\$log\" ]; then echo \"Waiting for server logs...\"; while [ -z \"\$log\" ]; do sleep 1; log=\$(ls -t /tmp/djls.log.* 2>/dev/null | head -1); done; fi; echo \"Tailing \$log\"; tail -F \"\$log\""'"# )?; // Set pane titles writeln!(stdin, "select-pane -t djls-debug:0.0 -T 'Editor'")?; - writeln!(stdin, "select-pane -t djls-debug:0.1 -T 'LSP DevTools'")?; + writeln!(stdin, "select-pane -t djls-debug:0.1 -T 'LSP Messages'")?; writeln!(stdin, "select-pane -t djls-debug:0.2 -T 'Server Logs'")?; // Enable pane borders with titles at the top writeln!(stdin, "set -t djls-debug pane-border-status top")?; + // Enable mouse support for scrolling and pane interaction + writeln!(stdin, "set -t djls-debug mouse on")?; + // Add custom keybind to kill session (capital K) writeln!(stdin, "bind-key K kill-session")?; @@ -64,9 +68,9 @@ fn main() -> Result<()> { writeln!(stdin, "set -t djls-debug status-left '[#S] '")?; writeln!(stdin, "set -t djls-debug status-left-length 20")?; - // Right side: keybind hints - writeln!(stdin, "set -t djls-debug status-right ' C-b d: detach | C-b K: kill session | C-b x: kill pane | C-b z: zoom | C-b ?: help '")?; - writeln!(stdin, "set -t djls-debug status-right-length 90")?; + // Right side: keybind hints - updated to include mouse info + writeln!(stdin, "set -t djls-debug status-right ' Mouse: scroll/click | C-b d: detach | C-b K: kill | C-b x: kill pane | C-b z: zoom | C-b ?: help '")?; + writeln!(stdin, "set -t djls-debug status-right-length 120")?; // Center: window name writeln!(stdin, "set -t djls-debug status-justify centre")?; diff --git a/crates/djls-server/src/logging.rs b/crates/djls-server/src/logging.rs index e8e0f20..2949259 100644 --- a/crates/djls-server/src/logging.rs +++ b/crates/djls-server/src/logging.rs @@ -1,7 +1,7 @@ -//! Logging infrastructure bridging tracing events to LSP client messages. +//! Logging infrastructure for forwarding tracing events to LSP client messages. //! -//! This module provides both temporary dual-dispatch macros and the permanent -//! `LspLayer` implementation for forwarding tracing events to the LSP client. +//! This module provides the `LspLayer` implementation for forwarding tracing +//! events to the LSP client through the tracing infrastructure. //! //! ## `LspLayer` //! @@ -10,34 +10,25 @@ //! - ERROR, WARN, INFO, DEBUG → forwarded to LSP client //! - TRACE → kept server-side only (for performance) //! -//! ## Temporary Macros +//! ## Usage //! -//! These macros bridge the gap during our migration from `client::log_message` -//! to the tracing infrastructure. They ensure messages are sent to both systems -//! so we maintain LSP client visibility while building out tracing support. +//! Use standard tracing macros throughout the codebase: //! -//! Each macro supports two invocation patterns to handle the different APIs: -//! -//! 1. String literal: //! ```rust,ignore -//! log_info!("Server initialized"); -//! log_warn!("Configuration not found"); -//! log_error!("Failed to parse document"); +//! tracing::info!("Server initialized"); +//! tracing::warn!("Configuration not found"); +//! tracing::error!("Failed to parse document"); //! ``` //! -//! 2. Format string with arguments: +//! For formatted messages: //! ```rust,ignore -//! log_info!("Processing {} documents", count); -//! log_warn!("Timeout after {}ms for {}", ms, path); -//! log_error!("Failed to open {}: {}", file, err); +//! tracing::info!("Processing {} documents", count); +//! tracing::warn!("Timeout after {}ms for {}", ms, path); +//! tracing::error!("Failed to open {}: {}", file, err); //! ``` //! -//! The difference in the macro arms exists because of how each system works: -//! -//! - `client::log_message` expects a single string value -//! - `tracing` macros can handle format strings natively for structured logging -//! - For format strings, we format once for the client but pass the original -//! format string and args to tracing to preserve structured data +//! The `LspLayer` automatically handles forwarding appropriate log levels +//! to the LSP client while preserving structured logging data for file output. use std::sync::Arc; @@ -163,38 +154,4 @@ where guard } -#[macro_export] -macro_rules! log_info { - ($msg:literal) => { - $crate::client::log_message(tower_lsp_server::lsp_types::MessageType::INFO, $msg); - tracing::info!($msg); - }; - ($fmt:literal, $($arg:tt)*) => { - $crate::client::log_message(tower_lsp_server::lsp_types::MessageType::INFO, format!($fmt, $($arg)*)); - tracing::info!($fmt, $($arg)*); - }; -} -#[macro_export] -macro_rules! log_warn { - ($msg:literal) => { - $crate::client::log_message(tower_lsp_server::lsp_types::MessageType::WARNING, $msg); - tracing::warn!($msg); - }; - ($fmt:literal, $($arg:tt)*) => { - $crate::client::log_message(tower_lsp_server::lsp_types::MessageType::WARNING, format!($fmt, $($arg)*)); - tracing::warn!($fmt, $($arg)*); - }; -} - -#[macro_export] -macro_rules! log_error { - ($msg:literal) => { - $crate::client::log_message(tower_lsp_server::lsp_types::MessageType::ERROR, $msg); - tracing::error!($msg); - }; - ($fmt:literal, $($arg:tt)*) => { - $crate::client::log_message(tower_lsp_server::lsp_types::MessageType::ERROR, format!($fmt, $($arg)*)); - tracing::error!($fmt, $($arg)*); - }; -} diff --git a/crates/djls-server/src/server.rs b/crates/djls-server/src/server.rs index eff8caf..4450194 100644 --- a/crates/djls-server/src/server.rs +++ b/crates/djls-server/src/server.rs @@ -25,8 +25,7 @@ use tower_lsp_server::lsp_types::WorkspaceServerCapabilities; use tower_lsp_server::LanguageServer; use tracing_appender::non_blocking::WorkerGuard; -use crate::log_error; -use crate::log_info; + use crate::queue::Queue; use crate::session::Session; @@ -58,7 +57,7 @@ impl DjangoLanguageServer { if let Some(s) = &*session { f(s) } else { - log_error!("Attempted to access session before initialization"); + tracing::error!("Attempted to access session before initialization"); R::default() } } @@ -72,7 +71,7 @@ impl DjangoLanguageServer { if let Some(s) = &mut *session { f(s) } else { - log_error!("Attempted to access session before initialization"); + tracing::error!("Attempted to access session before initialization"); R::default() } } @@ -85,16 +84,16 @@ impl DjangoLanguageServer { let session_arc = Arc::clone(&self.session); if let Err(e) = self.queue.submit(async move { f(session_arc).await }).await { - log_error!("Failed to submit task: {}", e); + tracing::error!("Failed to submit task: {}", e); } else { - log_info!("Task submitted successfully"); + tracing::info!("Task submitted successfully"); } } } impl LanguageServer for DjangoLanguageServer { async fn initialize(&self, params: InitializeParams) -> LspResult { - log_info!("Initializing server..."); + tracing::info!("Initializing server..."); let session = Session::new(¶ms); @@ -142,7 +141,7 @@ impl LanguageServer for DjangoLanguageServer { #[allow(clippy::too_many_lines)] async fn initialized(&self, _params: InitializedParams) { - log_info!("Server received initialized notification."); + tracing::info!("Server received initialized notification."); self.with_session_task(|session_arc| async move { let project_path_and_venv = { @@ -162,13 +161,13 @@ impl LanguageServer for DjangoLanguageServer { }; if let Some((path_display, venv_path)) = project_path_and_venv { - log_info!( + tracing::info!( "Task: Starting initialization for project at: {}", path_display ); if let Some(ref path) = venv_path { - log_info!("Using virtual environment from config: {}", path); + tracing::info!("Using virtual environment from config: {}", path); } let init_result = { @@ -188,10 +187,10 @@ impl LanguageServer for DjangoLanguageServer { match init_result { Ok(()) => { - log_info!("Task: Successfully initialized project: {}", path_display); + tracing::info!("Task: Successfully initialized project: {}", path_display); } Err(e) => { - log_error!( + tracing::error!( "Task: Failed to initialize Django project at {}: {}", path_display, e @@ -205,7 +204,7 @@ impl LanguageServer for DjangoLanguageServer { } } } else { - log_info!("Task: No project instance found to initialize."); + tracing::info!("Task: No project instance found to initialize."); } Ok(()) }) @@ -217,7 +216,7 @@ impl LanguageServer for DjangoLanguageServer { } async fn did_open(&self, params: DidOpenTextDocumentParams) { - log_info!("Opened document: {:?}", params.text_document.uri); + tracing::info!("Opened document: {:?}", params.text_document.uri); self.with_session_mut(|session| { let db = session.db(); @@ -227,7 +226,7 @@ impl LanguageServer for DjangoLanguageServer { } async fn did_change(&self, params: DidChangeTextDocumentParams) { - log_info!("Changed document: {:?}", params.text_document.uri); + tracing::info!("Changed document: {:?}", params.text_document.uri); self.with_session_mut(|session| { let db = session.db(); @@ -237,7 +236,7 @@ impl LanguageServer for DjangoLanguageServer { } async fn did_close(&self, params: DidCloseTextDocumentParams) { - log_info!("Closed document: {:?}", params.text_document.uri); + tracing::info!("Closed document: {:?}", params.text_document.uri); self.with_session_mut(|session| { session.documents_mut().handle_did_close(¶ms); @@ -265,7 +264,7 @@ impl LanguageServer for DjangoLanguageServer { } async fn did_change_configuration(&self, _params: DidChangeConfigurationParams) { - log_info!("Configuration change detected. Reloading settings..."); + tracing::info!("Configuration change detected. Reloading settings..."); let project_path = self .with_session(|session| session.project().map(|p| p.path().to_path_buf())) @@ -277,7 +276,7 @@ impl LanguageServer for DjangoLanguageServer { session.set_settings(new_settings); } Err(e) => { - log_error!("Error loading settings: {}", e); + tracing::error!("Error loading settings: {}", e); } }) .await;