From 0baf6cadf751cae570a9a721e81c29e646754927 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 23 Aug 2026 22:48:00 +0300 Subject: [PATCH] Migrate to structured logging --- Cargo.lock | 164 +++++++++++++++++++++++++++++++- Cargo.toml | 2 + src/app.rs | 3 +- src/data_provider/card_stats.rs | 5 +- src/data_provider/import.rs | 7 +- src/data_provider/web_api.rs | 7 +- src/dictionary.rs | 7 +- src/dictionary_quiz.rs | 4 +- src/import.rs | 3 +- src/lang.rs | 5 +- src/main.rs | 1 + src/navigation.rs | 21 ++-- src/sync.rs | 3 +- 13 files changed, 202 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d9afd5..f86de79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,12 +152,56 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.101" @@ -728,6 +772,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -1068,6 +1118,37 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "deranged" version = "0.5.8" @@ -1215,6 +1296,29 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "env_filter" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -2292,6 +2396,12 @@ dependencies = [ "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itertools" version = "0.13.0" @@ -2314,10 +2424,12 @@ dependencies = [ "chrono", "criterion", "dirs", + "env_logger", "hashbrown 0.17.1", "hex", "iced", "iced_core", + "log", "mimalloc", "parking_lot", "rand", @@ -2334,6 +2446,42 @@ dependencies = [ "zstd", ] +[[package]] +name = "jiff" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + +[[package]] +name = "jiff-static" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "jni" version = "0.21.1" @@ -2584,9 +2732,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "lru" @@ -3309,6 +3457,12 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "oorandom" version = "11.1.5" @@ -5390,6 +5544,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.20.0" diff --git a/Cargo.toml b/Cargo.toml index 36e001a..06ba459 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ mimalloc = "0.1.52" hashbrown = "0.17.1" rayon = "1.12.0" parking_lot = "0.12.5" +env_logger = "0.11.11" +log = "0.4.34" [profile.super-release] inherits = "release" diff --git a/src/app.rs b/src/app.rs index d749e21..2dd41e8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,6 +4,7 @@ use iced::{keyboard, window, Subscription}; use iced_core::{Font, Size, Theme}; use iced_core::window::Position; use iced_core::window::settings::PlatformSpecific; +use log::info; use rusqlite::Connection; use crate::data_provider::card_sets::load_sets; use crate::data_provider::settings::get_setting; @@ -15,7 +16,7 @@ use crate::navigation::RootMessage::Keyboard; pub const USER_FONT: Font = Font::with_name("Noto Sans JP"); pub fn start() -> iced::Result { - println!("Welcome to JapLearn"); + info!("Welcome to JapLearn"); iced::application(ScreenState::boot, ScreenState::update, ScreenState::view) .window(window_settings()) .subscription(subscription) diff --git a/src/data_provider/card_stats.rs b/src/data_provider/card_stats.rs index a4d2ad1..5103608 100644 --- a/src/data_provider/card_stats.rs +++ b/src/data_provider/card_stats.rs @@ -1,6 +1,7 @@ use crate::lang::{CardStatistics, DeckSettings}; use rusqlite::{Connection, params}; use std::time::Instant; +use log::info; pub fn load_stats_of_deck(set: &DeckSettings, connection: &Connection) -> Vec { let mut stmt = connection @@ -58,7 +59,7 @@ pub fn add_stat_list(stats: &mut [CardStatistics], connection: &mut Connection) stats[index].id = id.into(); } - println!("Added {} cards for {:?}", stats.len(), time.elapsed()); + info!("Added {} cards for {:?}", stats.len(), time.elapsed()); } pub fn update_stat_score(stat: &CardStatistics, connection: &Connection) { @@ -70,7 +71,7 @@ pub fn update_stat_score(stat: &CardStatistics, connection: &Connection) { (&stat.score, &stat.last_open.timestamp(), &stat.id), ) .unwrap(); - println!("Updated stat: {}", time.elapsed().as_millis()); + info!("Updated stat: {}", time.elapsed().as_millis()); } pub fn delete_stats(stat: &[CardStatistics], connection: &Connection) { diff --git a/src/data_provider/import.rs b/src/data_provider/import.rs index 4b71653..a2116d5 100644 --- a/src/data_provider/import.rs +++ b/src/data_provider/import.rs @@ -1,5 +1,6 @@ use crate::notification::NotificationData; use hashbrown::HashMap; +use log::info; use rusqlite::Connection; use serde_json::Value; @@ -53,7 +54,7 @@ pub fn load_groups(connection: &Connection) -> Result Result Result) -> Vec { let mut decompressed = Vec::new(); let res = io::copy(&mut decoder, &mut decompressed); if let Err(e) = res { - println!("{}", e); + info!("{}", e); } decompressed } @@ -89,7 +90,7 @@ pub async fn first_sync() -> Result { .text() .await .map_err(|_| WebApiUnavailable)?; - println!("id: {}", id); + info!("id: {}", id); Ok(id) } @@ -97,7 +98,7 @@ pub async fn get_web_version(key: &str) -> Result { let id_url = format!("{API_URL}{key}/version"); let client = reqwest::Client::new(); let version = client.get(&id_url).send().await.map_err(|_| WebApiUnavailable)?.text().await.map_err(|_| WebApiUnavailable)?; - println!("version: {}", version); + info!("version: {}", version); Ok(version.parse::().unwrap_or_default()) } diff --git a/src/dictionary.rs b/src/dictionary.rs index c1fcae6..4d030b5 100644 --- a/src/dictionary.rs +++ b/src/dictionary.rs @@ -24,6 +24,7 @@ use std::ops::Add; use std::path::PathBuf; use std::sync::Arc; use std::time::{Duration, Instant}; +use log::info; use crate::app::AppState; #[derive(Clone)] @@ -438,8 +439,8 @@ impl DictionaryState { col = col.push(lazy_line); } - println!("Drawing {index} lines"); - println!("Words rendering time: {:?}", time.elapsed()); + info!("Drawing {index} lines"); + info!("Words rendering time: {:?}", time.elapsed()); scrollable(col).height(Fill).into() } @@ -554,7 +555,7 @@ impl DictionaryState { }) .collect(); - println!("Time {}", time.elapsed().as_micros()); + info!("Time {}", time.elapsed().as_micros()); } fn groups_panel(&self) -> iced::Element<'_, DictionaryMessage> { diff --git a/src/dictionary_quiz.rs b/src/dictionary_quiz.rs index c71a740..ef0a764 100644 --- a/src/dictionary_quiz.rs +++ b/src/dictionary_quiz.rs @@ -146,8 +146,8 @@ impl DictionaryQuizState { if !self.is_help { self.score.total += 1; } - if self.answer == self.correct - || split_with_coma(self.correct.as_str()).contains(&self.answer) + if self.answer.to_lowercase() == self.correct.to_lowercase() + || split_with_coma(self.correct.to_lowercase().as_str()).contains(&self.answer.to_lowercase()) { if !self.is_help { self.score.correct += 1; diff --git a/src/import.rs b/src/import.rs index 493c75a..b88c05c 100644 --- a/src/import.rs +++ b/src/import.rs @@ -24,6 +24,7 @@ use std::fs::{File, OpenOptions}; use std::io::BufReader; use std::path::PathBuf; use std::sync::Arc; +use log::info; use tokio::task::spawn_blocking; use zip::ZipArchive; use crate::app::AppState; @@ -426,7 +427,7 @@ impl ImportState { let skip_empty = self.skip_empty; let group = self.import_data.as_ref().unwrap().0[self.selected_index].clone(); let progress = self.progress.clone().unwrap(); - println!("{}", group.name); + info!("{}", group.name); Task::perform( async move { spawn_blocking(move || { diff --git a/src/lang.rs b/src/lang.rs index a193781..79ba890 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -22,6 +22,7 @@ use std::num::ParseIntError; use std::str::FromStr; use std::sync::Arc; use std::time::Instant; +use log::info; const MAX_HISTORY_LEN: usize = 20; const MAX_HISTORY_LEN_PART: f32 = 0.33; @@ -661,7 +662,7 @@ impl DeckSettings { let time = Instant::now(); let engine = Engine::new(); let ast = engine.compile(&self.filter); - println!("Compile time is {:?}", time.elapsed()); + info!("Compile time is {:?}", time.elapsed()); ast.is_ok() } pub fn get_word_list(&self, state: &AppState) -> Vec { @@ -705,7 +706,7 @@ impl DeckSettings { .map(|(index, _)| index) .collect(); - println!("Collecting available words is {:?}", time.elapsed()); + info!("Collecting available words is {:?}", time.elapsed()); list } else { diff --git a/src/main.rs b/src/main.rs index 359c5fd..b8bcf5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,5 +28,6 @@ static GLOBAL: MiMalloc = MiMalloc; fn main() -> iced::Result { + env_logger::init(); start() } diff --git a/src/navigation.rs b/src/navigation.rs index b217691..cb5818a 100644 --- a/src/navigation.rs +++ b/src/navigation.rs @@ -33,6 +33,7 @@ use parking_lot::Mutex; use rusqlite::Connection; use std::sync::Arc; use std::time::Instant; +use log::info; impl Default for ScreenState { fn default() -> Self { @@ -95,9 +96,9 @@ pub struct ScreenState { impl ScreenState { pub fn boot() -> (ScreenState, Task) { - println!("Booting"); + info!("Booting"); create_db(); - println!("Db created"); + info!("Db created"); let state = ScreenState::default(); let reading_additional_task = Task::perform(Self::load_additional_data(), |data| data); @@ -128,7 +129,7 @@ impl ScreenState { } drop(state_guard); - println!("Boot finished"); + info!("Boot finished"); (state, final_task) } @@ -161,9 +162,9 @@ impl ScreenState { async fn load_web_backup(string: String) -> Result { let local = get_local_version().await; let web = get_web_version(string.as_str()).await?; - println!("{} {}", local, web); + info!("{} {}", local, web); if web > local { - println!("Web version is newer than local version"); + info!("Web version is newer than local version"); load_data(string, true).await?; set_local_version(web).await; } else { @@ -173,7 +174,7 @@ impl ScreenState { } pub fn update(&mut self, message: RootMessage) -> Task { - println!("Updating"); + info!("Updating"); let time = Instant::now(); if let Keyboard(e) = message { return self.handle_keyboard(e); @@ -185,7 +186,7 @@ impl ScreenState { } if let UpdateData = message { - println!("Loading data"); + info!("Loading data"); let mut state = self.app_state.lock(); if cfg!(windows) { state.connection = Connection::open_in_memory().unwrap(); @@ -228,7 +229,7 @@ impl ScreenState { Import ); } - println!("Update took {:?}", time.elapsed()); + info!("Update took {:?}", time.elapsed()); task.0 } @@ -255,7 +256,7 @@ impl ScreenState { pub fn view(&self) -> Element<'_, RootMessage> { - println!("View update"); + info!("View update"); let time = Instant::now(); let view = view_navigation!( self.stack, @@ -276,7 +277,7 @@ impl ScreenState { let notifications = self.notification_manager.draw().map(RootMessage::Notification); - println!("View took {:?}", time.elapsed()); + info!("View took {:?}", time.elapsed()); stack![view, notifications].width(Fill).height(Fill).into() } diff --git a/src/sync.rs b/src/sync.rs index f32952a..45c87f1 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -11,6 +11,7 @@ use iced::{Center, Element, Fill, Font, Length, Task}; use parking_lot::Mutex; use std::sync::Arc; use std::time::Duration; +use log::error; use crate::app::{fill_state, AppState}; use crate::notification::{NotificationRequest, NotificationData}; @@ -246,7 +247,7 @@ impl SyncState { .connection .query_row("PRAGMA wal_checkpoint(TRUNCATE)", [], |_| Ok(())) .unwrap_or_else(|e| { - eprintln!("Ошибка при checkpoint WAL: {e}"); + error!("Ошибка при checkpoint WAL: {e}"); }); } }