Finish basic logging setup with tracing

This commit is contained in:
Josh Thomas 2025-08-17 19:22:16 -05:00
parent bdb562ebf2
commit 0da3a45312
3 changed files with 40 additions and 80 deletions

View file

@ -36,19 +36,23 @@ fn main() -> Result<()> {
)?; )?;
// Split the right pane horizontally for server logs (50/50 split) // Split the right pane horizontally for server logs (50/50 split)
// Updated to handle dated log files properly
writeln!( writeln!(
stdin, 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 // Set pane titles
writeln!(stdin, "select-pane -t djls-debug:0.0 -T 'Editor'")?; 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'")?; writeln!(stdin, "select-pane -t djls-debug:0.2 -T 'Server Logs'")?;
// Enable pane borders with titles at the top // Enable pane borders with titles at the top
writeln!(stdin, "set -t djls-debug pane-border-status 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) // Add custom keybind to kill session (capital K)
writeln!(stdin, "bind-key K kill-session")?; 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 '[#S] '")?;
writeln!(stdin, "set -t djls-debug status-left-length 20")?; writeln!(stdin, "set -t djls-debug status-left-length 20")?;
// Right side: keybind hints // Right side: keybind hints - updated to include mouse info
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 ' 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 90")?; writeln!(stdin, "set -t djls-debug status-right-length 120")?;
// Center: window name // Center: window name
writeln!(stdin, "set -t djls-debug status-justify centre")?; writeln!(stdin, "set -t djls-debug status-justify centre")?;

View file

@ -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 //! This module provides the `LspLayer` implementation for forwarding tracing
//! `LspLayer` implementation for forwarding tracing events to the LSP client. //! events to the LSP client through the tracing infrastructure.
//! //!
//! ## `LspLayer` //! ## `LspLayer`
//! //!
@ -10,34 +10,25 @@
//! - ERROR, WARN, INFO, DEBUG → forwarded to LSP client //! - ERROR, WARN, INFO, DEBUG → forwarded to LSP client
//! - TRACE → kept server-side only (for performance) //! - TRACE → kept server-side only (for performance)
//! //!
//! ## Temporary Macros //! ## Usage
//! //!
//! These macros bridge the gap during our migration from `client::log_message` //! Use standard tracing macros throughout the codebase:
//! to the tracing infrastructure. They ensure messages are sent to both systems
//! so we maintain LSP client visibility while building out tracing support.
//! //!
//! Each macro supports two invocation patterns to handle the different APIs:
//!
//! 1. String literal:
//! ```rust,ignore //! ```rust,ignore
//! log_info!("Server initialized"); //! tracing::info!("Server initialized");
//! log_warn!("Configuration not found"); //! tracing::warn!("Configuration not found");
//! log_error!("Failed to parse document"); //! tracing::error!("Failed to parse document");
//! ``` //! ```
//! //!
//! 2. Format string with arguments: //! For formatted messages:
//! ```rust,ignore //! ```rust,ignore
//! log_info!("Processing {} documents", count); //! tracing::info!("Processing {} documents", count);
//! log_warn!("Timeout after {}ms for {}", ms, path); //! tracing::warn!("Timeout after {}ms for {}", ms, path);
//! log_error!("Failed to open {}: {}", file, err); //! tracing::error!("Failed to open {}: {}", file, err);
//! ``` //! ```
//! //!
//! The difference in the macro arms exists because of how each system works: //! The `LspLayer` automatically handles forwarding appropriate log levels
//! //! to the LSP client while preserving structured logging data for file output.
//! - `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
use std::sync::Arc; use std::sync::Arc;
@ -163,38 +154,4 @@ where
guard 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)*);
};
}

View file

