Skip to content

Commit 1fdebc4

Browse files
authored
Clean up logging and make it work (#65)
1 parent bb74121 commit 1fdebc4

File tree

10 files changed

+126
-38
lines changed

10 files changed

+126
-38
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ integration_test: build
1717
# Build and install dev version into Zed's extension directory for testing
1818
install_ext: generate_word_list
1919
cd crates/codebook-lsp && cargo build --profile=fast-release
20-
cp -f target/release/codebook-lsp "${HOME}/Library/Application Support/Zed/extensions/work/codebook/"
20+
cp -f target/fast-release/codebook-lsp "${HOME}/Library/Application Support/Zed/extensions/work/codebook/"
2121

2222
uninstall_ext:
2323
rm -f "${HOME}/Library/Application Support/Zed/extensions/work/codebook/codebook-lsp"

crates/codebook-config/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl Default for CodebookConfig {
6060
impl CodebookConfig {
6161
/// Load configuration by searching for both global and project-specific configs
6262
pub fn load(current_dir: Option<&Path>) -> Result<Self, io::Error> {
63-
info!("Initializing CodebookConfig");
63+
debug!("Initializing CodebookConfig");
6464

6565
if let Some(current_dir) = current_dir {
6666
let current_dir = Path::new(current_dir);
@@ -81,7 +81,7 @@ impl CodebookConfig {
8181
if global_path.exists() {
8282
match Self::load_settings_from_file(&global_path) {
8383
Ok(global_settings) => {
84-
info!("Loaded global config from {}", global_path.display());
84+
debug!("Loaded global config from {}", global_path.display());
8585
config.global_config_path = Some(global_path.clone());
8686
*config.global_settings.write().unwrap() = Some(global_settings.clone());
8787
*config.effective_settings.write().unwrap() = global_settings;
@@ -109,7 +109,7 @@ impl CodebookConfig {
109109

110110
// Then try to find and load project config
111111
if let Some((project_path, project_settings)) = Self::find_project_config(start_dir)? {
112-
info!("Loaded project config from {}", project_path.display());
112+
debug!("Loaded project config from {}", project_path.display());
113113
config.project_config_path = Some(project_path.clone());
114114
*config.project_settings.write().unwrap() = project_settings.clone();
115115

@@ -440,7 +440,7 @@ impl CodebookConfig {
440440

441441
let content = toml::to_string_pretty(&*self.project_settings.read().unwrap())
442442
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
443-
log::info!(
443+
info!(
444444
"Saving project configuration to {}",
445445
project_config_path.display()
446446
);
@@ -456,7 +456,7 @@ impl CodebookConfig {
456456

457457
let content = toml::to_string_pretty(&*self.global_settings.read().unwrap())
458458
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
459-
log::info!(
459+
info!(
460460
"Saving project configuration to {}",
461461
global_config_path.display()
462462
);

crates/codebook-lsp/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ tower-lsp.workspace = true
99
serde.workspace = true
1010
serde_json.workspace = true
1111
fs2.workspace = true
12-
tokio.workspace = true
12+
tokio = { workspace = true, features = ["sync", "rt"] }
1313
env_logger.workspace = true
1414
log.workspace = true
1515
clap.workspace = true

crates/codebook-lsp/src/lsp.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use codebook::parser::TextRange;
77
use codebook::parser::WordLocation;
88
use codebook::parser::get_word_from_string;
99
use codebook::queries::LanguageType;
10+
use log::LevelFilter;
1011
use log::error;
1112
use serde_json::Value;
1213
use tokio::task;
@@ -19,6 +20,7 @@ use codebook_config::CodebookConfig;
1920
use log::{debug, info};
2021

2122
use crate::file_cache::TextDocumentCache;
23+
use crate::lsp_logger;
2224

2325
const SOURCE_NAME: &str = "Codebook";
2426

@@ -58,8 +60,24 @@ impl From<CodebookCommand> for String {
5860

5961
#[tower_lsp::async_trait]
6062
impl LanguageServer for Backend {
61-
async fn initialize(&self, _: InitializeParams) -> RpcResult<InitializeResult> {
62-
info!("Server initialized");
63+
async fn initialize(&self, params: InitializeParams) -> RpcResult<InitializeResult> {
64+
// Get log level from initialization options
65+
let log_level = params
66+
.initialization_options
67+
.as_ref()
68+
.and_then(|options| options.get("logLevel"))
69+
.and_then(|level| level.as_str())
70+
.map(|level| {
71+
if level == "debug" {
72+
LevelFilter::Debug
73+
} else {
74+
LevelFilter::Info
75+
}
76+
})
77+
.unwrap_or(LevelFilter::Info);
78+
lsp_logger::LspLogger::init(self.client.clone(), log_level)
79+
.expect("Failed to initialize LSP logger");
80+
info!("LSP logger initialized with log level: {}", log_level);
6381
Ok(InitializeResult {
6482
capabilities: ServerCapabilities {
6583
text_document_sync: Some(TextDocumentSyncCapability::Kind(
@@ -313,10 +331,10 @@ impl Backend {
313331
should_save = true;
314332
}
315333
Ok(false) => {
316-
log::info!("Word '{}' already exists in dictionary.", word);
334+
info!("Word '{}' already exists in dictionary.", word);
317335
}
318336
Err(e) => {
319-
log::error!("Failed to add word: {}", e);
337+
error!("Failed to add word: {}", e);
320338
}
321339
}
322340
}
@@ -330,10 +348,10 @@ impl Backend {
330348
should_save = true;
331349
}
332350
Ok(false) => {
333-
log::info!("Word '{}' already exists in global dictionary.", word);
351+
info!("Word '{}' already exists in global dictionary.", word);
334352
}
335353
Err(e) => {
336-
log::error!("Failed to add word: {}", e);
354+
error!("Failed to add word: {}", e);
337355
}
338356
}
339357
}
@@ -379,7 +397,7 @@ impl Backend {
379397
let did_reload = match self.config.reload() {
380398
Ok(did_reload) => did_reload,
381399
Err(e) => {
382-
log::error!("Failed to reload config: {}", e);
400+
error!("Failed to reload config: {}", e);
383401
false
384402
}
385403
};
@@ -399,7 +417,7 @@ impl Backend {
399417
};
400418
// Convert the file URI to a local file path.
401419
let file_path = doc.uri.to_file_path().unwrap_or_default();
402-
info!("Spell-checking file: {:?}", file_path);
420+
debug!("Spell-checking file: {:?}", file_path);
403421
// 1) Perform spell-check.
404422
let lang_type = doc
405423
.language_id
@@ -438,11 +456,11 @@ impl Backend {
438456
})
439457
.collect();
440458

441-
debug!("Diagnostics: {:?}", diagnostics);
459+
// debug!("Diagnostics: {:?}", diagnostics);
442460
// 3) Send the diagnostics to the client.
443461
self.client
444462
.publish_diagnostics(doc.uri, diagnostics, None)
445463
.await;
446-
debug!("Published diagnostics for: {:?}", file_path);
464+
// debug!("Published diagnostics for: {:?}", file_path);
447465
}
448466
}

crates/codebook-lsp/src/lsp_logger.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use log::{Level, LevelFilter, Log, Metadata, Record};
2+
use tokio::sync::mpsc::{self, Sender};
3+
use tower_lsp::Client;
4+
use tower_lsp::lsp_types::MessageType;
5+
6+
pub struct LspLogger {
7+
sender: Sender<LogMessage>,
8+
level: LevelFilter,
9+
}
10+
11+
struct LogMessage {
12+
level: Level,
13+
message: String,
14+
}
15+
16+
impl LspLogger {
17+
pub fn init(client_clone: Client, level: LevelFilter) -> Result<(), log::SetLoggerError> {
18+
// Create a channel for log messages
19+
let (sender, mut receiver) = mpsc::channel::<LogMessage>(100);
20+
21+
// Create a new logger
22+
let logger = Self { sender, level };
23+
24+
// Set up a background task to send logs to LSP client
25+
tokio::spawn(async move {
26+
while let Some(log_msg) = receiver.recv().await {
27+
let lsp_level = match log_msg.level {
28+
Level::Error => MessageType::ERROR,
29+
Level::Warn => MessageType::WARNING,
30+
Level::Info => MessageType::INFO,
31+
Level::Debug | Level::Trace => MessageType::LOG,
32+
};
33+
34+
// Ignore any errors from sending log messages
35+
let _ = client_clone.log_message(lsp_level, log_msg.message).await;
36+
}
37+
});
38+
39+
// Register our custom logger
40+
log::set_boxed_logger(Box::new(logger)).map(|()| log::set_max_level(level))
41+
}
42+
}
43+
44+
impl Log for LspLogger {
45+
fn enabled(&self, metadata: &Metadata) -> bool {
46+
metadata.level() <= self.level
47+
}
48+
49+
fn log(&self, record: &Record) {
50+
if !self.enabled(record.metadata()) {
51+
return;
52+
}
53+
54+
// Format the log message with module path
55+
let message = format!(
56+
"[{}] {}: {}",
57+
record.target(),
58+
record.level(),
59+
record.args()
60+
);
61+
62+
// Send log message to channel, ignore if channel is full
63+
let _ = self.sender.try_send(LogMessage {
64+
level: record.level(),
65+
message,
66+
});
67+
}
68+
69+
fn flush(&self) {}
70+
}

crates/codebook-lsp/src/main.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
mod file_cache;
22
mod lsp;
3+
mod lsp_logger;
4+
35
use clap::{Parser, Subcommand};
46
use codebook_config::CodebookConfig;
57
use log::info;
@@ -30,8 +32,6 @@ enum Commands {
3032

3133
#[tokio::main(flavor = "current_thread")]
3234
async fn main() {
33-
// Initialize logging so we can see server messages in the console.
34-
env_logger::init();
3535
let cli = Cli::parse();
3636

3737
let root = match cli.root.as_deref() {
@@ -53,13 +53,15 @@ async fn main() {
5353
}
5454

5555
async fn serve_lsp(root: &Path) {
56-
info!("Starting Codebook Language Server...");
56+
eprintln!("Starting Codebook Language Server..");
5757
let (stdin, stdout) = (tokio::io::stdin(), tokio::io::stdout());
5858
let inner_root = root.to_owned();
59+
5960
// Some blocking setup is done, so spawn_block!
6061
let (service, socket) =
6162
task::spawn_blocking(move || LspService::new(|client| Backend::new(client, &inner_root)))
6263
.await
6364
.unwrap();
65+
6466
Server::new(stdin, stdout, socket).serve(service).await;
6567
}

crates/codebook/src/dictionaries/dictionary.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use log::debug;
21
use lru::LruCache;
32

43
use std::{
@@ -77,10 +76,10 @@ impl Dictionary for HunspellDictionary {
7776
}
7877

7978
fn suggest(&self, word: &str) -> Vec<String> {
80-
debug!("Checking Cache: {:?}", word);
79+
// debug!("Checking Cache: {:?}", word);
8180
// First try to get from cache with write lock since get() needs to modify LRU order
8281
if let Some(suggestions) = self.suggestion_cache.write().unwrap().get_mut(word) {
83-
debug!("Cache hit for {:?}", word);
82+
// debug!("Cache hit for {:?}", word);
8483
return suggestions.clone();
8584
}
8685

crates/codebook/src/dictionaries/manager.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use std::{
66

77
use super::{
88
dictionary::{self, TextDictionary},
9-
repo::{get_repo, DictionaryRepo, HunspellRepo, TextRepo},
9+
repo::{DictionaryRepo, HunspellRepo, TextRepo, get_repo},
1010
};
1111
use dictionary::{Dictionary, HunspellDictionary};
1212
use downloader::Downloader;
13-
use log::info;
13+
use log::{debug, error};
1414

1515
pub struct DictionaryManager {
1616
dictionary_cache: Arc<RwLock<HashMap<String, Arc<dyn Dictionary>>>>,
@@ -33,7 +33,7 @@ impl DictionaryManager {
3333
let repo = match get_repo(id) {
3434
Some(r) => r,
3535
None => {
36-
info!("Failed to get repo for dictionary: {}", id);
36+
debug!("Failed to get repo for dictionary, skipping: {}", id);
3737
return None;
3838
}
3939
};
@@ -56,22 +56,22 @@ impl DictionaryManager {
5656
let aff_path = match self.downloader.get(&repo.aff_url) {
5757
Ok(path) => path,
5858
Err(e) => {
59-
info!("Error: {:?}", e);
59+
error!("Error: {:?}", e);
6060
return None;
6161
}
6262
};
6363
let dic_path = match self.downloader.get(&repo.dict_url) {
6464
Ok(path) => path,
6565
Err(e) => {
66-
info!("Error: {:?}", e);
66+
error!("Error: {:?}", e);
6767
return None;
6868
}
6969
};
7070
let dict =
7171
match HunspellDictionary::new(aff_path.to_str().unwrap(), dic_path.to_str().unwrap()) {
7272
Ok(dict) => dict,
7373
Err(e) => {
74-
info!("Error: {:?}", e);
74+
error!("Error: {:?}", e);
7575
return None;
7676
}
7777
};
@@ -85,7 +85,7 @@ impl DictionaryManager {
8585
let text_path = match self.downloader.get(&repo.url.unwrap()) {
8686
Ok(path) => path,
8787
Err(e) => {
88-
info!("Error: {:?}", e);
88+
error!("Error: {:?}", e);
8989
return None;
9090
}
9191
};

crates/codebook/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::sync::Arc;
99
use codebook_config::CodebookConfig;
1010
use dictionaries::{dictionary, manager::DictionaryManager};
1111
use dictionary::Dictionary;
12-
use log::info;
12+
use log::debug;
1313
use parser::WordLocation;
1414

1515
pub struct Codebook {
@@ -87,7 +87,7 @@ impl Codebook {
8787
};
8888
dictionary_ids.extend(DEFAULT_DICTIONARIES.iter().map(|f| f.to_string()));
8989
let mut dictionaries = Vec::with_capacity(dictionary_ids.len());
90-
info!("Checking text with dictionaries: {:?}", dictionary_ids);
90+
debug!("Checking text with dictionaries: {:?}", dictionary_ids);
9191
for dictionary_id in dictionary_ids {
9292
let dictionary = self.manager.get_dictionary(&dictionary_id);
9393
if let Some(d) = dictionary {

crates/codebook/src/parser.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::splitter::{self};
2-
use log::debug;
32

43
use crate::queries::{LanguageType, get_language_setting};
54
use std::collections::HashMap;
@@ -87,12 +86,12 @@ fn find_locations_code(
8786
let current_line = node_start.row as u32;
8887
let current_column = node_start.column as u32;
8988
let words = get_words_from_text(node_text);
90-
debug!("Found Capture: {node_text:?}");
91-
debug!("Words: {words:?}");
92-
debug!("Column: {current_column}");
93-
debug!("Line: {current_line}");
89+
// debug!("Found Capture: {node_text:?}");
90+
// debug!("Words: {words:?}");
91+
// debug!("Column: {current_column}");
92+
// debug!("Line: {current_line}");
9493
for (word_text, (text_start_char, text_line)) in words {
95-
debug!("Checking: {:?}", word_text);
94+
// debug!("Checking: {:?}", word_text);
9695
if !check_function(&word_text) {
9796
let offset = if text_line == 0 { current_column } else { 0 };
9897
let base_start_char = text_start_char + offset;

0 commit comments

Comments
 (0)