codebook_lsp/
lsp_logger.rs1use log::{Level, LevelFilter, Log, Metadata, Record};
2use std::collections::VecDeque;
3use std::io::{self, IsTerminal};
4use std::sync::{Mutex, OnceLock};
5use tokio::sync::mpsc::{self, Sender};
6use tower_lsp::Client;
7use tower_lsp::lsp_types::MessageType;
8
9const BUFFER_SIZE: usize = 1000;
10
11pub struct LspLogger {
12 sender: Mutex<Option<Sender<LogMessage>>>,
13 level: Mutex<LevelFilter>,
14 buffer: Mutex<VecDeque<LogMessage>>,
16 stderr_is_tty: bool,
17}
18
19struct LogMessage {
20 level: Level,
21 message: String,
22}
23
24impl LogMessage {
25 fn clone(&self) -> Self {
26 LogMessage {
27 level: self.level,
28 message: self.message.clone(),
29 }
30 }
31}
32
33static LOGGER: OnceLock<&'static LspLogger> = OnceLock::new();
35
36impl LspLogger {
37 pub fn init_early(level: LevelFilter) -> Result<(), log::SetLoggerError> {
40 let stderr_is_tty = io::stderr().is_terminal();
41 let logger = Box::leak(Box::new(LspLogger {
42 sender: Mutex::new(None),
43 level: Mutex::new(level),
44 buffer: Mutex::new(VecDeque::with_capacity(BUFFER_SIZE)),
45 stderr_is_tty,
46 }));
47
48 let _ = LOGGER.set(logger);
50
51 let logger = LOGGER.get().expect("Logger should be initialized");
53 log::set_logger(*logger).map(|()| log::set_max_level(level))
54 }
55
56 pub fn attach_client(client: Client, level: LevelFilter) {
58 if let Some(logger) = LOGGER.get() {
59 *logger.level.lock().unwrap() = level;
61 log::set_max_level(level);
62
63 let (sender, mut receiver) = mpsc::channel::<LogMessage>(BUFFER_SIZE);
65
66 let buffered_messages: Vec<LogMessage> = {
68 let buffer = logger.buffer.lock().unwrap();
69 buffer.iter().map(|msg| msg.clone()).collect()
70 };
71
72 *logger.sender.lock().unwrap() = Some(sender.clone());
74
75 let client_clone = client.clone();
77 tokio::spawn(async move {
78 while let Some(log_msg) = receiver.recv().await {
79 let lsp_level = match log_msg.level {
80 Level::Error => MessageType::ERROR,
81 Level::Warn => MessageType::WARNING,
82 Level::Info => MessageType::INFO,
83 Level::Debug | Level::Trace => MessageType::LOG,
84 };
85
86 let _ = client_clone.log_message(lsp_level, log_msg.message).await;
88 }
89 });
90
91 for msg in buffered_messages {
93 let _ = sender.try_send(msg);
95 }
96
97 logger.buffer.lock().unwrap().clear();
99 }
100 }
101}
102
103impl Log for LspLogger {
104 fn enabled(&self, metadata: &Metadata) -> bool {
105 metadata.level() <= *self.level.lock().unwrap()
106 }
107
108 fn log(&self, record: &Record) {
109 if !self.enabled(record.metadata()) {
110 return;
111 }
112
113 let message = format!(
115 "[{}] {}: {}",
116 record.target(),
117 record.level(),
118 record.args()
119 );
120
121 let log_msg = LogMessage {
122 level: record.level(),
123 message: message.clone(),
124 };
125
126 let sender_guard = self.sender.lock().unwrap();
128 if let Some(sender) = sender_guard.as_ref() {
129 let _ = sender.try_send(log_msg);
131 } else {
132 if self.stderr_is_tty || matches!(log_msg.level, Level::Warn | Level::Error) {
134 eprintln!("{}", message);
135 }
136
137 drop(sender_guard);
139
140 let mut buffer = self.buffer.lock().unwrap();
142 if buffer.len() >= BUFFER_SIZE {
143 buffer.pop_front();
145 }
146 buffer.push_back(log_msg);
147 }
148 }
149
150 fn flush(&self) {}
151}