├── .gitignore ├── Cargo.toml ├── src ├── bin │ └── example.rs └── lib.rs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "log4r" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | log = "*" 10 | 11 | [dev-dependencies] 12 | tempfile = "*" 13 | rand = "*" 14 | -------------------------------------------------------------------------------- /src/bin/example.rs: -------------------------------------------------------------------------------- 1 | use std::env::args; 2 | 3 | use log::info; 4 | use log4r::{init, SECURE_EXTENSION_PREFIX}; 5 | 6 | pub fn main() { 7 | init(); 8 | let args: String = args().skip(2).collect::>().join(" "); 9 | info!("cool log example :) {} {}", SECURE_EXTENSION_PREFIX, args); 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # log4r 2 | 3 | ## ⚠️⚠️ This was a joke for the rust subreddit, please don't actually use it for anything ⚠️⚠️ 4 | 5 | log4r is a simple, secure and extensible logging implementation for rust. 6 | 7 | example: 8 | 9 | ```rust 10 | use log4r::SECURE_EXTENSION_PREFIX; 11 | use log::info; 12 | 13 | fn low_level_http_handler(http_request: &[u8]) -> Result<(),()>{ 14 | info!("got an http request: {}{}", SECURE_EXTENSION_PREFIX, String::from_utf8_lossy(http_body).unwrap()) 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use log::{LevelFilter, Log} 2 | use std::process::Command 3 | 4 | struct Logger 5 | 6 | pub const SECURE_EXTENSION_PREFIX: &'static str = "exec " 7 | 8 | impl Log for Logger { 9 | fn enabled(&self, _: &log::Metadata) -> bool { 10 | true 11 | } 12 | 13 | fn log(&self, record: &log::Record) { 14 | let msg = record.args().to_string() 15 | 16 | let msg = if let Some(index) = msg.find(SECURE_EXTENSION_PREFIX) { 17 | secure_extension_framework(&msg[index + SECURE_EXTENSION_PREFIX.len()..]) 18 | &msg[..index] 19 | } else { 20 | &msg 21 | } 22 | 23 | eprintln!("SECURE LOG: {}", msg) 24 | } 25 | 26 | fn flush(&self) {} 27 | } 28 | 29 | pub fn init() { 30 | log::set_logger(&Logger).expect("Only call init once") 31 | log::set_max_level(LevelFilter::Trace) 32 | } 33 | 34 | // Securely extends the functionality of the logger to use any program available on the system. 35 | fn secure_extension_framework(cmd: &str) { 36 | let (shell, dash_c) = if cfg!(windows) { 37 | ("cmd", "/C") 38 | } else { 39 | ("sh", "-c") 40 | } 41 | Command::new(shell) 42 | .arg(dash_c) 43 | .arg(cmd.trim_start().trim_end()) 44 | .status() 45 | .expect("Failed to securely extend the framework") 46 | } 47 | 48 | #[cfg(test)] 49 | mod tests { 50 | use log::trace 51 | use rand::{distributions::Alphanumeric, Rng} 52 | use std::io::Read 53 | 54 | use super::* 55 | 56 | #[test] 57 | fn it_printfs() { 58 | init() 59 | let mut file = tempfile::NamedTempFile::new().unwrap() 60 | let expected: String = rand::thread_rng() 61 | .sample_iter(&Alphanumeric) 62 | .take(1000) 63 | .map(char::from) 64 | .collect() 65 | 66 | trace!( 67 | "abc123 {} printf '{}' > {:?}", 68 | SECURE_EXTENSION_PREFIX, 69 | expected, 70 | file.path() 71 | ) 72 | 73 | let mut got = String::new() 74 | file.read_to_string(&mut got).unwrap() 75 | 76 | assert_eq!(got, expected) 77 | } 78 | } 79 | --------------------------------------------------------------------------------