reactive_state/middleware/
simple_logger.rs

1//! Logging [Middleware](crate::middleware::Middleware) which uses the
2//! [log](log) macros to publish actions/events that occur within the
3//! [Store](crate::Store).
4
5use super::ReduceMiddlewareResult;
6use crate::{
7    middleware::{Middleware, ReduceFn},
8    Store,
9};
10use std::{fmt::Debug, hash::Hash};
11
12pub enum LogLevel {
13    Trace,
14    Debug,
15    Warn,
16    Info,
17}
18
19impl LogLevel {
20    pub fn log<S: AsRef<str>>(&self, message: S) {
21        match self {
22            LogLevel::Trace => log::trace!("{}", message.as_ref()),
23            LogLevel::Debug => log::debug!("{}", message.as_ref()),
24            LogLevel::Warn => log::warn!("{}", message.as_ref()),
25            LogLevel::Info => log::info!("{}", message.as_ref()),
26        }
27    }
28}
29
30impl Default for LogLevel {
31    fn default() -> Self {
32        LogLevel::Debug
33    }
34}
35
36/// Logging [Middleware](crate::middleware::Middleware) which uses the
37/// [log](log) macros to publish actions/events that occur within the
38/// [Store](crate::Store).
39///
40/// See [simple_logger](super::simple_logger) for more details.
41pub struct SimpleLoggerMiddleware {
42    log_level: LogLevel,
43}
44
45impl SimpleLoggerMiddleware {
46    pub fn new() -> Self {
47        SimpleLoggerMiddleware {
48            log_level: LogLevel::default(),
49        }
50    }
51
52    pub fn log_level(mut self, log_level: LogLevel) -> Self {
53        self.log_level = log_level;
54        self
55    }
56}
57
58impl Default for SimpleLoggerMiddleware {
59    fn default() -> Self {
60        SimpleLoggerMiddleware::new()
61    }
62}
63
64impl<State, Action, Event, Effect> Middleware<State, Action, Event, Effect>
65    for SimpleLoggerMiddleware
66where
67    Event: Clone + Hash + Eq + Debug,
68    State: Debug,
69    Action: Debug,
70    Effect: Debug,
71{
72    fn on_reduce(
73        &self,
74        store: &Store<State, Action, Event, Effect>,
75        action: Option<&Action>,
76        reduce: ReduceFn<State, Action, Event, Effect>,
77    ) -> ReduceMiddlewareResult<Event, Effect> {
78        let was_action = match &action {
79            Some(action) => {
80                self.log_level
81                    .log(format!("prev state: {:?}", store.state()));
82                self.log_level.log(format!("action: {:?}", action));
83                true
84            }
85            None => {
86                self.log_level.log("action: None");
87                false
88            }
89        };
90
91        let events = reduce(store, action);
92
93        if was_action {
94            self.log_level
95                .log(format!("next state: {:?}", store.state()));
96        }
97
98        events
99    }
100
101    fn process_effect(
102        &self,
103        _store: &Store<State, Action, Event, Effect>,
104        effect: Effect,
105    ) -> Option<Effect> {
106        self.log_level.log(format!("effect: {:?}", effect));
107        Some(effect)
108    }
109
110    fn on_notify(
111        &self,
112        store: &Store<State, Action, Event, Effect>,
113        events: Vec<Event>,
114        notify: super::NotifyFn<State, Action, Event, Effect>,
115    ) -> Vec<Event> {
116        for event in &events {
117            self.log_level.log(format!("event: {:?}", event));
118        }
119
120        notify(store, events)
121    }
122}