Skip to content

Commit

Permalink
Added support for re-dash-inspector in the debug interceptor (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
wkok authored Sep 23, 2024
1 parent 0696f07 commit 2db1a71
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 65 deletions.
12 changes: 10 additions & 2 deletions doc/02-debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ Providing an options map we can add / remove some logging detail:
- `:stats?` Default `false`. Include basic timed statistics for the event execution.
- `:target` Default `:target/console`. Logging target, one of
- `:target/console` - Standard out
- `:target/dev-tools` - (Experimental) Flutter [DevTools logging view](https://docs.flutter.dev/tools/devtools/logging), with Kind `re-dash`
- `:target/everywhere` - Log to both console and Flutter DevTools (experimental)
- `:target/dev-tools` - Send to the [re-dash-inspector](https://github.com/htihospitality/re-dash-inspector)
- `:target/everywhere` - Send to both console and the [re-dash-inspector](https://github.com/htihospitality/re-dash-inspector)

With all the options enabled:

Expand Down Expand Up @@ -114,3 +114,11 @@ Add this somewhere early on in your app's startup, like in `main`
(rd/reg-global-interceptor
(rd/debug))
```

### Performance

The `debug` interceptor will only do anything when the app is running in debug mode, ie. [kDebugMode](https://api.flutter.dev/flutter/foundation/kDebugMode-constant.html) has to be true.

When the target is `:target/dev-tools` the [re-dash-inspector](https://github.com/htihospitality/re-dash-inspector) has to have an active connection to re-dash before events will be sent.

If neither of the above is true, the `debug` interceptor is effectively a no-op & will have no impact on app performance.
162 changes: 99 additions & 63 deletions src/hti/re_dash/debugging.cljd
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
(ns hti.re-dash.debugging
(:require ["dart:developer" :as dev]
["dart:convert" :as c]
["package:flutter/foundation.dart" :as ff]
[clojure.data :as data]
[clojure.string :as string]
[hti.re-dash.interceptors :as interceptors]))
[hti.re-dash.interceptors :as interceptors]
[clojure.walk :as w]))

(defonce debug-state (atom {}))

(defn sanitize
"Transforms all un-serializable map values with placeholders."
[m]
(w/postwalk
(fn [element]
(if (map-entry? element)
(let [[key val] element]
[key

(cond

;; Functions not de-serializable by cljd.reader
(fn? val) 'closure

:else val)])
element))
m))

(defn- log-console!
[{:keys [event-id started finished duration event-args diff
[{:keys [event-id started finished duration event-args db-before db-after
diff? stats? args?]
:or {diff? true
stats? false
Expand All @@ -30,12 +51,13 @@
"### Event Args:"
event-args])
(when diff?
["-----------------------------------------------"
"### DB Diff Before (Removed):"
(or (first diff) {})
"-----------------------------------------------"
"### DB Diff After (Added):"
(or (second diff) {})])
(let [diff (when db-after (data/diff db-before db-after))]
["-----------------------------------------------"
"### DB Diff Before (Removed):"
(or (first diff) {})
"-----------------------------------------------"
"### DB Diff After (Added):"
(or (second diff) {})]))
["###############################################"
"\r\n"])
flatten
Expand All @@ -44,67 +66,81 @@

(str "Event: " event-id))))

(defn- inspect-dev-tools!
"Sends a serialized db value to the re-dash-inspector DevTools extension"
[{:keys [event-id db-after]}]

(defn- log-dev-tools!
[{:keys [event-id diff event-args started finished duration
diff? stats? args?]
:or {diff? true
stats? false
args? false}}]
(when (and ff/kDebugMode (:re-dash/inspector-connected? @debug-state))
(dev/postEvent "re-dash"
{"event-id" (pr-str event-id)
"db" (-> db-after
sanitize
pr-str)})))

(defn- register-inspector
"Registers the re-dash-inspector listener to
react to connect/disconnect events"
[target]
(when (and (#{:target/dev-tools :target/everywhere} target)
(not (:re-dash/inspector-registered? @debug-state)))

(dev/registerExtension
"ext.re-dash-inspector.updateConnectionState"
(fn [_method {:strs [action]}]
(condp = action
"connect" (do (swap! debug-state assoc :re-dash/inspector-connected? true)
(Future.value (dev/ServiceExtensionResponse.result "connected")))
"disconnect" (do (swap! debug-state assoc :re-dash/inspector-connected? false)
(Future.value (dev/ServiceExtensionResponse.result "disconnected"))))))

(dev/log (str "Event: " event-id)
.name "re-dash"
.error (cond-> {}
diff? (assoc :db {:before (or (first diff) {})
:after (or (second diff) {})})
args? (assoc :args event-args)
stats? (assoc :stats {:started started
:finished finished
:duration duration}))))
(swap! debug-state assoc :re-dash/inspector-registered? true)))


(defn debug
[{:keys [target]
:or {target :target/console}
:as options}]

(interceptors/->interceptor

:re-dash/debug

(fn before [context]
(assoc context :debug {:started (DateTime/now)
:db (-> context :coeffects :db)}))

(fn after [context]
(let [event-id (-> context :coeffects :event first)
event-args (-> context :coeffects :event rest)
started (-> context :debug :started)
finished (DateTime/now)
duration (.difference finished started)
db-before (-> context :debug :db)
db-after (-> context :effects :db)
diff (when db-after
(data/diff db-before db-after))
log-args (merge
{:event-id event-id
:started started
:finished finished
:duration duration
:event-args event-args
:diff diff}
options)]

(condp = target

:target/console
(log-console! log-args)

:target/dev-tools
(log-dev-tools! log-args)

:target/everywhere
(do (log-console! log-args)
(log-dev-tools! log-args))))

context)))
(when ff/kDebugMode

(register-inspector target)

(interceptors/->interceptor

:re-dash/debug

(fn before [context]
(assoc context :debug {:started (DateTime/now)
:db (-> context :coeffects :db)}))

(fn after [context]
(let [event-id (-> context :coeffects :event first)
event-args (-> context :coeffects :event rest)
started (-> context :debug :started)
finished (DateTime/now)
duration (.difference finished started)
db-before (-> context :debug :db)
db-after (-> context :effects :db)
log-args (merge
{:event-id event-id
:started started
:finished finished
:duration duration
:event-args event-args
:db-before db-before
:db-after db-after}
options)]

(condp = target

:target/console
(log-console! log-args)

:target/dev-tools
(inspect-dev-tools! log-args)

:target/everywhere
(do (log-console! log-args)
(inspect-dev-tools! log-args))))

context))))

0 comments on commit 2db1a71

Please sign in to comment.