From d455175044ef51d40a0e473b612c73b8ae131efc Mon Sep 17 00:00:00 2001 From: Rohan Sircar Date: Wed, 30 Dec 2020 22:47:29 +0530 Subject: [PATCH] Added odin logging + store middleware --- build.sbt | 4 +- src/main/scala/outwatchapp/MainApp.scala | 11 ++-- src/main/scala/outwatchapp/OutwatchApp.scala | 2 +- .../components/todo/TodoListStore.scala | 21 ++++---- .../util/reactive/store/Middlewares.scala | 50 +++++++++++++++++-- 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/build.sbt b/build.sbt index b403357..5c772e4 100644 --- a/build.sbt +++ b/build.sbt @@ -33,7 +33,9 @@ libraryDependencies ++= Seq( // "io.circe" %%% "circe-config" % "0.8.0", "org.akka-js" %%% "shocon" % "1.0.0", "com.beachape" %%% "enumeratum-circe" % "1.6.1", - "com.github.valskalla" %%% "odin-core" % "0.7.0+95-ab4381ae+20201227-1831-SNAPSHOT" + "com.github.valskalla" %%% "odin-core" % "0.7.0+95-ab4381ae+20201227-1831-SNAPSHOT", + "io.github.cquiroz" %%% "scala-java-time" % "2.1.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.1.0" // "com.clovellytech" %%% "outwatch-router" % "0.0.9+7-5be0b1a2+20201227-2019-SNAPSHOT" ) diff --git a/src/main/scala/outwatchapp/MainApp.scala b/src/main/scala/outwatchapp/MainApp.scala index 944f944..fa17bb9 100644 --- a/src/main/scala/outwatchapp/MainApp.scala +++ b/src/main/scala/outwatchapp/MainApp.scala @@ -4,10 +4,10 @@ import scala.concurrent.duration._ import colibri.ext.monix._ import com.softwaremill.macwire._ +import io.odin.consoleLogger import monix.bio.Task import monix.eval.Coeval import monix.reactive.Observable -import outwatchapp.ui.components.todo.TodoListStore import org.scalajs.dom.raw.Element import outwatch._ import outwatch.dsl._ @@ -15,10 +15,11 @@ import outwatch.router._ import outwatchapp.components.CounterDemo import outwatchapp.components.RequestDemo import outwatchapp.components.todo.ChartjsDemo -import outwatchapp.pages.HomePage -import outwatchapp.util.reactive.WorkerData -import outwatchapp.util.reactive.WebWorker import outwatchapp.components.todo.FusejsDemo +import outwatchapp.pages.HomePage +import outwatchapp.ui.components.todo.TodoListStore +import outwatchapp.util.reactive.WebWorker +import outwatchapp.util.reactive.WorkerData class MainApp(el: Element)(implicit backend: AppTypes.Backend, @@ -34,7 +35,7 @@ class MainApp(el: Element)(implicit for { counterDemo <- CounterDemo() chartDemo <- ChartjsDemo() - todoStore <- TodoListStore() + todoStore <- TodoListStore(consoleLogger[Task]()) requestDemo <- RequestDemo(todoStore) demoWorker <- WebWorker[WorkerData]("/worker.js") } yield { diff --git a/src/main/scala/outwatchapp/OutwatchApp.scala b/src/main/scala/outwatchapp/OutwatchApp.scala index 56a7da5..1a9a724 100644 --- a/src/main/scala/outwatchapp/OutwatchApp.scala +++ b/src/main/scala/outwatchapp/OutwatchApp.scala @@ -14,7 +14,7 @@ import scalajs.js @JSImport("bootstrap/dist/css/bootstrap.min.css", JSImport.Namespace) @js.native object BootstrapBundleCss extends js.Object -@JSImport("bootstrap", JSImport.Namespace) +@JSImport("bootstrap/dist/js/bootstrap.bundle.min.js", JSImport.Namespace) @js.native object BootstrapBundleJs extends js.Object diff --git a/src/main/scala/outwatchapp/components/todo/TodoListStore.scala b/src/main/scala/outwatchapp/components/todo/TodoListStore.scala index 9b2fdb3..3f24a5d 100644 --- a/src/main/scala/outwatchapp/components/todo/TodoListStore.scala +++ b/src/main/scala/outwatchapp/components/todo/TodoListStore.scala @@ -1,15 +1,18 @@ -package nova.monadic_sfx.ui.components.todo +package outwatchapp.ui.components.todo import scala.scalajs.js.annotation.JSExportAll import cats.kernel.Eq import com.softwaremill.quicklens._ import io.circe.generic.JsonCodec +import io.odin.Logger import monix.bio.Task -import nova.monadic_sfx.util.reactive.store.Reducer -import nova.monadic_sfx.util.reactive.store.Store +import outwatchapp.util.reactive.store.Middlewares.actionLoggerMiddleware +import outwatchapp.util.reactive.store.Reducer +import outwatchapp.util.reactive.store.Store @JSExportAll +@JsonCodec case class Todo(id: Int, content: String) object Todo { implicit val eqForTodo = Eq.fromUniversalEquals[Todo] @@ -37,18 +40,16 @@ object TodoListStore { implicit val eqForState = Eq.fromUniversalEquals[State] } - def reducer()( + def reducer(logger: Logger[Task])( state: State, action: Action ): (State, Option[Task[Action]]) = action match { case Init => (state, None) case Add(content) => - println("hello") val nextAction = Some(for { // do some validation // _ <- logger.debug(s"Received $content") - _ <- Task(println(s"Received $content")) res <- Task.pure(InternalAdd(content)) } yield res) (state, nextAction) @@ -68,19 +69,21 @@ object TodoListStore { .using(_ :+ Todo(state.counter, content)) .modify(_.counter) .using(_ + 1) - (nextState, Some(Task.pure(End))) + (nextState, Some(logger.debug(s"Received $content") >> Task.pure(End))) case End => (state, None) } - def apply(): Task[Store[Action, State]] = + def apply(logger: Logger[Task]): Task[Store[Action, State]] = Task.deferAction(implicit s => for { + logMware <- actionLoggerMiddleware[Action, State](logger, "TodoStore") store <- Store .createL[Action, State]( Init, State(Vector.empty[Todo], 0), - Reducer.withOptionalEffects(reducer() _) + Reducer.withOptionalEffects(reducer(logger) _), + Seq(logMware) ) } yield store ) diff --git a/src/main/scala/outwatchapp/util/reactive/store/Middlewares.scala b/src/main/scala/outwatchapp/util/reactive/store/Middlewares.scala index 7cecb74..1008b8f 100644 --- a/src/main/scala/outwatchapp/util/reactive/store/Middlewares.scala +++ b/src/main/scala/outwatchapp/util/reactive/store/Middlewares.scala @@ -2,11 +2,17 @@ package outwatchapp.util.reactive.store import java.time.LocalDateTime +import io.circe.Encoder import io.circe.Printer import io.circe.generic.JsonCodec -// object Middleware { -// def apply[A,M,T](ob: Observable[(A,M)], cb: (A,M) => T): Observable[(A,M)] = ob -// } +import io.circe.syntax._ +import io.odin.Logger +import io.odin.LoggerMessage +import io.odin.formatter.options.PositionFormat +import io.odin.formatter.options.ThrowableFormat +import io.odin.meta.Render +import monix.bio.Task +import monix.reactive.Observable @JsonCodec final case class StoreInfo[A]( @@ -17,6 +23,42 @@ final case class StoreInfo[A]( object StoreInfo { val printer = Printer.noSpaces + implicit def render[T: Encoder]: Render[StoreInfo[T]] = + new Render[StoreInfo[T]] { + override def render(m: StoreInfo[T]): String = printer.print(m.asJson) + } } -object Middlewares {} +object Middlewares { + + val format = create(ThrowableFormat.Default, PositionFormat.Full) + + def create( + throwableFormat: ThrowableFormat, + positionFormat: PositionFormat + ): io.odin.formatter.Formatter = (msg: LoggerMessage) => msg.message.value + + def actionStateLoggerMiddleware[A, M]( + logger: Logger[Task] + ): Task[Middleware[A, M]] = + Task.deferAction(implicit s => + Task((obs: Observable[(A, M)]) => + obs.doOnNextF { case (a, m) => + logger.debug(s"Received action $a with state $m") + } + ) + ) + + def actionLoggerMiddleware[A: Encoder, M]( + logger: Logger[Task], + name: String + ): Task[Middleware[A, M]] = + Task.deferAction(implicit s => + Task((obs: Observable[(A, M)]) => + obs.doOnNextF { case (a, _) => + Task(LocalDateTime.now()) + .flatMap(curTime => logger.debug(StoreInfo(name, a, curTime))) + } + ) + ) +}