mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 22:31:47 +00:00
Use $/logTrace
for server trace logs in Zed and VS Code (#12564)
## Summary This pull request adds support for logging via `$/logTrace` RPC messages. It also enables that code path for when a client is Zed editor or VS Code (as there's no way for us to generically tell whether a client prefers `$/logTrace` over stderr. Related to: #12523 ## Test Plan I've built Ruff from this branch and tested it manually with Zed. --------- Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
This commit is contained in:
parent
381bd1ff4a
commit
fb9f566f56
2 changed files with 55 additions and 6 deletions
|
@ -90,6 +90,7 @@ impl Server {
|
||||||
.log_level
|
.log_level
|
||||||
.unwrap_or(crate::trace::LogLevel::Info),
|
.unwrap_or(crate::trace::LogLevel::Info),
|
||||||
global_settings.tracing.log_file.as_deref(),
|
global_settings.tracing.log_file.as_deref(),
|
||||||
|
init_params.client_info.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut workspace_for_url = |url: lsp_types::Url| {
|
let mut workspace_for_url = |url: lsp_types::Url| {
|
||||||
|
|
|
@ -14,16 +14,22 @@
|
||||||
//!
|
//!
|
||||||
//! Tracing will write to `stderr` by default, which should appear in the logs for most LSP clients.
|
//! Tracing will write to `stderr` by default, which should appear in the logs for most LSP clients.
|
||||||
//! A `logFile` path can also be specified in the settings, and output will be directed there instead.
|
//! A `logFile` path can also be specified in the settings, and output will be directed there instead.
|
||||||
use lsp_types::TraceValue;
|
use core::str;
|
||||||
|
use lsp_server::{Message, Notification};
|
||||||
|
use lsp_types::{
|
||||||
|
notification::{LogTrace, Notification as _},
|
||||||
|
ClientInfo, TraceValue,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
|
io::{Error as IoError, ErrorKind, Write},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, Mutex, OnceLock},
|
sync::{Arc, Mutex, OnceLock},
|
||||||
};
|
};
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
fmt::{time::Uptime, writer::BoxMakeWriter},
|
fmt::{time::Uptime, writer::BoxMakeWriter, MakeWriter},
|
||||||
layer::SubscriberExt,
|
layer::SubscriberExt,
|
||||||
Layer,
|
Layer,
|
||||||
};
|
};
|
||||||
|
@ -43,10 +49,43 @@ pub(crate) fn set_trace_value(trace_value: TraceValue) {
|
||||||
*global_trace_value = trace_value;
|
*global_trace_value = trace_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A tracing writer that uses LSPs logTrace method.
|
||||||
|
struct TraceLogWriter;
|
||||||
|
|
||||||
|
impl Write for TraceLogWriter {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
let message = str::from_utf8(buf).map_err(|e| IoError::new(ErrorKind::InvalidData, e))?;
|
||||||
|
LOGGING_SENDER
|
||||||
|
.get()
|
||||||
|
.expect("logging sender should be initialized at this point")
|
||||||
|
.send(Message::Notification(Notification {
|
||||||
|
method: LogTrace::METHOD.to_owned(),
|
||||||
|
params: serde_json::json!({
|
||||||
|
"message": message
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
.map_err(|e| IoError::new(ErrorKind::Other, e))?;
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MakeWriter<'a> for TraceLogWriter {
|
||||||
|
type Writer = Self;
|
||||||
|
|
||||||
|
fn make_writer(&'a self) -> Self::Writer {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn init_tracing(
|
pub(crate) fn init_tracing(
|
||||||
sender: ClientSender,
|
sender: ClientSender,
|
||||||
log_level: LogLevel,
|
log_level: LogLevel,
|
||||||
log_file: Option<&std::path::Path>,
|
log_file: Option<&std::path::Path>,
|
||||||
|
client: Option<&ClientInfo>,
|
||||||
) {
|
) {
|
||||||
LOGGING_SENDER
|
LOGGING_SENDER
|
||||||
.set(sender)
|
.set(sender)
|
||||||
|
@ -82,15 +121,24 @@ pub(crate) fn init_tracing(
|
||||||
.ok()
|
.ok()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let logger = match log_file {
|
||||||
|
Some(file) => BoxMakeWriter::new(Arc::new(file)),
|
||||||
|
None => {
|
||||||
|
if client.is_some_and(|client| {
|
||||||
|
client.name.starts_with("Zed") || client.name.starts_with("Visual Studio Code")
|
||||||
|
}) {
|
||||||
|
BoxMakeWriter::new(TraceLogWriter)
|
||||||
|
} else {
|
||||||
|
BoxMakeWriter::new(std::io::stderr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
let subscriber = tracing_subscriber::Registry::default().with(
|
let subscriber = tracing_subscriber::Registry::default().with(
|
||||||
tracing_subscriber::fmt::layer()
|
tracing_subscriber::fmt::layer()
|
||||||
.with_timer(Uptime::default())
|
.with_timer(Uptime::default())
|
||||||
.with_thread_names(true)
|
.with_thread_names(true)
|
||||||
.with_ansi(false)
|
.with_ansi(false)
|
||||||
.with_writer(match log_file {
|
.with_writer(logger)
|
||||||
Some(file) => BoxMakeWriter::new(Arc::new(file)),
|
|
||||||
None => BoxMakeWriter::new(std::io::stderr),
|
|
||||||
})
|
|
||||||
.with_filter(TraceLevelFilter)
|
.with_filter(TraceLevelFilter)
|
||||||
.with_filter(LogLevelFilter { filter: log_level }),
|
.with_filter(LogLevelFilter { filter: log_level }),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue