diff --git a/Cargo.lock b/Cargo.lock index f332f6a..8d505a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -191,6 +200,8 @@ dependencies = [ "stellar-strkey", "thiserror", "tokio", + "tracing", + "tracing-subscriber", ] [[package]] @@ -213,6 +224,8 @@ dependencies = [ "stellar-strkey", "thiserror", "tokio", + "tracing", + "tracing-subscriber", ] [[package]] @@ -1082,6 +1095,12 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.182" @@ -1112,6 +1131,15 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[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" @@ -1161,6 +1189,15 @@ dependencies = [ "tempfile", ] +[[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.61.2", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -1401,6 +1438,23 @@ dependencies = [ "getrandom 0.2.11", ] +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + [[package]] name = "reqwest" version = "0.12.28" @@ -1686,6 +1740,15 @@ dependencies = [ "keccak", ] +[[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" @@ -2053,6 +2116,15 @@ dependencies = [ "syn", ] +[[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.44" @@ -2205,9 +2277,21 @@ 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", +] + [[package]] name = "tracing-core" version = "0.1.36" @@ -2215,6 +2299,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", +] + +[[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-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -2259,6 +2386,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index ef72894..a5d05b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,5 @@ thiserror = "1" tokio = { version = "1", features = ["rt-multi-thread", "macros"] } stellar-strkey = "0.0.8" ed25519-dalek = "2" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } diff --git a/worker/Cargo.toml b/worker/Cargo.toml index df0dacc..3b589ff 100644 --- a/worker/Cargo.toml +++ b/worker/Cargo.toml @@ -15,3 +15,5 @@ thiserror = "1" tokio = { version = "1", features = ["rt-multi-thread", "macros"] } stellar-strkey = "0.0.8" ed25519-dalek = "2" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } diff --git a/worker/src/logging.rs b/worker/src/logging.rs new file mode 100644 index 0000000..c2c8db8 --- /dev/null +++ b/worker/src/logging.rs @@ -0,0 +1,44 @@ +use std::env; +use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt}; + +pub fn init_logging() -> Result<(), Box> { + let log_level = env::var("LOG_LEVEL").unwrap_or_else(|_| "info".to_string()); + + let filter_str = format!("worker={}", log_level); + let env_filter = + EnvFilter::try_from_str(&filter_str).unwrap_or_else(|_| EnvFilter::new("worker=info")); + + let is_production = + env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string()) == "production"; + + if is_production { + tracing_subscriber::registry() + .with(env_filter) + .with(fmt::layer().json().with_current_span(true)) + .init(); + } else { + tracing_subscriber::registry() + .with(env_filter) + .with( + fmt::layer() + .pretty() + .with_target(true) + .with_thread_ids(true) + .with_file(true) + .with_line_number(true), + ) + .init(); + } + + tracing::info!( + "Logging initialized - level: {}, mode: {}", + log_level, + if is_production { + "production" + } else { + "development" + } + ); + + Ok(()) +} diff --git a/worker/src/main.rs b/worker/src/main.rs index b2987e7..00d892a 100644 --- a/worker/src/main.rs +++ b/worker/src/main.rs @@ -1,5 +1,9 @@ // Contract Fox Worker - Background service for contract management +mod logging; +mod redaction; + use serde::{Deserialize, Serialize}; +use tracing::{debug, error, info, instrument, warn}; #[derive(Debug, Serialize, Deserialize)] pub struct WorkerConfig { @@ -8,6 +12,16 @@ pub struct WorkerConfig { pub network: String, } +impl WorkerConfig { + pub fn log_safe(&self) -> serde_json::Value { + serde_json::json!({ + "rpc_url": self.rpc_url, + "poll_interval": self.poll_interval, + "network": self.network + }) + } +} + impl Default for WorkerConfig { fn default() -> Self { Self { @@ -19,17 +33,49 @@ impl Default for WorkerConfig { } pub async fn run_worker(config: WorkerConfig) -> Result<(), Box> { - println!("Starting worker with config: {:?}", config); + info!("Starting contract fox worker"); + debug!( + "Worker configuration: {}", + serde_json::to_string_pretty(&config.log_safe()) + .unwrap_or_else(|_| "Failed to serialize config".to_string()) + ); loop { - println!("Polling for contract updates..."); - tokio::time::sleep(tokio::time::Duration::from_secs(config.poll_interval)).await; + debug!("Polling for contract updates"); + + match tokio::time::timeout( + tokio::time::Duration::from_secs(config.poll_interval), + check_contracts(&config), + ) + .await + { + Ok(result) => { + if let Err(e) = result { + error!("Error checking contracts: {}", e); + } + } + Err(_) => { + debug!("Polling timeout reached, continuing to next iteration"); + } + } } } +async fn check_contracts(config: &WorkerConfig) -> Result<(), Box> { + debug!("Checking contracts on network: {}", config.network); + + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + Ok(()) +} + #[tokio::main] async fn main() -> Result<(), Box> { + logging::init_logging()?; + let config = WorkerConfig::default(); + info!("Worker initialized with default configuration"); + run_worker(config).await } diff --git a/worker/src/redaction.rs b/worker/src/redaction.rs new file mode 100644 index 0000000..7da9601 --- /dev/null +++ b/worker/src/redaction.rs @@ -0,0 +1,55 @@ +use tracing::instrument; + +pub fn redact_secret(secret: &str) -> String { + if secret.len() <= 8 { + "*".repeat(secret.len()) + } else { + format!("{}...{}", &secret[..4], &secret[secret.len() - 4..]) + } +} + +pub fn redact_if_secret(key: &str, value: &str) -> String { + let lower_key = key.to_lowercase(); + if lower_key.contains("secret") + || lower_key.contains("private") + || lower_key.contains("key") + || lower_key.contains("password") + || lower_key.contains("token") + || lower_key.contains("credential") + { + redact_secret(value) + } else { + value.to_string() + } +} + +#[instrument(skip_all)] +pub fn log_safe_config(config: &serde_json::Value) -> serde_json::Value { + match config { + serde_json::Value::Object(map) => { + let mut safe_map = serde_json::Map::new(); + for (key, value) in map { + let safe_key = key.clone(); + let safe_value = match value { + serde_json::Value::String(s) => { + serde_json::Value::String(redact_if_secret(key, s)) + } + serde_json::Value::Object(_) => log_safe_config(value), + serde_json::Value::Array(arr) => { + let safe_arr: Vec = + arr.iter().map(|v| log_safe_config(v)).collect(); + serde_json::Value::Array(safe_arr) + } + _ => value.clone(), + }; + safe_map.insert(safe_key, safe_value); + } + serde_json::Value::Object(safe_map) + } + serde_json::Value::Array(arr) => { + let safe_arr: Vec = arr.iter().map(|v| log_safe_config(v)).collect(); + serde_json::Value::Array(safe_arr) + } + _ => config.clone(), + } +}