nandi/frqpublic Fork 0
015500d33df581fb4cdcb21c053865b3dfa47e91
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

A browser has no socket, and three places that assumed one did 30d5fae · on 015500d33df581fb4cdcb21c053865b3dfa47e91 · nandi · 2d ago
debug.cljd · 67 lines · 3.1 KBMySQL Blame HistoryRaw
 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
(ns frq.debug
  "A line of diagnostics from a running Flutter build, to a file.

  Nothing else here reaches you. `print` is `cljd.core/print` and writes to
  `*out*`, which is nowhere at all in a compiled bundle; `dart:developer`'s
  `log` — what `frq.net.dart` uses, and what its comment claims reaches a
  terminal under `just flutter-desktop` — goes to the VM service, so it too
  is silent when the bundle is launched directly, which is what that recipe
  does. Both were tried first, and both looked exactly like the code never
  running. A file is the one sink that cannot be swallowed by whoever is
  holding stdout.

  Off unless `FRQ_JOT` names a path, so a `jot!` left in a hot build path
  costs one `getenv`-backed deref and nothing else. The file is appended to
  rather than truncated: the interesting run is usually the one after the one
  that told you what to look at.

      FRQ_JOT=/tmp/frq-jump.log just flutter-desktop run

  Written for a jump that fired, scrolled, and was silently undone in the same
  frame — see `frq.hiccup/end-ward!`. What settled it was not one line but the
  order of several from different callbacks, which is the shape of question
  this answers well: who ran, in what order, with what numbers. A debugger
  cannot ask it, because stopping the app is what makes the frame stop being
  a frame."
  (:require ["dart:io" :as io]))

(defonce ^:private sink
  ;; Read once. An env var does not change under a running app, and this is
  ;; called from inside build and post-frame callbacks.
  ;; try/catch and not a platform test: a browser has no environment at all,
  ;; and `Platform.environment` throws there rather than answering with an
  ;; empty map. Nothing is listening on the web, which is the honest answer --
  ;; and a diagnostic that took the app down with it would be the worst of the
  ;; three targets' outcomes.
  ;;
  ;; `Object` and not `Exception`, which is the whole of why this needed a
  ;; second go: what dart:io throws off-platform is `UnsupportedError`, and in
  ;; Dart an Error is not an Exception -- `on Exception catch` does not see it.
  ;; It escaped from the WebSocket's open handler, took the handler with it,
  ;; and left the connect screen spinning at "Connecting…" forever.
  (delay (try
           (let [p (get (.-environment io/Platform) "FRQ_JOT")]
             (when (and p (seq p)) p))
           (catch Object _ nil))))

(defn on?
  "Whether anything is listening, for a caller with expensive diagnostics to
  build. `jot!` asks this itself; this is for the `(when (debug/on?) ...)`
  around a string that costs something to make."
  []
  (some? @sink))

(defn jot!
  "Append one line, when `FRQ_JOT` named a file. Answers nil either way.

  Never throws: a diagnostic that takes the app down with it is worse than no
  diagnostic, and the path may be unwritable for reasons that have nothing to
  do with what is being looked at."
  [& parts]
  (when-let [path @sink]
    (try
      (.writeAsStringSync (io/File. path)
                          (str (apply str parts) "\n")
                          .mode io/FileMode.append)
      (catch Exception _ nil)))
  nil)