diff --git a/Cargo.lock b/Cargo.lock index 0468fdf..d050f0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,12 +395,14 @@ version = "0.1.0" dependencies = [ "chrono", "gpio", + "log", "regex", "rocket", "rppal", "rust-embed", "serde", "serde_json", + "simplelog", "tokio", ] @@ -786,6 +788,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.36.7" @@ -1278,6 +1289,17 @@ dependencies = [ "libc", ] +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + [[package]] name = "slab" version = "0.4.9" @@ -1351,6 +1373,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -1369,7 +1400,9 @@ checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", diff --git a/Cargo.toml b/Cargo.toml index f254786..c3178f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ serde_json = "1.0.140" rocket = "0.5.1" tokio = { version = "1.44.2", features = ["full"] } rust-embed = "8.7.0" +log = "0.4.27" +simplelog = "0.12.2" [target.armv7-unknown-linux-gnueabihf] -linker = "arm-linux-gnueabihf-gcc" \ No newline at end of file +linker = "arm-linux-gnueabihf-gcc" diff --git a/src/id_store.rs b/src/id_store.rs index 66ec8dd..b53452a 100644 --- a/src/id_store.rs +++ b/src/id_store.rs @@ -1,13 +1,21 @@ +use log::info; use serde::{Deserialize, Serialize}; use std::{ collections::{HashMap, HashSet}, error::Error, + fmt::Display, fs, }; #[derive(PartialEq, Eq, Deserialize, Serialize, Hash, Clone, PartialOrd, Ord)] pub struct TallyID(pub String); +impl Display for TallyID { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + #[derive(Deserialize, Serialize)] pub struct AttendanceDay { date: String, @@ -106,6 +114,7 @@ impl AttendanceDay { if self.ids.contains(&id) { return; } + info!("Adding id: {}", id); self.ids.push(id); } } diff --git a/src/main.rs b/src/main.rs index 71de6fc..3488a85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,9 @@ -use std::sync::Arc; - use id_store::IDStore; +use log::{LevelFilter, error, info, warn}; use pm3::{pm3_mock, run_pm3}; -use tokio::sync::{mpsc, Mutex}; +use simplelog::{ConfigBuilder, SimpleLogger}; +use std::{env, sync::Arc}; +use tokio::sync::{Mutex, mpsc}; use webserver::start_webserver; mod id_store; @@ -10,17 +11,40 @@ mod parser; mod pm3; mod webserver; +fn setup_logger() { + let log_level = env::var("LOG_LEVEL") + .ok() + .and_then(|level| level.parse::().ok()) + .unwrap_or({ + if cfg!(debug_assertions) { + LevelFilter::Debug + } else { + LevelFilter::Warn + } + }); + + let config = ConfigBuilder::new() + .set_target_level(LevelFilter::Error) + .build(); + + let _ = SimpleLogger::init(log_level, config); +} + #[tokio::main] async fn main() { + setup_logger(); + + info!("Starting application"); + let (tx, mut rx) = mpsc::channel::(1); tokio::spawn(async move { match run_pm3(tx).await { Ok(()) => { - println!("PM3 exited with an zero error code"); + warn!("PM3 exited with a zero exit code"); } Err(e) => { - println!("PM3 failed to run: {}", e); + error!("Failed to run PM3: {}", e); } } }); @@ -37,7 +61,7 @@ async fn main() { match start_webserver(store.clone()).await { Ok(()) => {} Err(e) => { - eprintln!("Failed to start webserver: {}", e); + error!("Failed to start webserver: {}", e); } } } diff --git a/src/pm3.rs b/src/pm3.rs index e067e1a..052134a 100644 --- a/src/pm3.rs +++ b/src/pm3.rs @@ -1,18 +1,18 @@ +use log::{debug, error, info}; use std::env; use std::error::Error; use std::io::{self, BufRead}; use std::process::{Command, Stdio}; -use tokio::time::{Duration, sleep}; - use tokio::sync::mpsc; +use tokio::time::{Duration, sleep}; pub async fn run_pm3(tx: mpsc::Sender) -> Result<(), Box> { let pm3_path = match env::var("PM3_BIN") { Ok(path) => path, Err(_) => { - println!("PM3_BIN not set. Using default value"); + info!("PM3_BIN not set. Using default value"); "pm3".to_owned() - }, + } }; let mut cmd = Command::new("stdbuf") @@ -29,18 +29,20 @@ pub async fn run_pm3(tx: mpsc::Sender) -> Result<(), Box> { for line_result in reader.lines() { match line_result { Ok(line) => { + debug!("PM3: {}", line); let parse_result = super::parser::parse_line(&line); if let Some(uid) = parse_result { + debug!("Read ID: {}", uid); match tx.send(uid).await { Ok(()) => {} Err(e) => { - eprintln!("Failed to send to channel: {}", e); + error!("Failed to send to channel: {}", e); } } } } Err(e) => { - eprintln!("{}", e); + error!("Failed to read line from PM3: {}", e); } } } @@ -50,7 +52,7 @@ pub async fn run_pm3(tx: mpsc::Sender) -> Result<(), Box> { if status.success() { Ok(()) } else { - Err("pm3 had non zero exit code".into()) + Err("PM3 exited with a non zero exit code".into()) } } @@ -60,7 +62,7 @@ pub async fn pm3_mock(tx: mpsc::Sender) -> Result<(), Box> { match tx.send("F1409618".to_owned()).await { Ok(()) => {} Err(e) => { - eprintln!("Failed to send to channel: {}", e); + error!("Failed to send to channel: {}", e); } } diff --git a/src/webserver.rs b/src/webserver.rs index f2fdf1c..c8ca5b7 100644 --- a/src/webserver.rs +++ b/src/webserver.rs @@ -1,3 +1,4 @@ +use log::{error, info}; use rocket::http::Status; use rocket::{Config, State}; use rocket::{get, http::ContentType, response::content::RawHtml, routes}; @@ -49,10 +50,11 @@ fn static_files(file: std::path::PathBuf) -> Option<(ContentType, Vec)> { #[get("/api/csv")] async fn export_csv(manager: &State>>) -> Result { + info!("Exporting CSV"); match manager.lock().await.export_csv() { Ok(csv) => Ok(csv), Err(e) => { - eprintln!("Failed to generate csv: {}", e); + error!("Failed to generate csv: {}", e); Err(Status::InternalServerError) } }