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
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
extern crate alloc;

use slog::{info, o, error};
use crate::{FsmBackend, FsmBackendImpl, FsmEvent, Inspect, InspectEvent, InspectFsmEvent};
use crate::lib::*;
use AsRef;
use core::fmt::Debug;
use core::any::Any;
use alloc::string::ToString;
use alloc::format;

pub struct InspectSlog {
    pub logger: slog::Logger
}

impl InspectSlog {
    pub fn new(logger: Option<slog::Logger>) -> Self {
        InspectSlog {
            logger: logger.unwrap_or(slog::Logger::root(slog::Discard, o!()))
        }
    }
}

impl Inspect for InspectSlog
{
    fn new_event<F: FsmBackend>(&self, event: &FsmEvent<<F as FsmBackend>::Events, <F as FsmBackend>::Timers>, fsm: &FsmBackendImpl<F>) -> Self {
        let event_display = match event {
            FsmEvent::Timer(t) => format!("Fsm::Timer({:?})", t),
            _ => event.as_ref().to_string()
        };

        let current_state = format!("{:?}", fsm.get_current_states());

        let kv = o!("event" => event_display, "start_state" => current_state);
        info!(self.logger, "Dispatching"; &kv);
        InspectSlog {
            logger: self.logger.new(kv)
        }
    }

    fn for_transition<T>(&self) -> Self {
        let transition = type_name::<T>();
        let kv = o!("transition" => transition);
        info!(self.logger, "Matched transition"; &kv);
        InspectSlog {
            logger: self.logger.new(kv)
        }
    }
 
    fn for_sub_machine<FSub: FsmBackend>(&self) -> Self {
        let sub_fsm = type_name::<FSub>();
        let kv = o!("sub_fsm" => sub_fsm);
        info!(self.logger, "Dispatching to a submachine"; &kv);
        InspectSlog {
            logger: self.logger.new(kv)
        }
    }

    fn for_timer<F>(&self, timer_id: <F as FsmBackend>::Timers) -> Self where F: FsmBackend {
        let kv = o!("timer_id" => format!("{:?}", timer_id));
        InspectSlog {
            logger: self.logger.new(kv)
        }
    }    

    fn on_guard<T>(&self, guard_result: bool) {
        let guard = type_name::<T>();
        info!(self.logger, "Guard {guard} evaluated to {guard_result}", guard = guard, guard_result = guard_result);
    }

    fn on_state_enter<S>(&self) {
        let state = type_name::<S>();
        info!(self.logger, "Entering {state}", state = state);
    }

    fn on_state_exit<S>(&self) {
        let state = type_name::<S>();
        info!(self.logger, "Exiting {state}", state = state);
    }

    fn on_action<S>(&self) {
        let action = type_name::<S>();
        info!(self.logger, "Executing {action}", action = action);
    }

    fn event_done<F: FsmBackend>(self, fsm: &FsmBackendImpl<F>) {
        let states = format!("{:?}", fsm.get_current_states());
        info!(self.logger, "Dispatch done"; "stop_state" => states);
    }

    fn on_error<E>(&self, msg: &str, error: &E) where E: Debug {
        let kv = o!("error" => format!("{:?}", error));
        error!(self.logger, "{}", msg; kv);
    }

    fn info(&self, msg: &str) {
        info!(self.logger, "{}", msg);
    }
}

impl InspectEvent for InspectSlog
{
    fn on_event<S: Any + Debug + Clone>(&self, event: &InspectFsmEvent<S>) {
        info!(self.logger, "Inspection event {:?}", event);
    }
}