SkillAgentSearch skills...

Debux

A trace-based debugging library for Clojure and ClojureScript.

Install / Use

/learn @philoskim/Debux
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Debux

:source-language: clojure :source-highlighter: coderay :sectnums: :imagesdir: ./doc/img :toc:

Debux is a simple but useful library for debugging Clojure and ClojureScript. I wrote this library to debug my own Clojure(Script) code and to analyze other developer's one.

  • Clojars repository: link:https://clojars.org/philoskim/debux[]

Prerequisites

  • clojure 1.10.0 or later (since debux 0.9.0)
  • clojurescript 1.10.238 or later

[[two-libraries]]

Two libraries

In development, use the philoskim/debux library. When you use debux macros and functions from this library, it will emit debugging messages to the REPL window or the Chrome DevTools' console.

In production, use the philoskim/debux-stubs (link:https://github.com/philoskim/debux-stubs[]) library. This has the same public API as philoskim/debux but the macros simply expand only to the given original form itself.

With this setup

  • in production, your use of debux macros will have zero run-time and compile-time cost,

  • in development, debux macros are able to be turned off too via the set-debug-mode! function.

WARNING: Never use philoskim/debux library in production because it will impose too much overhead on the peformance, especially in using dbgn and clogn, even though (set-debug-mode! false) is run.

Installation

First, please be sure to read the "Two libraries" section immediately above for background.

To include debux in your project for development, simply add the following to your project.clj development dependencies:

[source] .... [philoskim/debux "0.9.1"] ....

and this to your production dependencies.

[source] .... [philoskim/debux-stubs "0.9.1"] ....

Recent change logs

NOTE: You can see All change logs since v0.3.0 https://github.com/philoskim/debux/tree/master/doc/change-logs.adoc[here].

  • v0.9.1 ** :simple option deprecated. Instead, use :final (or :f) option. See the details <<final-option, here>>.

  • v0.9.0

All the new features of this version are thanks to the link:https://github.com/philoskim/debux/pull/31[pull request] of link:https://github.com/gnl[George Lipov]. Thanks a lot again!

** The minimum version of Clojure is upgraded from 1.8.0 to 1.10.0 ** ClojureScript dependency in Clojure removed. ** bb (Babashka for Clojure) support added. See the details <<babashka, here>>. *** nbb (Babashka for Node) is not supported yet.

** tap> support added. See the details <<tap-output, here>>. *** set-tap-output! function added. *** set-date-time-fn! function added.

** :simple option added.

  • v0.8.3 ** link:https://github.com/hyperfiddle/electric[Electric] support added. See the details <<electric, here>>.

  • v0.8.2 ** A bug fixed: pull request link:https://github.com/philoskim/debux/pull/26[#26]

  • v0.8.1 ** dbgt and clogt macro bugs fixed.

  • v0.8.0 ** dbgt and clogt macros for debugging transducers added. See the details <<dbgt, here>>. ** set-debug-level! removed. Instead, use with-level macro. See the details <<with-level, here>>.

How to use

In Clojure, the following line should be included in your file.

[source] .... (use 'debux.core) ....

In ClojureScript, the following (:require pass:q[...]) line has to be included in your file.

[source] .examples/core.cljs .... (ns examples.core (:require [debux.cs.core :as d :refer-macros [clog clogn dbg dbgn break clog_ clogn_ dbg_ dbgn_ break_]])) ....

{empty} +

[cols="^1m,^1m,^1m,^1m,^1m,^1m", options="header"] .Debugging API use

|===

| | dbg | dbgn | clog | clogn | break

| Clojure REPL | O | O | X | X | X | ClojureScript REPL | O | O | X | X | X | ClojureScript Browser console | O | O | O | O | O

|===

  • Legend: O (supported), X (not supported)

//-

. dbg/dbgn can be used in Clojure REPL.

. dbg/dbgn can be used in ClojureScript REPL like link:https://github.com/tomjakubowski/weasel[weasel] or https://github.com/bhauman/lein-figwheel[figwheel].

** Refer to <<browser-repl>> for Browser REPL usage.

. dbg/dbgn , clog/clogn and break can be used in the browser console window like Chrome DevTools. + TIP: I recommend that you should use clog/clogn instead of dbg/dbgn in the browser console window, because clog/clogn uses the console.log function of browser's developer tools to style the form. You can see its effect <<style-option, here>>.

dbg examples

NOTE: You can see every example source code of this document in https://github.com/philoskim/debux/tree/master/examples[examples] folder.

Basic usage

NOTE: The features of clog are almost the same as those of dbg.

The macro dbg prints an original form and pretty-prints the evaluated value on the REPL window. Then it returns the value without interrupting the code evaluation.

[source] .... (* 2 (dbg (+ 10 20))) ; => 60 ....

[listing] .REPL output

{:ns examples.demo, :line 8} dbg: (+ 10 20) => | 30

[#eval-multiple-forms] Sometimes you need to see multiple forms evaluated. To do so, a literal vector form can be used like this.

[source] .... (defn my-fun [a {:keys [b c d] :or {d 10 b 20 c 30}} [e f g & h]] (dbg [a b c d e f g h]))

(my-fun (take 5 (range)) {:c 50 :d 100} ["a" "b" "c" "d" "e"]) ; => [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")] ....

[listing] .REPL output

{:ns examples.demo, :line 11} dbg: [a b c d e f g h] => | [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")]

[#eval-multiple-forms-with-dbgn] You can use dbgn for better results as well. See the detalis for dbgn <<dbgn-examples, here>>.

[source] .... (defn my-fun2 [a {:keys [b c d] :or {d 10 b 20 c 30}} [e f g & h]] (dbgn [a b c d e f g h]))

(my-fun2 (take 5 (range)) {:c 50 :d 100} ["a" "b" "c" "d" "e"]) ; => [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")] ....

[listing] .REPL output

{:ns examples.demo, :line 15} dbgn: [a b c d e f g h] => | a => | (0 1 2 3 4) | b => | 20 | c => | 50 | d => | 100 | e => | "a" | f => | "b" | g => | "c" | h => | ("d" "e") | [a b c d e f g h] => | [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")]

Generally, dbg prints the evaluated result of the outermost form except for the following eight special cases (pass:q[->], pass:q[->>], pass:q[some->], pass:q[some->>], pass:q[cond->], pass:q[cond->>], let, comp).

Debugging the thread macro pass:q[->] or pass:q[->>]

Using outside the thread macros

When debugging the thread-first macro pass:q[->] or thread-last macro pass:q[->>], dbg prints every expression in the thread macros.

This is an example of thread-first macro pass:q[->].

[source] .... (dbg (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first)) ;=> "X" ....

.REPL output [listing]

{:ns examples.demo, :line 18} dbg: (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first) => | "a b c d" => | "a b c d" | .toUpperCase => | "A B C D" | (.replace "A" "X") => | "X B C D" | (.split " ") => | ["X", "B", "C", "D"] | first => | "X"

Another example.

[source] .... (def person {:name "Mark Volkmann" :address {:street "644 Glen Summit" :city "St. Charles" :state "Missouri" :zip 63304} :employer {:name "Object Computing, Inc." :address {:street "12140 Woodcrest Dr." :city "Creve Coeur" :state "Missouri" :zip 63141}}})

(dbg (-> person :employer :address :city)) ; => "Creve Coeur" ....

.REPL output .... {:ns examples.demo, :line 37} dbg: (-> person :employer :address :city) => | person => | {:name "Mark Volkmann", | :address | {:street "644 Glen Summit", | :city "St. Charles", | :state "Missouri", | :zip 63304}, | :employer | {:name "Object Computing, Inc.", | :address | {:street "12140 Woodcrest Dr.", | :city "Creve Coeur", | :state "Missouri", | :zip 63141}}} | :employer => | {:name "Object Computing, Inc.", | :address | {:street "12140 Woodcrest Dr.", | :city "Creve Coeur", | :state "Missouri", | :zip 63141}} | :address => | {:street "12140 Woodcrest Dr.", | :city "Creve Coeur", | :state "Missouri", | :zip 63141} | :city => | "Creve Coeur" ....

This is an example of thread-last macro pass:q[->>].

[source] .... (def c 5)

(dbg (->> c (+ 3) (/ 2) (- 1))) ; => 3/4 ....

.REPL output .... {:ns examples.demo, :line 42} dbg: (->> c (+ 3) (/ 2) (- 1)) => | c => | 5 | (+ 3) => | 8 | (/ 2) => | 1/4 | (- 1) => | 3/4 ....

Using inside the thread macros

If you want to debug one of the expressions within the thread macro pass:q[->] or pass:q[->>], don't do it like this.

[source] .... (-> {:a [1 2]} (dbg (get :a)) (conj 3)) ; => java.lang.IllegalArgumentException ; Don't know how to create ISeq from: java.lang.Long ....

You will have some exception. Instead, do it like this.

[source] .... (-> {:a [1 2]} (get :a) dbg (conj 3)) ; => [1 2 3] ....

.REPL output .... {:ns examples.demo} dbg: (get {:a [1 2]} :a) => | [1 2] ....

Another example.

[source] .... (->> [-1 0 1 2] (filter pos?) (map inc) dbg (map str)) ; => ("2" "3") ....

.REPL output .... {:ns examples.demo} dbg: (map inc (filter pos? [-1 0 1 2])) => | (2 3) ....

NOTE: In the above examples, dbg doesn't get the :line number information from the Clojure compiler, so it is omitted. I don't know why the Clojure compiler doesn't provide the line number informaton through the code of (:line (meta &form)) inside the thread macros pass:q[->] or pass:q[->>] in this situation. If anyone knows about it, please let me know.

See more examples <<dbg-last, here

View on GitHub
GitHub Stars478
CategoryDevelopment
Updated4d ago
Forks19

Languages

Clojure

Security Score

80/100

Audited on Mar 25, 2026

No findings