Improve logging controls

This commit is contained in:
2026-01-12 02:25:28 +09:00
parent 764a6349ef
commit c8c90f0641
3 changed files with 396 additions and 517 deletions

View File

@@ -1,21 +1,164 @@
//! Core TauClock backend that wires plugins and exposes Rust commands.
//!
//! The UI currently uses only frontend logic, but the scaffold is documented
//! so contributors know where to extend native capabilities (timers, IPC, etc).
mod state;
use log::LevelFilter;
use state::{AppState, FrontendState};
use std::{path::PathBuf, str::FromStr};
use tauri_plugin_log::{Target, TargetKind};
/// Example command exposed to the frontend. Extend or replace as needed.
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
fn get_state(app_state: tauri::State<AppState>) -> FrontendState {
log::debug!("get_state invoked");
app_state.snapshot()
}
#[tauri::command]
fn tick(app_state: tauri::State<AppState>) -> FrontendState {
log::trace!("tick invoked");
app_state.tick()
}
#[tauri::command]
fn create_alarm(
time: String,
label: Option<String>,
app_state: tauri::State<AppState>,
) -> FrontendState {
let has_label = label
.as_ref()
.map(|value| !value.trim().is_empty())
.unwrap_or(false);
log::info!(
"create_alarm invoked (time={time}, has_label={has_label})",
time = time,
has_label = has_label
);
app_state.create_alarm(time, label)
}
#[tauri::command]
fn toggle_alarm(id: String, app_state: tauri::State<AppState>) -> FrontendState {
log::info!("toggle_alarm invoked (id={id})", id = id);
app_state.toggle_alarm(id)
}
#[tauri::command]
fn delete_alarm(id: String, app_state: tauri::State<AppState>) -> FrontendState {
log::info!("delete_alarm invoked (id={id})", id = id);
app_state.delete_alarm(id)
}
#[tauri::command]
fn toggle_timer(
input: Option<String>,
force_parse: bool,
app_state: tauri::State<AppState>,
) -> FrontendState {
let has_input = input
.as_ref()
.map(|value| !value.trim().is_empty())
.unwrap_or(false);
log::info!(
"toggle_timer invoked (force_parse={force_parse}, has_input={has_input})",
force_parse = force_parse,
has_input = has_input
);
app_state.toggle_timer(input, force_parse)
}
#[tauri::command]
fn reset_timer(app_state: tauri::State<AppState>) -> FrontendState {
log::debug!("reset_timer invoked");
app_state.reset_timer()
}
#[tauri::command]
fn toggle_stopwatch(app_state: tauri::State<AppState>) -> FrontendState {
log::info!("toggle_stopwatch invoked");
app_state.toggle_stopwatch()
}
#[tauri::command]
fn add_lap(app_state: tauri::State<AppState>) -> FrontendState {
log::debug!("add_lap invoked");
app_state.add_lap()
}
#[tauri::command]
fn reset_stopwatch(app_state: tauri::State<AppState>) -> FrontendState {
log::debug!("reset_stopwatch invoked");
app_state.reset_stopwatch()
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
/// Build the Tauri application, attach plugins, and start the runtime loop.
pub fn run() {
let context = tauri::generate_context!();
let storage_path = resolve_storage_path(context.config());
let storage_display = storage_path.display().to_string();
let app_state = AppState::new(storage_path);
let log_level = resolve_log_level();
let log_plugin = tauri_plugin_log::Builder::new()
.targets([
Target::new(TargetKind::Stdout),
Target::new(TargetKind::Webview),
Target::new(TargetKind::LogDir { file_name: None }),
])
.level(log_level)
.build();
tauri::Builder::default()
.plugin(tauri_plugin_log::Builder::new().build())
.manage(app_state)
.plugin(log_plugin)
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.invoke_handler(tauri::generate_handler![
get_state,
tick,
create_alarm,
toggle_alarm,
delete_alarm,
toggle_timer,
reset_timer,
toggle_stopwatch,
add_lap,
reset_stopwatch
])
.setup(move |_| {
log::info!("Tauclock backend ready; storage_path={}", storage_display);
log::debug!("Backend log level set to {:?}", log_level);
Ok(())
})
.run(context)
.expect("error while running tauri application");
}
fn resolve_log_level() -> LevelFilter {
let env_value = std::env::var("TAUCLOCK_LOG_LEVEL")
.or_else(|_| std::env::var("TAUCLOCK_LOG"))
.ok();
if let Some(raw) = env_value {
if let Ok(level) = LevelFilter::from_str(raw.trim()) {
return level;
} else {
eprintln!(
"[tauclock] Invalid TAUCLOCK_LOG_LEVEL '{}', falling back to default",
raw
);
}
}
if cfg!(debug_assertions) {
LevelFilter::Debug
} else {
LevelFilter::Info
}
}
fn resolve_storage_path(config: &tauri::Config) -> PathBuf {
let mut dir = dirs::data_dir()
.unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
let identifier = if config.identifier.is_empty() {
"tauclock".to_string()
} else {
config.identifier.clone()
};
dir.push(identifier);
dir.join("alarms.json")
}