Debugging in Clojure?

DebuggingClojure

Debugging Problem Overview


What are best ways to Debug Clojure code, while using the repl?

Debugging Solutions


Solution 1 - Debugging

There's also dotrace, which allows you to look at the inputs and outputs of selected functions.

(use 'clojure.contrib.trace)
(defn fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
(dotrace [fib] (fib 3))

produces the output:

TRACE t4425: (fib 3)
TRACE t4426: |    (fib 2)
TRACE t4427: |    |    (fib 1)
TRACE t4427: |    |    => 1
TRACE t4428: |    |    (fib 0)
TRACE t4428: |    |    => 0
TRACE t4426: |    => 1
TRACE t4429: |    (fib 1)
TRACE t4429: |    => 1
TRACE t4425: => 2
2

In Clojure 1.4, dotrace has moved:

You need the dependency:

[org.clojure/tools.trace "0.7.9"]
(require 'clojure.tools.trace)

And you need to add the ^:dynamic to the function definition

(defn ^:dynamic fib[n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))

Then Bob is once again your uncle:

(clojure.tools.trace/dotrace [fib] (fib 3))

TRACE t4328: (fib 3)
TRACE t4329: | (fib 2)
TRACE t4330: | | (fib 1)
TRACE t4330: | | => 1
TRACE t4331: | | (fib 0)
TRACE t4331: | | => 0
TRACE t4329: | => 1
TRACE t4332: | (fib 1)
TRACE t4332: | => 1
TRACE t4328: => 2

Solution 2 - Debugging

I have a little debugging macro that I find very useful:

;;debugging parts of expressions
(defmacro dbg[x] `(let [x# ~x] (println "dbg:" '~x "=" x#) x#))

You can insert it wherever you want to watch what's going on and when:

;; Examples of dbg
(println (+ (* 2 3) (dbg (* 8 9))))
(println (dbg (println "yo")))
(defn factorial[n] (if (= n 0) 1 (* n (dbg (factorial (dec n))))))
(factorial 8)

(def integers (iterate inc 0))
(def squares  (map #(dbg(* % %))   integers))
(def cubes    (map #(dbg(* %1 %2)) integers squares))
(take 5 cubes)
(take 5 cubes)

Solution 3 - Debugging

Emacs's CIDER got a source debugger that you can step expression by expression inside an Emacs buffer and even inject new values. You can read all about it here. A demo screenshot:

CIDER debug

Solution 4 - Debugging

My favourite method is a liberal sprinkling of printlns all over the code... Turning them on and off is easy thanks to the #_ reader macro (which makes the reader read in the following form, then pretend it's never seen it). Or you could use a macro expanding either to a passed-in body or nil depending on the value of some special variable, say *debug*:

(defmacro debug-do [& body]
  (when *debug*
    `(do ~@body)))

With a (def *debug* false) in there, this will expand to nil. With true, it'll expand to body wrapped in a do.


The accepted answer to this SO question: Idiomatic Clojure for progress reporting? is very helpful when debugging sequence operations.


Then there's something which is currently incompatible with swank-clojure's REPL, but is too good not to mention: debug-repl. You can use it in a standalone REPL, which is easy to get e.g. with Leiningen (lein repl); and if you're launching your programme from the command line, then it's going to bring its own REPL up right in your terminal. The idea is that you can drop the debug-repl macro in anywhere you like and have it bring up its own REPL when the programme's execution reaches that point, with all locals in scope etc. A couple of relevant links: The Clojure debug-repl, Clojure debug-repl tricks, how 'bout a debug-repl (on the Clojure Google group), debug-repl on Clojars.


swank-clojure does an adequate job of making SLIME's built-in debugger useful when working with Clojure code -- note how the irrelevant bits of the stacktrace are greyed out so it's easy to find the actual problem in the code being debugged. One thing to keep in mind is that anonymous functions without "name tags" appear in the stacktrace with basically no useful information attached to them; when a "name tag" is added, it does appear in the stacktrace and all is well again:

(fn [& args] ...)
vs.
(fn tag [& args] ...)

example stacktrace entries:
1: user$eval__3130$fn__3131.invoke(NO_SOURCE_FILE:1)
vs.                ^^
1: user$eval__3138$tag__3139.invoke(NO_SOURCE_FILE:1)
                   ^^^

Solution 5 - Debugging

You can also insert code to drop yourself into a REPL with all the local bindings, using Alex Osborne's debug-repl:

(defmacro local-bindings
  "Produces a map of the names of local bindings to their values."
  []
  (let [symbols (map key @clojure.lang.Compiler/LOCAL_ENV)]
    (zipmap (map (fn [sym] `(quote ~sym)) symbols) symbols)))
 
(declare *locals*)
(defn eval-with-locals
  "Evals a form with given locals. The locals should be a map of symbols to
values."
  [locals form]
  (binding [*locals* locals]
    (eval
     `(let ~(vec (mapcat #(list % `(*locals* '~%)) (keys locals)))
        ~form))))
 
(defmacro debug-repl
  "Starts a REPL with the local bindings available."
  []
  `(clojure.main/repl
    :prompt #(print "dr => ")
    :eval (partial eval-with-locals (local-bindings))))

Then to use it, insert it wherever you want the repl to start:

(defn my-function [a b c]
  (let [d (some-calc)]
    (debug-repl)))

I stick this in my user.clj so it's available in all REPL sessions.

Solution 6 - Debugging

"best ways to Debug Clojure code, while using the repl"

Slightly left-field, but 'using the REPL iteself'.

I've been writing hobbyist Clojure for over a year and haven't felt a great need for any debugging tools. If you keep your functions small, and run each one with expected inputs at the REPL and observe the results then it should be possible to have a pretty clear picture of how your code is behaving.

I find a debugger is most useful for observing STATE in a running application. Clojure makes it easy (and fun!) to write in a functional style with immutable data structures (no changing state). This massively reduces the need for a debugger. Once I know that all the components behave as I expect (paying particular attention to the types of things) then the large scale behaviour is rarely a problem.

Solution 7 - Debugging

If you use emacs/slime/swank, then try this at the REPL:

(defn factorial [n]
        (cond (< n 2) n
              (= n 23) (swank.core/break)
              :else (* n (factorial (dec n)))))

(factorial 30)

It doesn't give you a full stack trace like you'd get under LISP, but it's good for poking around.

This is the fine work of:

http://hugoduncan.org/post/2010/swank_clojure_gets_a_break_with_the_local_environment.xhtml

as was mentioned in a comment above.

Solution 8 - Debugging

For IntelliJ there's an excellent Clojure plugin called [Cursive][1]. Among other things, it provides a REPL which you can run in debug mode and step through your Clojure code just like you would for e.g. Java.

I would second Peter Westmacott's answer though in that in my experience just running pieces of my code in the REPL is most of the time a sufficient form of debugging.

[1]: https://cursiveclojure.com/ "Cursive"

Solution 9 - Debugging

As of 2016 you can use Debux, a simple debugging library for Clojure/Script that works in conjunction with your repl as well as your browser's console. You can sprinkle dbg (debug) or clog (console.log) macros in your code and easily observe results of individual functions, etc, printed to your REPL and/or console.

From the project's Readme:

> Basic usage > > This is a simple example. The macro dbg prints an original form and > pretty-prints the evaluated value on the REPL window. Then it returns > the value without interfering with the code execution. > > If you wrap the code with dbg like this, > > (* 2 (dbg (+ 10 20))) ; => 60

> the following will be printed in the > REPL window. > > REPL output:

> dbg: (+ 10 20) => 30 > > Nested dbg > > The dbg macro can be nested.

> (dbg (* 2 (dbg (+ 10 20)))) ; => 60

> REPL output:

> dbg: (+ 10 20) => 30

> > dbg: (* 2 (dbg (+ 10 20))) => 60

Solution 10 - Debugging

Hugo Duncan and collaborators continue to do amazing work with the ritz project. Ritz-nrepl is a nREPL server with debug capabilities. Watch Hugo's Debuggers in Clojure talk at Clojure/Conj 2012 to see it in action, in the video some of the slides aren't readable so you may want to view the slides from here.

Solution 11 - Debugging

Use spyscope which implement a custom reader macro so that your debug code is also production code https://github.com/dgrnbrg/spyscope

Solution 12 - Debugging

Here's a nice macro for debugging complicated let forms:

(defmacro def+
  "def with binding (def+ [{:keys [a b d]} {:a 1 :b 2 :d 3}])"
  [bindings]
  (let [let-expr (macroexpand `(let ~bindings))
        vars (filter #(not (.contains (str %) "__"))
               (map first (partition 2 (second let-expr))))
        def-vars (map (fn [v] `(def ~v ~v)) vars)]
    (concat let-expr def-vars)))

...and an essay explaining its use.

Solution 13 - Debugging

Coming from Java and being familiar with Eclipse, I like what Counterclockwise (the Eclipse plugin for Clojure development) has to offer: http://doc.ccw-ide.org/documentation.html#_debug_clojure_code

Solution 14 - Debugging

Function version of def-let, which turns a let into a series of defs. Some credit goes to here

(defn def-let [aVec]
  (if-not (even? (count aVec))
    aVec
    (let [aKey (atom "")       
          counter (atom 0)]
      (doseq [item aVec]
        (if (even? @counter) 
          (reset! aKey  item)           
          (intern *ns*  (symbol @aKey)  (eval item)))
        ;   (prn  item)       
    (swap! counter inc)))))

Usage: Needs to quote the content with a quotation, e.g.

(def-let '[a 1 b 2 c (atom 0)])

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionArun RView Question on Stackoverflow
Solution 1 - DebuggingJohn Lawrence AspdenView Answer on Stackoverflow
Solution 2 - DebuggingJohn Lawrence AspdenView Answer on Stackoverflow
Solution 3 - DebuggingAmumuView Answer on Stackoverflow
Solution 4 - DebuggingMichał MarczykView Answer on Stackoverflow
Solution 5 - DebuggingthnetosView Answer on Stackoverflow
Solution 6 - DebuggingRachel K. WestmacottView Answer on Stackoverflow
Solution 7 - DebuggingJohn Lawrence AspdenView Answer on Stackoverflow
Solution 8 - DebuggingdskrvkView Answer on Stackoverflow
Solution 9 - DebuggingMallory-ErikView Answer on Stackoverflow
Solution 10 - DebuggingRodrigo TaboadaView Answer on Stackoverflow
Solution 11 - DebuggingmyguidingstarView Answer on Stackoverflow
Solution 12 - DebuggingJouni K. SeppänenView Answer on Stackoverflow
Solution 13 - DebuggingyotsovView Answer on Stackoverflow
Solution 14 - DebuggingKevin ZhuView Answer on Stackoverflow