1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
use std::cell::RefCell; const LOG_MESSAGES_BYTES_LIMIT: usize = 10 * 1000; #[derive(Default)] struct LogCollectorInner { messages: Vec<String>, bytes_written: usize, limit_warning: bool, } #[derive(Default)] pub struct LogCollector { inner: RefCell<LogCollectorInner>, } impl LogCollector { pub fn log(&self, message: &str) { let mut inner = self.inner.borrow_mut(); if inner.bytes_written + message.len() >= LOG_MESSAGES_BYTES_LIMIT { if !inner.limit_warning { inner.limit_warning = true; inner.messages.push(String::from("Log truncated")); } } else { inner.bytes_written += message.len(); inner.messages.push(message.to_string()); } } } impl From<LogCollector> for Vec<String> { fn from(log_collector: LogCollector) -> Self { log_collector.inner.into_inner().messages } } #[cfg(test)] pub(crate) mod tests { use super::*; #[test] fn test_log_messages_bytes_limit() { let lc = LogCollector::default(); for _i in 0..LOG_MESSAGES_BYTES_LIMIT * 2 { lc.log("x"); } let logs: Vec<_> = lc.into(); assert_eq!(logs.len(), LOG_MESSAGES_BYTES_LIMIT); for log in logs.iter().take(LOG_MESSAGES_BYTES_LIMIT - 1) { assert_eq!(*log, "x".to_string()); } assert_eq!(logs.last(), Some(&"Log truncated".to_string())); } }