1use heapless::spsc::Queue;
208use once_cell::unsync::{Lazy, OnceCell};
209use quanta::Instant;
210use serialize::buffer::{Buffer, BUFFER};
211use std::fmt::Display;
212
213use quicklog_clock::{quanta::QuantaClock, Clock};
214use quicklog_flush::{file_flusher::FileFlusher, Flush};
215
216pub mod level;
218pub mod macros;
220pub mod serialize;
222
223include!("constants.rs");
224pub mod constants;
226
227#[doc(hidden)]
231pub type Intermediate = (Instant, Box<dyn Display>);
232
233#[doc(hidden)]
235static mut LOGGER: Lazy<Quicklog> = Lazy::new(Quicklog::default);
236
237pub type Sender = heapless::spsc::Producer<'static, Intermediate, MAX_LOGGER_CAPACITY>;
239pub type SendResult = Result<(), Intermediate>;
241pub type Receiver = heapless::spsc::Consumer<'static, Intermediate, MAX_LOGGER_CAPACITY>;
243pub type RecvResult = Result<(), FlushError>;
245
246static mut SENDER: OnceCell<Sender> = OnceCell::new();
248static mut RECEIVER: OnceCell<Receiver> = OnceCell::new();
250
251pub trait Log {
254 fn flush_one(&mut self) -> RecvResult;
256 fn log(&self, display: Box<dyn Display>) -> SendResult;
258}
259
260#[derive(Debug)]
262pub enum FlushError {
263 Empty,
265}
266
267#[doc(hidden)]
271pub fn logger() -> &'static mut Quicklog {
272 unsafe { &mut LOGGER }
273}
274
275pub struct Quicklog {
277 flusher: Box<dyn Flush>,
278 clock: Box<dyn Clock>,
279}
280
281impl Quicklog {
282 #[doc(hidden)]
284 pub fn use_flush(&mut self, flush: Box<dyn Flush>) {
285 self.flusher = flush
286 }
287
288 #[doc(hidden)]
290 pub fn use_clock(&mut self, clock: Box<dyn Clock>) {
291 self.clock = clock
292 }
293
294 pub fn init() {
297 Quicklog::init_channel();
298 Quicklog::init_buffer();
299 }
300
301 fn init_buffer() {
303 unsafe {
304 BUFFER.set(Buffer::new()).ok();
305 }
306 }
307
308 fn init_channel() {
310 static mut QUEUE: Queue<Intermediate, MAX_LOGGER_CAPACITY> = Queue::new();
311 let (sender, receiver): (Sender, Receiver) = unsafe { QUEUE.split() };
312 unsafe {
313 SENDER.set(sender).ok();
314 RECEIVER.set(receiver).ok();
315 }
316 }
317}
318
319impl Default for Quicklog {
320 fn default() -> Self {
321 Quicklog {
322 flusher: Box::new(FileFlusher::new("logs/quicklog.log")),
323 clock: Box::new(QuantaClock::new()),
324 }
325 }
326}
327
328impl Log for Quicklog {
329 fn log(&self, display: Box<dyn Display>) -> SendResult {
330 match unsafe {
331 SENDER
332 .get_mut()
333 .expect("Sender is not initialized, `Quicklog::init()` needs to be called at the entry point of your application")
334 .enqueue((self.clock.get_instant(), display))
335 } {
336 Ok(_) => Ok(()),
337 Err(err) => Err(err),
338 }
339 }
340
341 fn flush_one(&mut self) -> RecvResult {
342 match unsafe {
343 RECEIVER
344 .get_mut()
345 .expect("RECEIVER is not initialized, `Quicklog::init()` needs to be called at the entry point of your application")
346 .dequeue()
347 } {
348 Some((time_logged, disp)) => {
349 let log_line = format!(
350 "[{:?}]{}\n",
351 self.clock
352 .compute_system_time_from_instant(time_logged)
353 .expect("Unable to get time from instant"),
354 disp
355 );
356 self.flusher.flush_one(log_line);
357 Ok(())
358 }
359 None => Err(FlushError::Empty),
360 }
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use std::{str::from_utf8, sync::Mutex};
367
368 use quicklog_flush::Flush;
369
370 use crate::{
371 debug, error, flush, info,
372 serialize::{Serialize, Store},
373 trace, warn,
374 };
375
376 struct VecFlusher {
377 pub vec: &'static mut Vec<String>,
378 }
379
380 impl VecFlusher {
381 pub fn new(vec: &'static mut Vec<String>) -> VecFlusher {
382 VecFlusher { vec }
383 }
384 }
385
386 impl Flush for VecFlusher {
387 fn flush_one(&mut self, display: String) {
388 self.vec.push(display);
389 }
390 }
391
392 #[derive(Clone, Debug)]
393 struct Something {
394 some_str: &'static str,
395 }
396
397 fn message_from_log_line(log_line: &str) -> String {
398 log_line
399 .split('\t')
400 .last()
401 .map(|s| s.chars().take(s.len() - 1).collect::<String>())
402 .unwrap()
403 }
404
405 fn message_and_level_from_log_line(log_line: &str) -> String {
406 let timestamp_end_idx = log_line.find(']').unwrap() + 1;
407 log_line
408 .chars()
409 .skip(timestamp_end_idx)
410 .take(log_line.len() - timestamp_end_idx - 1)
411 .collect::<String>()
412 }
413
414 static TEST_LOCK: Mutex<usize> = Mutex::new(0);
418
419 macro_rules! setup {
420 () => {
421 let mut guard = TEST_LOCK.lock().unwrap();
423 if *guard == 0 {
424 crate::init!();
425 *guard += 1;
426 }
427 static mut VEC: Vec<String> = Vec::new();
428 let vec_flusher = unsafe { VecFlusher::new(&mut VEC) };
429 crate::logger().use_flush(Box::new(vec_flusher));
430 };
431 }
432
433 fn from_log_lines<F: Fn(&str) -> String>(lines: &[String], f: F) -> Vec<String> {
434 lines.iter().map(|s| f(s.as_str())).collect::<Vec<_>>()
435 }
436
437 #[doc(hidden)]
438 macro_rules! helper_assert {
439 (@ $f:expr, $format_string:expr, $check_f:expr) => {
440 $f;
441 flush!();
442 assert_eq!(
443 unsafe { from_log_lines(&VEC, $check_f) },
444 vec![$format_string]
445 );
446 unsafe {
447 let _ = &VEC.clear();
448 }
449 };
450 }
451
452 macro_rules! assert_message_equal {
453 ($f:expr, $format_string:expr) => { helper_assert!(@ $f, $format_string, message_from_log_line) };
454 }
455
456 macro_rules! assert_message_with_level_equal {
457 ($f:expr, $format_string:expr) => { helper_assert!(@ $f, $format_string, message_and_level_from_log_line) };
458 }
459
460 #[derive(Clone, Debug)]
461 struct NestedSomething {
462 thing: Something,
463 }
464
465 impl std::fmt::Display for Something {
466 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
467 write!(f, "Something display: {}", self.some_str)
468 }
469 }
470
471 #[test]
472 fn has_all_levels() {
473 setup!();
474
475 assert_message_with_level_equal!(
476 trace!("Hello world {}", "Another"),
477 format!("[TRACE]\tHello world {}", "Another")
478 );
479 assert_message_with_level_equal!(
480 debug!("Hello world {}", "Another"),
481 format!("[DEBUG]\tHello world {}", "Another")
482 );
483 assert_message_with_level_equal!(
484 info!("Hello world {}", "Another"),
485 format!("[INFO]\tHello world {}", "Another")
486 );
487 assert_message_with_level_equal!(
488 warn!("Hello world {}", "Another"),
489 format!("[WARN]\tHello world {}", "Another")
490 );
491 assert_message_with_level_equal!(
492 error!("Hello world {}", "Another"),
493 format!("[ERROR]\tHello world {}", "Another")
494 );
495 }
496
497 #[test]
498 fn works_in_closure() {
499 setup!();
500
501 let s1 = Something {
502 some_str: "Hello world 1",
503 };
504 let s2 = Something {
505 some_str: "Hello world 2",
506 };
507
508 let f = || {
509 assert_message_equal!(
510 info!("Hello world {} {:?}", s1, s2),
511 format!("Hello world {} {:?}", s1, s2)
512 );
513 };
514
515 f();
516 }
517
518 #[test]
519 fn works_with_attributes() {
520 setup!();
521
522 let s1 = Something {
523 some_str: "Hello world 1",
524 };
525 let s2 = Something {
526 some_str: "Hello world 2",
527 };
528 let nested = NestedSomething {
529 thing: Something {
530 some_str: "hello nested",
531 },
532 };
533
534 assert_message_equal!(
535 info!("log one attr {}", nested.thing.some_str),
536 format!("log one attr {}", nested.thing.some_str)
537 );
538 assert_message_equal!(
539 info!("hello world {} {:?}", s1.some_str, s2.some_str),
540 format!("hello world {} {:?}", s1.some_str, s2.some_str)
541 );
542 }
543
544 #[test]
545 fn works_with_box_ref() {
546 setup!();
547
548 let s1 = Box::new(Something {
549 some_str: "Hello world 1",
550 });
551 let s2 = Box::new(Something {
552 some_str: "Hello world 2",
553 });
554
555 assert_message_equal!(
556 info!("log single box ref {}", s1.as_ref()),
557 format!("log single box ref {}", s1.as_ref())
558 );
559 assert_message_equal!(
560 info!("log multi box ref {} {:?}", s1.as_ref(), s2.as_ref()),
561 format!("log multi box ref {} {:?}", s1.as_ref(), s2.as_ref())
562 );
563 }
564
565 #[test]
566 fn works_with_move() {
567 setup!();
568
569 let s1 = Something {
570 some_str: "Hello world 1",
571 };
572 let s2 = Something {
573 some_str: "Hello world 2",
574 };
575 let s3 = Something {
576 some_str: "Hello world 3",
577 };
578
579 assert_message_equal!(
580 info!("log multi move {} {:?}", s1, s2),
581 format!("log multi move {} {:?}", s1, s2)
582 );
583 assert_message_equal!(
584 info!("log single move {}", s3),
585 format!("log single move {}", s3)
586 );
587 }
588
589 #[test]
590 fn works_with_references() {
591 setup!();
592
593 let s1 = Something {
594 some_str: "Hello world 1",
595 };
596 let s2 = Something {
597 some_str: "Hello world 2",
598 };
599
600 assert_message_equal!(
601 info!("log single ref: {}", &s1),
602 format!("log single ref: {}", &s1)
603 );
604 assert_message_equal!(
605 info!("log multi ref: {} {:?}", &s1, &s2),
606 format!("log multi ref: {} {:?}", &s1, &s2)
607 );
608 }
609
610 fn log_multi_ref_helper(thing: &Something, thing2: &Something) {
611 info!("log multi ref {} {:?}", thing, thing2);
612 }
613
614 fn log_ref_helper(thing: &Something) {
615 info!("log single ref: {}", thing)
616 }
617
618 #[test]
619 fn works_with_ref_lifetime_inside_fn() {
620 setup!();
621
622 let s1 = Something {
623 some_str: "Hello world 1",
624 };
625 let s2 = Something {
626 some_str: "Hello world 2",
627 };
628
629 assert_message_equal!(log_ref_helper(&s1), format!("log single ref: {}", &s1));
630 assert_message_equal!(
631 log_multi_ref_helper(&s2, &s1),
632 format!("log multi ref {} {:?}", &s2, &s1)
633 );
634 }
635
636 #[derive(Clone)]
637 struct A {
638 price: u64,
639 symbol: &'static str,
640 exch_id: u64,
641 }
642
643 impl A {
644 fn get_price(&self) -> u64 {
645 self.price
646 }
647
648 fn get_exch_id(&self) -> u64 {
649 self.exch_id
650 }
651
652 fn get_symbol(&self) -> &'static str {
653 self.symbol
654 }
655 }
656
657 #[test]
658 fn works_with_fn_return_val() {
659 setup!();
660
661 let a = A {
662 price: 1_521_523,
663 symbol: "SomeSymbol",
664 exch_id: 642_153_768,
665 };
666
667 assert_message_equal!(
668 info!(
669 "A: price: {} symbol: {} exch_id: {}",
670 a.get_price(),
671 ?a.get_symbol(),
672 %a.get_exch_id()
673 ),
674 format!(
675 "A: price: {} symbol: \"{}\" exch_id: {:?}",
676 a.get_price(),
677 a.get_symbol(),
678 a.get_exch_id()
679 )
680 );
681 assert_message_equal!(
682 info!("single call {}", a.get_price()),
683 format!("single call {}", a.get_price())
684 );
685 }
686
687 fn log_ref_and_move(s1: Something, s2r: &Something) {
688 info!("Hello world {} {:?}", s1, s2r);
689 }
690
691 #[test]
692 fn works_with_ref_and_move() {
693 setup!();
694
695 let s1 = Something {
696 some_str: "Hello world 1",
697 };
698 let s1_clone = s1.clone();
699 let s2 = Something {
700 some_str: "Hello world 2",
701 };
702
703 assert_message_equal!(
704 log_ref_and_move(s1, &s2),
705 format!("Hello world {} {:?}", s1_clone, &s2)
706 );
707 let s3 = Something {
708 some_str: "Hello world 3",
709 };
710 let s4 = Something {
711 some_str: "Hello world 4",
712 };
713
714 assert_message_equal!(
715 info!("ref: {:?}, move: {}", &s2, s3),
716 format!("ref: {:?}, move: {}", &s2, s3)
717 );
718 assert_message_equal!(info!("single ref: {}", &s2), format!("single ref: {}", &s2));
719 assert_message_equal!(info!("single move: {}", s4), format!("single move: {}", s4));
720 }
721
722 #[test]
723 fn works_with_eager_debug_display_hints() {
724 setup!();
725
726 let s1 = Something {
727 some_str: "Hello world 1",
728 };
729 let s2 = Something {
730 some_str: "Hello world 2",
731 };
732 let some_str = "hello world";
733
734 assert_message_equal!(
735 info!("display {}; eager debug {}; eager display {}, eager display inner field {}", some_str, ?s2, %s1, %s1.some_str),
736 format!(
737 "display {}; eager debug {:?}; eager display {}, eager display inner field {}",
738 some_str, s2, s1, s1.some_str
739 )
740 );
741 assert_message_equal!(
742 info!("single eager display: {}", %s2),
743 format!("single eager display: {}", s2)
744 );
745 }
746
747 #[test]
748 fn works_with_fields() {
749 setup!();
750
751 let s1 = Something {
752 some_str: "Hello world 1",
753 };
754 let s2 = Something {
755 some_str: "Hello world 1",
756 };
757 let s3 = Something {
758 some_str: "Hello world 3",
759 };
760 let s3_clone = s3.clone();
761
762 assert_message_equal!(
763 info!("pass by ref {}", some_struct.field1.innerfield.inner = &s1),
764 format!("pass by ref some_struct.field1.innerfield.inner={}", &s1)
765 );
766 assert_message_equal!(
767 info!("pass by move {}", some.inner.field = s3),
768 format!("pass by move some.inner.field={}", s3_clone)
769 );
770 assert_message_equal!(
771 info!(
772 "non-nested field: {}, nested field: {}, pure lit: {}",
773 borrow_s2_field = %s2,
774 some_inner_field.inner.field.inner.arg = "hello world",
775 "pure lit arg" = "another lit arg"
776 ),
777 format!("non-nested field: borrow_s2_field={}, nested field: some_inner_field.inner.field.inner.arg=hello world, pure lit: pure lit arg=another lit arg", &s2)
778 );
779 assert_message_equal!(
780 info!(
781 "pure lit: {}, reuse debug: {}, nested field: {}, able to reuse after pass by ref: {}",
782 "pure lit arg" = "another lit arg",
783 "able to reuse s1" = ?s1,
784 some_inner_field.some.field.included = "hello world",
785 able.to.reuse.s2.borrow = &s2
786 ),
787 format!("pure lit: pure lit arg=another lit arg, reuse debug: able to reuse s1={:?}, nested field: some_inner_field.some.field.included=hello world, able to reuse after pass by ref: able.to.reuse.s2.borrow={}", s1, &s2)
788 );
789 }
790
791 struct S {
792 symbol: String,
793 }
794
795 impl Serialize for S {
796 fn encode(&self, write_buf: &'static mut [u8]) -> Store {
797 fn decode(read_buf: &[u8]) -> String {
798 let x = from_utf8(read_buf).unwrap();
799 x.to_string()
800 }
801 write_buf.copy_from_slice(self.symbol.as_bytes());
802 Store::new(decode, write_buf)
803 }
804
805 fn buffer_size_required(&self) -> usize {
806 self.symbol.len()
807 }
808 }
809
810 #[derive(Debug, Clone, Copy)]
811 struct BigStruct {
812 vec: [i32; 100],
813 some: &'static str,
814 }
815
816 impl Serialize for BigStruct {
817 fn encode(&self, write_buf: &'static mut [u8]) -> Store {
818 fn decode(buf: &[u8]) -> String {
819 let (mut _head, mut tail) = buf.split_at(0);
820 let mut vec = vec![];
821 for _ in 0..100 {
822 (_head, tail) = tail.split_at(4);
823 vec.push(i32::from_le_bytes(_head.try_into().unwrap()));
824 }
825 let s = from_utf8(tail).unwrap();
826 format!("vec: {:?}, str: {}", vec, s)
827 }
828
829 let (mut _head, mut tail) = write_buf.split_at_mut(0);
830 for i in 0..100 {
831 (_head, tail) = tail.split_at_mut(4);
832 _head.copy_from_slice(&self.vec[i].to_le_bytes())
833 }
834
835 tail.copy_from_slice(self.some.as_bytes());
836
837 Store::new(decode, write_buf)
838 }
839
840 fn buffer_size_required(&self) -> usize {
841 std::mem::size_of::<i32>() * 100 + self.some.len()
842 }
843 }
844
845 #[test]
846 fn works_with_serialize() {
847 setup!();
848
849 let s = S {
850 symbol: String::from("Hello"),
851 };
852 let bs = BigStruct {
853 vec: [1; 100],
854 some: "The quick brown fox jumps over the lazy dog",
855 };
856
857 assert_message_equal!(info!("s: {} {}", ^s, ^s), "s: Hello Hello");
858 assert_message_equal!(
859 info!("bs: {}", ^bs),
860 format!(
861 "bs: vec: {:?}, str: {}",
862 vec![1; 100],
863 "The quick brown fox jumps over the lazy dog"
864 )
865 );
866 }
867}