Logging in Suas

Suas ships with the LoggerMiddleware; a middleware implementation that logs to console whenever an action is dispatched. The logger middleware logs the action, the old state, and the new state.

Recording

We can add a logger middleware to our counter app example by passing it when creating the store.

let store = Suas.createStore(reducer: counterReducer, 
                          middleware: LoggerMiddleware())
val store = Suas.createStore(counterReducer)
                .withMiddleware(LoggerMiddleware())
                .build()
Store store = Suas.createStore(counterReducer)
        .withMiddleware(new LoggerMiddleware())
        .build();

That's it. When actions are dispatched to the store, you will get some nice logs in the console.

For the decrement action you get.

┌───→ Action: DecrementAction @16:04:05.172
├─ Prev state ► State(innerState: ["Counter": CounterExample.Counter(value: 1)])
├─ Action     ► DecrementAction(decrementValue: 1)
├─ Next state ► State(innerState: ["Counter": CounterExample.Counter(value: 0)])
└──────────────────────────────────────────

And for the increment action.

┌───→ Action: IncrementAction @16:04:04.588
├─ Prev state ► State(innerState: ["Counter": CounterExample.Counter(value: 0)])
├─ Action     ► IncrementAction(incrementValue: 1)
├─ Next state ► State(innerState: ["Counter": CounterExample.Counter(value: 1)])
└──────────────────────────────────────────

The logged message has the following anatomy:

┌───→ Action: ACTION-NAME @TIME-OF-ACTION
├─ Prev state ► CURRENT-STATE
├─ Action     ► THE-ACTION
├─ Next state ► NEW-STATE
└────────────────────────────────────────

The LoggerMiddleware provides a large set of customization options.

LoggerMiddleware(
  showTimestamp: Bool,
  showDuration: Bool,
  lineLength: Int?,
  predicate: { (State, Action) -> Bool in },
  debugOnly: Bool,
  titleFormatter: { (Action, Date, UInt64) -> String in },
  stateTransformer: { (State) -> Any in },
  actionTransformer: { (Action) -> Any in },,
  logger: { (String) in },
)
val loggerMiddleware = LoggerMiddleware.Builder()
            .withShowTimestamp(true)
            .withShowDuration(true)
            .withLineLength(120)
            .withPredicate(predicate)
            .withTitleFormatter(titleFormatter)
            .withStateTransformer(stateTransformer)
            .withActionTransformer(actionTransformer)
            .withLogAppender(logAppender)
            .build()
final Middleware loggerMiddleware = new LoggerMiddleware.Builder()
                .withShowTimestamp(true)
                .withShowDuration(true)
                .withLineLength(120)
                .withPredicate(predicate)
                .withTitleFormatter(titleFormatter)
                .withStateTransformer(stateTransformer)
                .withActionTransformer(actionTransformer)
                .withLogAppender(logAppender)
                .build();

These parameters are (all optional):

  • showTimestamp decides whether to show the timestamp or not. Defaults to true.
  • showDuration decides whether to print the duration of the action or not. Defaults to false.
  • lineLength the maximum line length. Longer lines are text wrapped. Defaults to nil to signify no max line length.
  • predicate function that decides whether to print the current state/action pair or not.
  • debugOnly should the logger print to console in release builds or not, by default it only prints in debug mode.
  • titleFormatter: function that receives the the Action, Date and Duration and returns a string to be used as the title.
  • stateTransformer: a function that receives the state and returns any new type to be printed to console. Normally you would return a textual representation of your state.
  • actionTransformer: a function that receives the action and returns any new type to be printed to console. Normally you would return a textual representation of your action.
  • logger: a function that receives the final string that is to be printed to the console. If you pass a function here, you need to print it to the console yourself.

What's Next

By using middlewares you can implement some advanced features: