-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support dynamic updates of the log level #139
Conversation
/// Log state managed by the LSP | ||
/// | ||
/// This state allows for dynamically updating the log level at runtime using [`reload`]. | ||
/// | ||
/// It works using an `RwLock` that's only ever locked by us inside `self.handle.reload()`, | ||
/// this seems to be fast enough even though atomics are checked at every log call site. | ||
/// Notably we only lock if the new log levels are actually different, which is important | ||
/// since we call [`reload`] when ANY configuration changes. | ||
pub(crate) struct LogState { | ||
handle: LogReloadHandle, | ||
|
||
/// The log level as provided by the client, before any extra processing is done. | ||
/// Used to check if an update is required. | ||
log_level: Option<LogLevel>, | ||
|
||
/// The dependency log levels as provided by the client, before any extra processing is done | ||
/// Used to check if an update is required. | ||
dependency_log_levels: Option<String>, | ||
} | ||
|
||
impl LogState { | ||
pub(crate) fn reload( | ||
&mut self, | ||
log_level: Option<LogLevel>, | ||
dependency_log_levels: Option<String>, | ||
) { | ||
if (self.log_level == log_level) && (self.dependency_log_levels == dependency_log_levels) { | ||
// Nothing changed | ||
return; | ||
} | ||
|
||
let (filter, message) = log_filter(log_level, dependency_log_levels.clone()); | ||
|
||
match self.handle.reload(filter) { | ||
Ok(()) => { | ||
// Update to match the new filter | ||
tracing::info!("{message}"); | ||
self.log_level = log_level; | ||
self.dependency_log_levels = dependency_log_levels; | ||
} | ||
Err(error) => { | ||
// Log and return without updating our internal log level | ||
tracing::error!("Failed to update log level: {error}"); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the core bit of it, pretty nice!
/// State used to dynamically update the log level | ||
pub(crate) log_state: Option<logging::LogState>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm excited to move to lsp-server because I think the startup procedure there will result in us creating GlobalState
/ LspState
after we've received InitializeParams
, meaning we will be able to get rid of Option<>
s here and in GlobalState
let (log_state, log_tx) = LogState::new(client.clone()); | ||
let (log_thread_state, log_tx) = LogThreadState::new(client.clone()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a rename so we can use LogState
for the bit that holds the reload handle
This thread state thing will also eventually go away in lsp-server world
Closes #134
dynamic.mov