@ -25,8 +25,7 @@ use tower_lsp_server::lsp_types::WorkspaceServerCapabilities;
use tower_lsp_server::LanguageServer; use tower_lsp_server::LanguageServer;
use tracing_appender::non_blocking::WorkerGuard; use tracing_appender::non_blocking::WorkerGuard;
use crate::log_error;
use crate::log_info;
use crate::queue::Queue; use crate::queue::Queue;
use crate::session::Session; use crate::session::Session;
@ -58,7 +57,7 @@ impl DjangoLanguageServer {
if let Some(s) = &*session { if let Some(s) = &*session {
f(s) f(s)
} else { } else {
log_error!("Attempted to access session before initialization"); tracing::error!("Attempted to access session before initialization");
R::default() R::default()
} }
} }
@ -72,7 +71,7 @@ impl DjangoLanguageServer {
if let Some(s) = &mut *session { if let Some(s) = &mut *session {
f(s) f(s)
} else { } else {
log_error!("Attempted to access session before initialization"); tracing::error!("Attempted to access session before initialization");
R::default() R::default()
} }
} }
@ -85,16 +84,16 @@ impl DjangoLanguageServer {
let session_arc = Arc::clone(&self.session); let session_arc = Arc::clone(&self.session);
if let Err(e) = self.queue.submit(async move { f(session_arc).await }).await { 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 { } else {
log_info!("Task submitted successfully"); tracing::info!("Task submitted successfully");
} }
} }
} }
impl LanguageServer for DjangoLanguageServer { impl LanguageServer for DjangoLanguageServer {
async fn initialize(&self, params: InitializeParams) -> LspResult<InitializeResult> { async fn initialize(&self, params: InitializeParams) -> LspResult<InitializeResult> {
log_info!("Initializing server..."); tracing::info!("Initializing server...");
let session = Session::new(&params); let session = Session::new(&params);
@ -142,7 +141,7 @@ impl LanguageServer for DjangoLanguageServer {
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
async fn initialized(&self, _params: InitializedParams) { 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 { self.with_session_task(|session_arc| async move {
let project_path_and_venv = { let project_path_and_venv = {
@ -162,13 +161,13 @@ impl LanguageServer for DjangoLanguageServer {
}; };
if let Some((path_display, venv_path)) = project_path_and_venv { if let Some((path_display, venv_path)) = project_path_and_venv {
log_info!( tracing::info!(
"Task: Starting initialization for project at: {}", "Task: Starting initialization for project at: {}",
path_display path_display
); );
if let Some(ref path) = venv_path { 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 = { let init_result = {
@ -188,10 +187,10 @@ impl LanguageServer for DjangoLanguageServer {
match init_result { match init_result {
Ok(()) => { Ok(()) => {
log_info!("Task: Successfully initialized project: {}", path_display); tracing::info!("Task: Successfully initialized project: {}", path_display);
} }
Err(e) => { Err(e) => {
log_error!( tracing::error!(
"Task: Failed to initialize Django project at {}: {}", "Task: Failed to initialize Django project at {}: {}",
path_display, path_display,
e e
@ -205,7 +204,7 @@ impl LanguageServer for DjangoLanguageServer {
} }
} }
} else { } else {
log_info!("Task: No project instance found to initialize."); tracing::info!("Task: No project instance found to initialize.");
} }
Ok(()) Ok(())
}) })
@ -217,7 +216,7 @@ impl LanguageServer for DjangoLanguageServer {
} }
async fn did_open(&self, params: DidOpenTextDocumentParams) { 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| { self.with_session_mut(|session| {
let db = session.db(); let db = session.db();
@ -227,7 +226,7 @@ impl LanguageServer for DjangoLanguageServer {
} }
async fn did_change(&self, params: DidChangeTextDocumentParams) { 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| { self.with_session_mut(|session| {
let db = session.db(); let db = session.db();
@ -237,7 +236,7 @@ impl LanguageServer for DjangoLanguageServer {
} }
async fn did_close(&self, params: DidCloseTextDocumentParams) { 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| { self.with_session_mut(|session| {
session.documents_mut().handle_did_close(&params); session.documents_mut().handle_did_close(&params);
@ -265,7 +264,7 @@ impl LanguageServer for DjangoLanguageServer {
} }
async fn did_change_configuration(&self, _params: DidChangeConfigurationParams) { 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 let project_path = self
.with_session(|session| session.project().map(|p| p.path().to_path_buf())) .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); session.set_settings(new_settings);
} }
Err(e) => { Err(e) => {
log_error!("Error loading settings: {}", e); tracing::error!("Error loading settings: {}", e);
} }
}) })
.await; .await;