diff --git a/Cargo.toml b/Cargo.toml index 95f3afa77..dc4f5ed9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,15 @@ [workspace] -members = ["copper", "copper_log_test", "copper_derive", "copper_derive_test", "copper_log", "examples/config_gen", "examples/pluginload", "examples/simplelogger", "examples/v4lsrc", "copper_log_runtime", "copper_datalogger", "copper_clock"] +members = ["copper", + "copper_log_test", + "copper_derive", + "copper_derive_test", + "copper_log", + "examples/config_gen", + "examples/pluginload", + "examples/simplelogger", + "examples/v4lsrc", + "copper_log_runtime", + "copper_datalogger", + "copper_clock", + "copper_traits"] resolver = "2" diff --git a/copper/Cargo.toml b/copper/Cargo.toml index a9e313c33..6645df98c 100644 --- a/copper/Cargo.toml +++ b/copper/Cargo.toml @@ -13,9 +13,6 @@ serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" uom = { version = "0.36.0", features = ["rational"] } ron = "0.8.1" +copper-traits = { path = "../copper_traits" } copper-log = { path = "../copper_log" } -copper-log-runtime = { path = "../copper_log_runtime" } -bincode = "2.0.0-rc.3" - - - +copper-log-runtime = { path = "../copper_log_runtime" } \ No newline at end of file diff --git a/copper/src/lib.rs b/copper/src/lib.rs index 64238e4a4..17071b11c 100644 --- a/copper/src/lib.rs +++ b/copper/src/lib.rs @@ -5,59 +5,4 @@ pub mod cutask; pub mod monitoring; pub mod serde; -use bincode::Encode; -use std::error::Error; -use std::fmt::{Debug, Display, Formatter}; - -// Copper common error type. - -#[derive(Debug)] -pub struct CuError { - message: String, - context: Option, -} - -impl Display for CuError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let context_str = match &self.context { - Some(c) => format!("{}", c), - None => "None".to_string(), - }; - write!(f, "{}\n context:{}", self.message, context_str)?; - Ok(()) - } -} - -impl Error for CuError {} - -impl From<&str> for CuError { - fn from(s: &str) -> CuError { - CuError { - message: s.to_string(), - context: None, - } - } -} - -impl From for CuError { - fn from(s: String) -> CuError { - CuError { - message: s, - context: None, - } - } -} - -impl CuError { - pub fn add_context(mut self, context: &str) -> CuError { - self.context = Some(context.into()); - self - } -} - -pub type CuResult = Result; - -/// Defines a basic write, append only stream trait to be able to log or send serializable objects. -pub trait Stream { - fn log(&mut self, obj: &impl Encode); -} +pub use copper_traits::*; diff --git a/copper_datalogger/Cargo.toml b/copper_datalogger/Cargo.toml index 93ed0250d..087eaddb1 100644 --- a/copper_datalogger/Cargo.toml +++ b/copper_datalogger/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "copper_datalogger" +name = "copper-datalogger" version = "0.1.0" edition = "2021" diff --git a/copper_datalogger/src/lib.rs b/copper_datalogger/src/lib.rs index 40c719c4e..66568a030 100644 --- a/copper_datalogger/src/lib.rs +++ b/copper_datalogger/src/lib.rs @@ -19,7 +19,7 @@ use bincode::{decode_from_reader, decode_from_slice}; use bincode_derive::Decode as dDecode; use bincode_derive::Encode as dEncode; -use copper::Stream; +use copper::{CuError, CuResult, Stream}; const MAIN_MAGIC: [u8; 4] = [0xB4, 0xA5, 0x50, 0xFF]; @@ -70,7 +70,7 @@ impl MmapStream { } impl Stream for MmapStream { - fn log(&mut self, obj: &impl Encode) { + fn log(&mut self, obj: &impl Encode) -> CuResult<()> { let result = encode_into_slice( obj, &mut self.current_slice[self.current_position..], @@ -79,6 +79,7 @@ impl Stream for MmapStream { match result { Ok(nb_bytes) => { self.current_position += nb_bytes; + Ok(()) } Err(e) => match e { EncodeError::UnexpectedEnd => { @@ -91,8 +92,14 @@ impl Stream for MmapStream { self.current_slice = unsafe { from_raw_parts_mut(underlying_slice.as_mut_ptr(), underlying_slice.len()) }; + Ok(()) + } + _ => { + let err = + <&str as Into>::into("Unexpected error while encoding object.") + .add_context(e.to_string().as_str()); + Err(err) } - _ => panic!("Unexpected error while encoding object: {:?}", e), }, } } diff --git a/copper_log_runtime/Cargo.toml b/copper_log_runtime/Cargo.toml index a016f2673..cc5410245 100644 --- a/copper_log_runtime/Cargo.toml +++ b/copper_log_runtime/Cargo.toml @@ -5,11 +5,12 @@ edition = "2021" [dependencies] copper-value = { path = "../copper_value" } -lazy_static = "1.4.0" +copper-traits = { path = "../copper_traits" } serde = { version = "1.0.202", features = ["derive"] } bincode = { version = "2.0.0-rc.3", features = ["serde"] } bincode_derive = "2.0.0-rc.3" pretty-hex = "0.4.1" ctor = "0.2.8" ctrlc = { version = "3.4.4", features = ["termination"] } -kanal = { version = "0.1.0-pre8" } \ No newline at end of file +kanal = { version = "0.1.0-pre8" } +once_cell = "1.19.0" \ No newline at end of file diff --git a/copper_log_runtime/src/lib.rs b/copper_log_runtime/src/lib.rs index d7f48fb6d..ca9a11875 100644 --- a/copper_log_runtime/src/lib.rs +++ b/copper_log_runtime/src/lib.rs @@ -1,15 +1,18 @@ use bincode::enc::write::Writer; use bincode_derive::{Decode, Encode}; +use copper_traits::{CuResult, Stream}; pub use copper_value as value; // Part of the API, do not remove. use copper_value::Value; use kanal::{bounded, Sender}; -use lazy_static::lazy_static; -use pretty_hex::pretty_hex; +use once_cell::sync::OnceCell; use std::fmt::Display; use std::io::{stdout, Write}; use std::sync::{Arc, Mutex}; use std::thread; +// The logging system is basically a global queue. +static QUEUE: OnceCell> = OnceCell::new(); + #[allow(dead_code)] pub const ANONYMOUS: u32 = 0; @@ -45,21 +48,22 @@ impl CuLogEntry { } } -lazy_static! { - static ref QUEUE: Sender = initialize_queue(); -} - /// The lifetime of this struct is the lifetime of the logger. pub struct LoggerRuntime {} impl LoggerRuntime { - pub fn init() -> Self { - lazy_static::initialize(&QUEUE); + pub fn init(destination: impl Stream + 'static) -> Self { + QUEUE + .set(initialize_queue(destination)) + .expect("Failed to initialize the logger queue."); LoggerRuntime {} } pub fn close(&self) { - QUEUE.close(); + QUEUE + .get() + .expect("Logger Runtime closed before beeing open.") + .close(); } } @@ -69,14 +73,13 @@ impl Drop for LoggerRuntime { } } -fn initialize_queue() -> Sender { +fn initialize_queue(mut destination: impl Stream + 'static) -> Sender { let (sender, receiver) = bounded::(100); let config = bincode::config::standard(); let handle = thread::spawn(move || loop { if let Ok(data) = receiver.recv() { - let binary = bincode::encode_to_vec(&data, config).unwrap(); - println!("{}", pretty_hex(&binary.as_slice())); + destination.log(&data); } else { break; } @@ -97,16 +100,12 @@ fn initialize_queue() -> Sender { /// Function called from generated code to log data. #[inline] -pub fn log(entry: CuLogEntry) { - // If the queue is closed, we just drop the data. - if QUEUE.send(entry).is_err() { - if !QUEUE.is_closed() { - eprintln!("Copper: Failed to send data to the logger, some data got dropped."); - if QUEUE.is_full() { - eprintln!( - "Copper: The logger queue is full, consider increasing the size of the queue." - ); - } - } +pub fn log(entry: CuLogEntry) -> CuResult<()> { + if let Some(queue) = QUEUE.get() { + queue + .send(entry) + .map_err(|_| "Failed to send data to the logger.".into()) + } else { + Err("Logger not initialized.".into()) } } diff --git a/copper_log_test/Cargo.toml b/copper_log_test/Cargo.toml index 9c1d3fd6c..2919df19e 100644 --- a/copper_log_test/Cargo.toml +++ b/copper_log_test/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" copper = { path = "../copper" } copper-log = { path = "../copper_log" } copper-log-runtime = { path = "../copper_log_runtime" } +copper-datalogger = { path = "../copper_datalogger" } copper-value = { path = "../copper_value" } serde = { version = "1.0.202", features = ["derive"] } diff --git a/copper_log_test/src/main.rs b/copper_log_test/src/main.rs index 68adc8ac6..66ce667ca 100644 --- a/copper_log_test/src/main.rs +++ b/copper_log_test/src/main.rs @@ -1,10 +1,18 @@ +use copper_datalogger::{stream, DataLogger, EntryType}; use copper_log::debug; use copper_log_runtime::LoggerRuntime; use copper_value::to_value; use serde::Serialize; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; fn main() { - let rt = LoggerRuntime {}; + let path: PathBuf = PathBuf::from("/tmp/teststructlog.copper"); + let data_logger = Arc::new(Mutex::new( + DataLogger::new(path.as_path(), Some(100000)).expect("Failed to create logger"), + )); + let mut stream = stream(data_logger.clone(), EntryType::StructuredLogLine, 1024); + let rt = LoggerRuntime::init(stream); #[derive(Serialize)] struct Test { a: i32, diff --git a/copper_traits/Cargo.toml b/copper_traits/Cargo.toml new file mode 100644 index 000000000..53db7509d --- /dev/null +++ b/copper_traits/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "copper-traits" +version = "0.1.0" +edition = "2021" + +[dependencies] +bincode = "2.0.0-rc.3" \ No newline at end of file diff --git a/copper_traits/src/lib.rs b/copper_traits/src/lib.rs new file mode 100644 index 000000000..9eb76e772 --- /dev/null +++ b/copper_traits/src/lib.rs @@ -0,0 +1,56 @@ +use bincode::Encode; +use std::error::Error; +use std::fmt::{Display, Formatter}; + +/// Common copper Error type. +#[derive(Debug)] +pub struct CuError { + message: String, + context: Option, +} + +impl Display for CuError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let context_str = match &self.context { + Some(c) => format!("{}", c), + None => "None".to_string(), + }; + write!(f, "{}\n context:{}", self.message, context_str)?; + Ok(()) + } +} + +impl Error for CuError {} + +impl From<&str> for CuError { + fn from(s: &str) -> CuError { + CuError { + message: s.to_string(), + context: None, + } + } +} + +impl From for CuError { + fn from(s: String) -> CuError { + CuError { + message: s, + context: None, + } + } +} + +impl CuError { + pub fn add_context(mut self, context: &str) -> CuError { + self.context = Some(context.into()); + self + } +} + +// Generic Result type for copper. +pub type CuResult = Result; + +/// Defines a basic write, append only stream trait to be able to log or send serializable objects. +pub trait Stream: Sync + Send { + fn log(&mut self, obj: &impl Encode) -> CuResult<()>; +}