aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Hoerr <kjhoerr@submelon.dev>2026-04-22 14:52:59 -0400
committerKevin Hoerr <kjhoerr@submelon.dev>2026-04-22 14:52:59 -0400
commit0952686526e118339b945ccfb84db1dcc69ee2ab (patch)
tree983cc5018ba31f88d89c241c951a38a4cae752c8
parent25246c26c11f485272689b8c7bd7910f90cc38ed (diff)
downloadequity-tracker-0952686526e118339b945ccfb84db1dcc69ee2ab.tar.gz
equity-tracker-0952686526e118339b945ccfb84db1dcc69ee2ab.tar.bz2
equity-tracker-0952686526e118339b945ccfb84db1dcc69ee2ab.zip
Add logging
-rw-r--r--Cargo.lock122
-rw-r--r--Cargo.toml3
-rw-r--r--TODO.md2
-rw-r--r--src/app/mod.rs9
-rw-r--r--src/app/store/sqlite.rs2
-rw-r--r--src/logging.rs54
-rw-r--r--src/main.rs12
7 files changed, 203 insertions, 1 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6f021bd..5c817b2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -389,6 +389,9 @@ dependencies = [
"ratatui",
"sqlite",
"thiserror 2.0.18",
+ "tracing",
+ "tracing-error",
+ "tracing-subscriber",
]
[[package]]
@@ -744,6 +747,15 @@ dependencies = [
]
[[package]]
+name = "matchers"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
name = "memchr"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -845,6 +857,15 @@ dependencies = [
]
[[package]]
+name = "nu-ansi-term"
+version = "0.50.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
+dependencies = [
+ "windows-sys 0.60.2",
+]
+
+[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1047,6 +1068,12 @@ dependencies = [
]
[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1343,6 +1370,15 @@ dependencies = [
]
[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1619,6 +1655,15 @@ dependencies = [
]
[[package]]
+name = "thread_local"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
name = "time"
version = "0.3.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1640,6 +1685,77 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-error"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db"
+dependencies = [
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex-automata",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
name = "typenum"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1717,6 +1833,12 @@ dependencies = [
]
[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 0e395e7..0aa8e87 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,6 +18,9 @@ miette = { version = "7.6.0", features = ["fancy"] }
ratatui = "0.30.0"
sqlite = "0.37.0"
thiserror = "2.0.18"
+tracing = "0.1.44"
+tracing-error = "0.2.1"
+tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
[lints.rust]
diff --git a/TODO.md b/TODO.md
index 588bd62..9bfd841 100644
--- a/TODO.md
+++ b/TODO.md
@@ -3,7 +3,7 @@
- [x] SQLite integration
- [x] Design process flow
- [x] Prepare in-mem schema
-- [ ] Write debug logging to file?
+- [x] Write debug logging to file
- [ ] Add app state handling
- [ ] Init screen: app loading
- [ ] Add detect change control for schema
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 15290ef..d51640f 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -34,6 +34,7 @@ impl App {
}
pub fn exit(&mut self) -> Result<()> {
+ tracing::event!(tracing::Level::TRACE, exit = true, "Changing exit status.");
self.exit = true;
Ok(())
}
@@ -42,6 +43,7 @@ impl App {
let store = self.context.unwrap_store();
let count = store.get_counter()?;
+ tracing::event!(tracing::Level::TRACE, count, "Decrementing counter.");
if count == 0 {
Err(OverflowError {
_msg: "Cannot count below 0".into(),
@@ -57,6 +59,7 @@ impl App {
let store = self.context.unwrap_store();
let count = store.get_counter()?;
+ tracing::event!(tracing::Level::TRACE, count, "Incrementing counter.");
if count == u8::MAX {
Err(OverflowError {
_msg: "Cannot count above u8::MAX".into(),
@@ -77,6 +80,12 @@ impl App {
}
pub fn set_error(&mut self, error: ErrReport) -> Result<()> {
+ tracing::event!(
+ tracing::Level::ERROR,
+ error = error.to_string(),
+ help = error.help().map_or(String::default(), |h| h.to_string())
+ );
+
self.error = Some(error);
Ok(())
}
diff --git a/src/app/store/sqlite.rs b/src/app/store/sqlite.rs
index 4f5f8f2..e971ef3 100644
--- a/src/app/store/sqlite.rs
+++ b/src/app/store/sqlite.rs
@@ -87,6 +87,8 @@ impl Store for SQLiteStore {
fn set_counter(&mut self, new_count: u8) -> Result<u8, ContextError> {
self.update_counter(i64::from(new_count))?;
+ tracing::event!(tracing::Level::DEBUG, new_count, "Updated counter.");
+
Ok(new_count)
}
}
diff --git a/src/logging.rs b/src/logging.rs
new file mode 100644
index 0000000..fd81dba
--- /dev/null
+++ b/src/logging.rs
@@ -0,0 +1,54 @@
+use std::{io::Error, path::PathBuf, str::FromStr};
+
+use tracing_error::ErrorLayer;
+use tracing_subscriber::{self, Layer, layer::SubscriberExt, util::SubscriberInitExt};
+
+const LOG_FILE: &'static str = "equity-tracker.log";
+
+const LOG_LEVEL: &'static str = "LOG_LEVEL";
+const DEFAULT_LOG_LEVEL: &'static str = "DEBUG";
+
+const LOG_DIRECTORY: &'static str = "LOG_DIRECTORY";
+const DEFAULT_LOG_DIRECTORY: &'static str = "./target";
+
+/// Either retrieves the environment variable or uses a default value
+fn get_env_var(var_name: &'static str, default: &'static str) -> String {
+ if let Ok(env_var) = std::env::var(var_name) {
+ env_var
+ } else {
+ default.into()
+ }
+}
+
+/// Provides a PathBuf of the configured log directory, or the target directory
+fn get_log_directory() -> std::io::Result<PathBuf> {
+ let env_dir = get_env_var(LOG_DIRECTORY, DEFAULT_LOG_DIRECTORY);
+ let path = PathBuf::from_str(&env_dir).map_err(|e| Error::other(e))?;
+
+ Ok(path)
+}
+
+/// Configure the logging through tracing
+pub fn initialize_logging() -> std::io::Result<()> {
+ let directory = get_log_directory()?;
+ std::fs::create_dir_all(directory.clone())?;
+
+ let log_path = directory.join(LOG_FILE);
+ let log_file = std::fs::File::create(log_path)?;
+
+ let log_filter = get_env_var(LOG_LEVEL, DEFAULT_LOG_LEVEL);
+ let file_subscriber = tracing_subscriber::fmt::layer()
+ .with_file(true)
+ .with_line_number(true)
+ .with_target(false)
+ .with_ansi(false)
+ .with_writer(log_file)
+ .with_filter(tracing_subscriber::filter::EnvFilter::builder().parse_lossy(log_filter));
+
+ tracing_subscriber::registry()
+ .with(file_subscriber)
+ .with(ErrorLayer::default())
+ .init();
+
+ Ok(())
+}
diff --git a/src/main.rs b/src/main.rs
index bb63c86..d1d4ee4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
mod app;
+mod logging;
mod ui;
use app::App;
@@ -24,9 +25,15 @@ fn main() -> Result<()> {
let backend = CrosstermBackend::new(stdout);
let mut term = Terminal::new(backend).into_diagnostic()?;
+ logging::initialize_logging().into_diagnostic()?;
+
+ tracing::event!(tracing::Level::DEBUG, "App initialization started.");
+
let mut app = App::default();
app.init_context()?;
+ tracing::event!(tracing::Level::INFO, "App started.");
+
// could be error, so don't unwrap; let term restore first
let run = run_app(&mut term, &mut app);
@@ -67,6 +74,11 @@ fn run_app<B: Backend>(term: &mut Terminal<B>, app: &mut App) -> Result<()> {
/// Process user input and run associated app functions
fn handle_key_event(app: &mut App, key_event: KeyEvent) -> Result<()> {
+ tracing::event!(
+ tracing::Level::TRACE,
+ event = key_event.code.to_string(),
+ "Received key event."
+ );
match key_event.code {
KeyCode::Char('q') => app.exit()?,
KeyCode::Left => app.decrement_counter()?,