1
Fork 0
mirror of https://github.com/RGBCube/superfreq synced 2025-07-27 17:07:44 +00:00

core: switch to log for proper logging

This commit is contained in:
NotAShelf 2025-05-14 02:57:22 +03:00
parent 02a11eb9db
commit b7f374c32c
No known key found for this signature in database
GPG key ID: 29D95B64378DB4BF
5 changed files with 210 additions and 166 deletions

View file

@ -4,6 +4,7 @@ use crate::conflict;
use crate::core::SystemReport;
use crate::engine;
use crate::monitor;
use log::{LevelFilter, debug, error, info, warn};
use std::fs::File;
use std::io::Write;
use std::sync::Arc;
@ -19,20 +20,23 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
config.daemon.log_level
};
log_message(
&effective_log_level,
LogLevel::Info,
"Starting superfreq daemon...",
);
// Get the appropriate level filter
let level_filter = match effective_log_level {
LogLevel::Error => LevelFilter::Error,
LogLevel::Warning => LevelFilter::Warn,
LogLevel::Info => LevelFilter::Info,
LogLevel::Debug => LevelFilter::Debug,
};
// Update the log level filter if needed, without re-initializing the logger
log::set_max_level(level_filter);
info!("Starting superfreq daemon...");
// Check for conflicts with other power management services
let conflicts = conflict::detect_conflicts();
if conflicts.has_conflicts() {
log_message(
&effective_log_level,
LogLevel::Warning,
&conflicts.get_conflict_message(),
);
warn!("{}", conflicts.get_conflict_message());
}
// Create a flag that will be set to true when a signal is received
@ -41,27 +45,19 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
// Set up signal handlers
ctrlc::set_handler(move || {
println!("Received shutdown signal, exiting...");
info!("Received shutdown signal, exiting...");
r.store(false, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
log_message(
&effective_log_level,
LogLevel::Info,
&format!(
"Daemon initialized with poll interval: {}s",
config.daemon.poll_interval_sec
),
info!(
"Daemon initialized with poll interval: {}s",
config.daemon.poll_interval_sec
);
// Set up stats file if configured
if let Some(stats_path) = &config.daemon.stats_file_path {
log_message(
&effective_log_level,
LogLevel::Info,
&format!("Stats will be written to: {stats_path}"),
);
info!("Stats will be written to: {stats_path}");
}
// Initialize config file watcher if a path is available
@ -80,28 +76,16 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
let mut config_watcher = if let Some(path) = config_file_path {
match ConfigWatcher::new(&path) {
Ok(watcher) => {
log_message(
&effective_log_level,
LogLevel::Info,
&format!("Watching config file: {path}"),
);
info!("Watching config file: {path}");
Some(watcher)
}
Err(e) => {
log_message(
&effective_log_level,
LogLevel::Warning,
&format!("Failed to initialize config file watcher: {e}"),
);
warn!("Failed to initialize config file watcher: {e}");
None
}
}
} else {
log_message(
&effective_log_level,
LogLevel::Warning,
"No config file found to watch for changes.",
);
warn!("No config file found to watch for changes.");
None
};
@ -119,11 +103,7 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
if let Some(config_result) = watcher.check_for_changes() {
match config_result {
Ok(new_config) => {
log_message(
&effective_log_level,
LogLevel::Info,
"Config file changed, updating configuration",
);
info!("Config file changed, updating configuration");
config = new_config;
// Reset polling interval after config change
current_poll_interval = config.daemon.poll_interval_sec;
@ -131,11 +111,7 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
last_settings_change = Instant::now();
}
Err(e) => {
log_message(
&effective_log_level,
LogLevel::Error,
&format!("Error loading new configuration: {e}"),
);
error!("Error loading new configuration: {e}");
// Continue with existing config
}
}
@ -144,11 +120,7 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
match monitor::collect_system_report(&config) {
Ok(report) => {
log_message(
&effective_log_level,
LogLevel::Debug,
"Collected system report, applying settings...",
);
debug!("Collected system report, applying settings...");
// Determine current system state
let current_state = determine_system_state(&report);
@ -156,40 +128,24 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
// Update the stats file if configured
if let Some(stats_path) = &config.daemon.stats_file_path {
if let Err(e) = write_stats_file(stats_path, &report) {
log_message(
&effective_log_level,
LogLevel::Error,
&format!("Failed to write stats file: {e}"),
);
error!("Failed to write stats file: {e}");
}
}
match engine::determine_and_apply_settings(&report, &config, None) {
Ok(()) => {
log_message(
&effective_log_level,
LogLevel::Debug,
"Successfully applied system settings",
);
debug!("Successfully applied system settings");
// If system state changed or settings were applied differently, record the time
if current_state != last_system_state {
last_settings_change = Instant::now();
last_system_state = current_state.clone();
log_message(
&effective_log_level,
LogLevel::Info,
&format!("System state changed to: {current_state:?}"),
);
info!("System state changed to: {current_state:?}");
}
}
Err(e) => {
log_message(
&effective_log_level,
LogLevel::Error,
&format!("Error applying system settings: {e}"),
);
error!("Error applying system settings: {e}");
}
}
@ -202,25 +158,13 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
current_poll_interval =
(current_poll_interval * 2).min(config.daemon.max_poll_interval_sec);
log_message(
&effective_log_level,
LogLevel::Debug,
&format!(
"Adaptive polling: increasing interval to {current_poll_interval}s"
),
);
debug!("Adaptive polling: increasing interval to {current_poll_interval}s");
} else if time_since_change < 10 {
// If we've had recent changes, decrease the interval (down to min)
current_poll_interval =
(current_poll_interval / 2).max(config.daemon.min_poll_interval_sec);
log_message(
&effective_log_level,
LogLevel::Debug,
&format!(
"Adaptive polling: decreasing interval to {current_poll_interval}s"
),
);
debug!("Adaptive polling: decreasing interval to {current_poll_interval}s");
}
} else {
// If not adaptive, use the configured poll interval
@ -236,19 +180,11 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
current_poll_interval = (current_poll_interval * battery_multiplier)
.min(config.daemon.max_poll_interval_sec);
log_message(
&effective_log_level,
LogLevel::Debug,
"On battery power, increasing poll interval to save energy",
);
debug!("On battery power, increasing poll interval to save energy");
}
}
Err(e) => {
log_message(
&effective_log_level,
LogLevel::Error,
&format!("Error collecting system report: {e}"),
);
error!("Error collecting system report: {e}");
}
}
@ -257,39 +193,22 @@ pub fn run_daemon(mut config: AppConfig, verbose: bool) -> Result<(), Box<dyn st
let poll_duration = Duration::from_secs(current_poll_interval);
if elapsed < poll_duration {
let sleep_time = poll_duration - elapsed;
log_message(
&effective_log_level,
LogLevel::Debug,
&format!("Sleeping for {}s until next cycle", sleep_time.as_secs()),
);
debug!("Sleeping for {}s until next cycle", sleep_time.as_secs());
std::thread::sleep(sleep_time);
}
}
log_message(&effective_log_level, LogLevel::Info, "Daemon stopped");
info!("Daemon stopped");
Ok(())
}
/// Log a message based on the current log level
fn log_message(effective_level: &LogLevel, msg_level: LogLevel, message: &str) {
// Only log messages at or above the effective log level
let should_log = match effective_level {
LogLevel::Error => matches!(msg_level, LogLevel::Error),
LogLevel::Warning => matches!(msg_level, LogLevel::Error | LogLevel::Warning),
LogLevel::Info => matches!(
msg_level,
LogLevel::Error | LogLevel::Warning | LogLevel::Info
),
LogLevel::Debug => true,
};
if should_log {
match msg_level {
LogLevel::Error => eprintln!("ERROR: {message}"),
LogLevel::Warning => eprintln!("WARNING: {message}"),
LogLevel::Info => println!("INFO: {message}"),
LogLevel::Debug => println!("DEBUG: {message}"),
}
/// Initialize the logger with the appropriate level
const fn get_log_level_filter(log_level: LogLevel) -> LevelFilter {
match log_level {
LogLevel::Error => LevelFilter::Error,
LogLevel::Warning => LevelFilter::Warn,
LogLevel::Info => LevelFilter::Info,
LogLevel::Debug => LevelFilter::Debug,
}
}

View file

@ -2,6 +2,7 @@ use crate::config::{AppConfig, ProfileConfig};
use crate::core::{OperationalMode, SystemReport, TurboSetting};
use crate::cpu::{self};
use crate::util::error::EngineError;
use log::{debug, info};
/// Determines the appropriate CPU profile based on power status or forced mode,
/// and applies the settings using functions from the `cpu` module.
@ -12,8 +13,8 @@ pub fn determine_and_apply_settings(
) -> Result<(), EngineError> {
// First, check if there's a governor override set
if let Some(override_governor) = cpu::get_governor_override() {
println!(
"Engine: Governor override is active: '{}'. Setting governor.",
info!(
"Governor override is active: '{}'. Setting governor.",
override_governor.trim()
);
cpu::set_governor(override_governor.trim(), None)?;
@ -24,11 +25,11 @@ pub fn determine_and_apply_settings(
if let Some(mode) = force_mode {
match mode {
OperationalMode::Powersave => {
println!("Engine: Forced Powersave mode selected. Applying 'battery' profile.");
info!("Forced Powersave mode selected. Applying 'battery' profile.");
selected_profile_config = &config.battery;
}
OperationalMode::Performance => {
println!("Engine: Forced Performance mode selected. Applying 'charger' profile.");
info!("Forced Performance mode selected. Applying 'charger' profile.");
selected_profile_config = &config.charger;
}
}
@ -41,28 +42,25 @@ pub fn determine_and_apply_settings(
report.batteries.is_empty() || report.batteries.first().is_some_and(|b| b.ac_connected);
if on_ac_power {
println!("Engine: On AC power, selecting Charger profile.");
info!("On AC power, selecting Charger profile.");
selected_profile_config = &config.charger;
} else {
println!("Engine: On Battery power, selecting Battery profile.");
info!("On Battery power, selecting Battery profile.");
selected_profile_config = &config.battery;
}
}
// Apply settings from selected_profile_config
// TODO: The println! statements are for temporary debugging/logging
// and we'd like to replace them with proper logging in the future.
if let Some(governor) = &selected_profile_config.governor {
println!("Engine: Setting governor to '{governor}'");
info!("Setting governor to '{governor}'");
cpu::set_governor(governor, None)?;
}
if let Some(turbo_setting) = selected_profile_config.turbo {
println!("Engine: Setting turbo to '{turbo_setting:?}'");
info!("Setting turbo to '{turbo_setting:?}'");
match turbo_setting {
TurboSetting::Auto => {
println!("Engine: Managing turbo in auto mode based on system conditions");
debug!("Managing turbo in auto mode based on system conditions");
manage_auto_turbo(report, selected_profile_config)?;
}
_ => cpu::set_turbo(turbo_setting)?,
@ -70,31 +68,31 @@ pub fn determine_and_apply_settings(
}
if let Some(epp) = &selected_profile_config.epp {
println!("Engine: Setting EPP to '{epp}'");
info!("Setting EPP to '{epp}'");
cpu::set_epp(epp, None)?;
}
if let Some(epb) = &selected_profile_config.epb {
println!("Engine: Setting EPB to '{epb}'");
info!("Setting EPB to '{epb}'");
cpu::set_epb(epb, None)?;
}
if let Some(min_freq) = selected_profile_config.min_freq_mhz {
println!("Engine: Setting min frequency to '{min_freq} MHz'");
info!("Setting min frequency to '{min_freq} MHz'");
cpu::set_min_frequency(min_freq, None)?;
}
if let Some(max_freq) = selected_profile_config.max_freq_mhz {
println!("Engine: Setting max frequency to '{max_freq} MHz'");
info!("Setting max frequency to '{max_freq} MHz'");
cpu::set_max_frequency(max_freq, None)?;
}
if let Some(profile) = &selected_profile_config.platform_profile {
println!("Engine: Setting platform profile to '{profile}'");
info!("Setting platform profile to '{profile}'");
cpu::set_platform_profile(profile)?;
}
println!("Engine: Profile settings applied successfully.");
debug!("Profile settings applied successfully.");
Ok(())
}
@ -140,24 +138,24 @@ fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<()
let enable_turbo = match (cpu_temp, avg_cpu_usage) {
// If temperature is too high, disable turbo regardless of load
(Some(temp), _) if temp >= turbo_settings.temp_threshold_high => {
println!(
"Engine: Auto Turbo: Disabled due to high temperature ({:.1}°C >= {:.1}°C)",
info!(
"Auto Turbo: Disabled due to high temperature ({:.1}°C >= {:.1}°C)",
temp, turbo_settings.temp_threshold_high
);
false
}
// If load is high enough, enable turbo (unless temp already caused it to disable)
(_, Some(usage)) if usage >= turbo_settings.load_threshold_high => {
println!(
"Engine: Auto Turbo: Enabled due to high CPU load ({:.1}% >= {:.1}%)",
info!(
"Auto Turbo: Enabled due to high CPU load ({:.1}% >= {:.1}%)",
usage, turbo_settings.load_threshold_high
);
true
}
// If load is low, disable turbo
(_, Some(usage)) if usage <= turbo_settings.load_threshold_low => {
println!(
"Engine: Auto Turbo: Disabled due to low CPU load ({:.1}% <= {:.1}%)",
info!(
"Auto Turbo: Disabled due to low CPU load ({:.1}% <= {:.1}%)",
usage, turbo_settings.load_threshold_low
);
false
@ -165,7 +163,7 @@ fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<()
// In intermediate load scenarios or if we can't determine, leave turbo in current state
// For now, we'll disable it as a safe default
_ => {
println!("Engine: Auto Turbo: Disabled (default for indeterminate state)");
info!("Auto Turbo: Disabled (default for indeterminate state)");
false
}
};
@ -179,8 +177,8 @@ fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<()
match cpu::set_turbo(turbo_setting) {
Ok(()) => {
println!(
"Engine: Auto Turbo: Successfully set turbo to {}",
debug!(
"Auto Turbo: Successfully set turbo to {}",
if enable_turbo { "enabled" } else { "disabled" }
);
Ok(())

View file

@ -12,6 +12,9 @@ use crate::config::AppConfig;
use crate::core::{GovernorOverrideMode, TurboSetting};
use crate::util::error::ControlError;
use clap::Parser;
use env_logger::Builder;
use log::{debug, error, info};
use std::sync::Once;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
@ -77,6 +80,9 @@ enum Commands {
}
fn main() {
// Initialize logger once for the entire application
init_logger();
let cli = Cli::parse();
// Load configuration first, as it might be needed by the monitor module
@ -84,7 +90,7 @@ fn main() {
let config = match config::load_config() {
Ok(cfg) => cfg,
Err(e) => {
eprintln!("Error loading configuration: {e}. Using default values.");
error!("Error loading configuration: {e}. Using default values.");
// Proceed with default config if loading fails, as per previous steps
AppConfig::default()
}
@ -100,12 +106,12 @@ fn main() {
let total_width = title_len + 8; // 8 is for padding (4 on each side)
let separator = "".repeat(total_width);
println!("\n{}", separator);
println!("\n{separator}");
// Calculate centering
println!("{}", title);
println!("{title}");
println!("{}", separator);
println!("{separator}");
};
format_section("System Information");
@ -164,7 +170,7 @@ fn main() {
"CPU Temperature: {}",
report.cpu_global.average_temperature_celsius.map_or_else(
|| "N/A (No sensor detected)".to_string(),
|t| format!("{:.1}°C", t)
|t| format!("{t:.1}°C")
)
);
@ -205,9 +211,9 @@ fn main() {
let max_freq = core_info.max_frequency_mhz.unwrap_or(0);
if freq > max_freq && max_freq > 0 {
// Special format for boosted frequencies
format!("{}*", freq)
format!("{freq}*")
} else {
format!("{}", freq)
format!("{freq}")
}
}
None => "N/A".to_string(),
@ -234,13 +240,13 @@ fn main() {
"{}%",
core_info
.usage_percent
.map_or_else(|| "N/A".to_string(), |f| format!("{:.1}", f))
.map_or_else(|| "N/A".to_string(), |f| format!("{f:.1}"))
),
format!(
"{}°C",
core_info
.temperature_celsius
.map_or_else(|| "N/A".to_string(), |f| format!("{:.1}", f))
.map_or_else(|| "N/A".to_string(), |f| format!("{f:.1}"))
),
width = max_core_id_len
);
@ -355,24 +361,24 @@ fn main() {
Some(Commands::Daemon { verbose }) => daemon::run_daemon(config, verbose),
Some(Commands::Debug) => cli::debug::run_debug(&config),
None => {
println!("Welcome to superfreq! Use --help for commands.");
println!("Current effective configuration: {config:?}");
info!("Welcome to superfreq! Use --help for commands.");
debug!("Current effective configuration: {config:?}");
Ok(())
}
};
if let Err(e) = command_result {
eprintln!("Error executing command: {e}");
error!("Error executing command: {e}");
if let Some(source) = e.source() {
eprintln!("Caused by: {source}");
error!("Caused by: {source}");
}
// TODO: Consider specific error handling for PermissionDenied from cpu here
// For example, check if e.downcast_ref::<cpu::ControlError>() matches PermissionDenied
// TODO: Consider specific error handling for PermissionDenied from the cpu module here.
// For example, check if `e.downcast_ref::<cpu::ControlError>()` matches `PermissionDenied`
// and print a more specific message like "Try running with sudo."
// We'll revisit this in the future once CPU logic is more stable.
if let Some(control_error) = e.downcast_ref::<ControlError>() {
if matches!(control_error, ControlError::PermissionDenied(_)) {
eprintln!(
error!(
"Hint: This operation may require administrator privileges (e.g., run with sudo)."
);
}
@ -381,3 +387,20 @@ fn main() {
std::process::exit(1);
}
}
/// Initialize the logger for the entire application
static LOGGER_INIT: Once = Once::new();
fn init_logger() {
LOGGER_INIT.call_once(|| {
// Set default log level based on environment or default to Info
let env_log = std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string());
Builder::new()
.parse_filters(&env_log)
.format_timestamp(None)
.format_module_path(false)
.init();
debug!("Logger initialized with RUST_LOG={env_log}");
});
}