scooter  ·  2026-04-26

Log.res

 1// hack to switch on type and render anything to string (only primitive types)
 2let _toString = (kv, key) => {
 3  switch Object.get(kv, key) {
 4  | Some(x) =>
 5    switch JSON.Classify.classify(x) {
 6    | Bool(y) => Bool.toString(y)
 7    | Null => "null"
 8    | String(y) => y
 9    | Number(y) => Float.toString(y)
10    | _ => "<invalid>"
11    }
12  | None => ""
13  }
14}
15
16// takes an object and prints it in logfmt appended to the message
17let _render = (msg: string, ~kv=Object.make()) => {
18  let keys = Object.keysToArray(kv)
19  Belt.Array.reduce(keys, msg, (out, key) => out ++ ` ${key}=${_toString(kv, key)}`)
20}
21
22// bind to vite to eliminate debug code in prod
23@val external import: 'a = "import"
24@inline
25let mode = "development"
26
27/** Debug messages to the console (only in development) */
28let debug = (msg, ~kv=?) => {
29  if import["meta"]["env"]["MODE"] === mode {
30    switch kv {
31    | Some(obj) => Console.debug(_render(msg, ~kv=obj))
32    | None => Console.debug(msg)
33    }
34  }
35}
36
37let info = (msg, ~kv=?) => {
38  switch kv {
39  | Some(obj) => Console.log(_render(msg, ~kv=obj))
40  | None => Console.log(msg)
41  }
42}
43
44let warn = (msg, ~kv=?) => {
45  switch kv {
46  | Some(obj) => Console.warn(_render(msg, ~kv=obj))
47  | None => Console.warn(msg)
48  }
49}
50
51let error = (msg, ~kv=?) => {
52  switch kv {
53  | Some(obj) => Console.error(_render(msg, ~kv=obj))
54  | None => Console.error(msg)
55  }
56}
57
58/** Verify that the value in b is true or print msg. Same as console.assert */
59let verify = (b: bool, msg: string) => {
60  Console.assert_(b, msg)
61}