From b09220fbe207ac3f71e2865fc4525b5830c7e6bb Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Mon, 6 Sep 2021 19:24:45 -0400 Subject: [PATCH] logtail facade Signed-off-by: Christine Dodrill --- Cargo.lock | 105 +++++++++++++++++++++++++++-- crates/logtail-facade/Cargo.toml | 23 +++++++ crates/logtail-facade/src/lib.rs | 109 +++++++++++++++++++++++++++++++ crates/logtail-facade/src/log.rs | 46 +++++++++++++ 4 files changed, 279 insertions(+), 4 deletions(-) create mode 100644 crates/logtail-facade/Cargo.toml create mode 100644 crates/logtail-facade/src/lib.rs create mode 100644 crates/logtail-facade/src/log.rs diff --git a/Cargo.lock b/Cargo.lock index 703df86..1c828c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "futures" version = "0.3.17" @@ -467,10 +473,23 @@ name = "logtail" version = "0.1.0" dependencies = [ "hex", - "rand", + "rand 0.8.4", "sha2", ] +[[package]] +name = "logtail-facade" +version = "0.1.0" +dependencies = [ + "log", + "logtail", + "logtail-poster", + "serde", + "serde_json", + "serial_test", + "tempdir", +] + [[package]] name = "logtail-poster" version = "0.1.0" @@ -656,6 +675,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.4" @@ -664,7 +696,7 @@ checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.3", "rand_hc", ] @@ -675,9 +707,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.3", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.3" @@ -693,7 +740,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", ] [[package]] @@ -705,6 +761,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "reqwest" version = "0.11.4" @@ -847,6 +912,28 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d" +dependencies = [ + "lazy_static", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.9.5" @@ -917,6 +1004,16 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + [[package]] name = "thiserror" version = "1.0.29" diff --git a/crates/logtail-facade/Cargo.toml b/crates/logtail-facade/Cargo.toml new file mode 100644 index 0000000..faef095 --- /dev/null +++ b/crates/logtail-facade/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "logtail-facade" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = [ "log-facade" ] +log-facade = [ "log" ] + +[dependencies] +log = { version = "0.4", optional = true } +serde = { version = "1", features = [ "derive" ] } +serde_json = "1" + +# local deps +logtail = { path = "../logtail" } +logtail-poster = { path = "../logtail-poster" } + +[dev-dependencies] +tempdir = "0.3" +serial_test = "0.5.1" diff --git a/crates/logtail-facade/src/lib.rs b/crates/logtail-facade/src/lib.rs new file mode 100644 index 0000000..48b6a29 --- /dev/null +++ b/crates/logtail-facade/src/lib.rs @@ -0,0 +1,109 @@ +use serde::{Deserialize, Serialize}; +use std::{env, ffi::OsString, fs, io, path::PathBuf}; + +#[cfg(feature = "log-facade")] +mod log; +#[cfg(feature = "log-facade")] +pub use self::log::*; + +pub(crate) fn cache_dir() -> Option { + let dir = env::var_os("STATE_DIRECTORY").or_else(|| { + env::var_os("HOME").and_then(|dir| { + let mut dir: PathBuf = dir.into(); + dir.push(".cache"); + dir.push("rebterlai"); + Some(OsString::from(dir)) + }) + }); + dir +} + +pub(crate) fn state_file(name: &str) -> Option { + let mut dir: PathBuf = cache_dir()?.into(); + dir.push(&format!("{}.json", name)); + Some(dir) +} + +#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] +pub struct Config { + private_id: String, + public_id: String, +} + +impl Config { + pub fn new() -> Self { + let private_id = logtail::PrivateID::new(); + + Self { + private_id: private_id.as_hex(), + public_id: private_id.as_public().as_hex(), + } + } + + pub fn load(collection: S) -> io::Result + where + S: Into, + { + let dir = cache_dir() + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "can't find directory"))?; + if let Err(_) = fs::metadata(&dir) { + fs::create_dir_all(&dir)?; + } + println!("{:?}", dir); + + let fname = state_file(&collection.into()).ok_or_else(|| { + io::Error::new( + io::ErrorKind::InvalidInput, + "can't derive logtail config filename", + ) + })?; + match fs::metadata(&fname) { + Ok(_) => { + let fin = fs::File::open(&fname)?; + let cfg = serde_json::from_reader(io::BufReader::new(fin)) + .or_else(|why| Err(io::Error::new(io::ErrorKind::Other, why)))?; + Ok(cfg) + } + Err(_) => { + let cfg = Self::new(); + let mut fout = fs::File::create(&fname)?; + serde_json::to_writer(&mut fout, &cfg) + .or_else(|why| Err(io::Error::new(io::ErrorKind::Other, why)))?; + Ok(cfg) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tempdir::TempDir; + + #[test] + #[serial_test::serial] + fn cache_dir() { + let home = TempDir::new("cache").unwrap(); + std::env::set_var("STATE_DIRECTORY", home.path().to_str().unwrap()); + let dir = super::cache_dir(); + + assert!(dir.is_some()); + assert_eq!(dir.unwrap(), home.path().to_str().unwrap()); + + home.close().unwrap(); + } + + #[test] + #[serial_test::serial] + fn new_and_load() { + let home = TempDir::new("cache").unwrap(); + std::env::set_var("STATE_DIRECTORY", home.path().to_str().unwrap()); + + let cfg = Config::load("foo.bar").unwrap(); + let cfg2 = Config::load("foo.bar").unwrap(); + + assert_eq!(cfg, cfg2); + + home.close().unwrap(); + } +} diff --git a/crates/logtail-facade/src/log.rs b/crates/logtail-facade/src/log.rs new file mode 100644 index 0000000..2b64fb4 --- /dev/null +++ b/crates/logtail-facade/src/log.rs @@ -0,0 +1,46 @@ +use log::{Level, Metadata, Record}; +use std::sync::{Arc, Mutex}; + +pub struct LogtailLogger { + ing: Arc>, + threshold: Level, +} + +#[derive(serde::Serialize)] +struct LogData<'a> { + level: &'a str, + target: &'a str, + module_path: &'a str, + file: &'a str, + line: u32, + message: String, +} + +impl log::Log for LogtailLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= self.threshold + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let ld = LogData { + level: record.level().as_str(), + target: record.target(), + module_path: record.module_path().unwrap_or("???"), + file: record.file().unwrap_or("???"), + line: record.line().unwrap_or(0), + message: format!("{}", record.args()), + }; + + if let Ok(val) = serde_json::to_value(&ld) { + if let Ok(mut ing) = self.ing.lock() { + if let Err(why) = ing.send(val) { + eprintln!("logtail_facade::jog::LogtailLogger::log: can't send json value to buffer: {}", why); + } + } + } + } + } + + fn flush(&self) {} +}