235

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

John Lawrence Aspden
  • 17,124
  • 11
  • 67
  • 110
Arun R
  • 8,372
  • 6
  • 37
  • 46
  • 1
    In additions to the answers below, see 'Debugging tools and techniques' in the REPL guide: https://clojure.org/guides/repl/enhancing_your_repl_workflow#debugging-tools-and-techniques – Valentin Waeselynck Jul 19 '18 at 13:21

14 Answers14

163

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
Pramod
  • 5,150
  • 3
  • 45
  • 46
John Lawrence Aspden
  • 17,124
  • 11
  • 67
  • 110
  • 2
    Nice, but how do you get clojure to find 'clojure.contrib.trace? I have the clojure-contrib jar on my classpath but REPL says `user=> (use 'closure.contrib.trace) java.io.FileNotFoundException: Could not locate closure/contrib/trace__init.class or closure/contrib/trace.clj on classpath: (NO_SOURCE_FILE:0)` – LarsH Sep 03 '10 at 20:49
  • 2
    Could you be misspelling clojure as closure, or is that a typo in the comment? Can you load other clojure.contrib libraries? – John Lawrence Aspden Sep 05 '10 at 21:27
  • 13
    As of 1.3 this has moved to clojure.tools.trace (https://github.com/clojure/tools.trace) – George Dec 13 '11 at 14:16
  • 4
    If you are getting: "IllegalStateException Can't dynamically bind non-dynamic var" see here: http://stackoverflow.com/questions/8875353/why-im-getting-cant-dynamically-bind-non-dynamic-var – Cornelius Jan 29 '13 at 16:22
  • 2
    Is it working in the 1.5 release also? I'm learning Clojure with the clojure koans, but can't get dotrace to work yet. – nha Nov 08 '14 at 15:51
105

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)
John Lawrence Aspden
  • 17,124
  • 11
  • 67
  • 110
68

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

Amumu
  • 17,924
  • 31
  • 84
  • 131
46

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)
                   ^^^
Community
  • 1
  • 1
Michał Marczyk
  • 83,634
  • 13
  • 201
  • 212
39

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.

Dave Liepmann
  • 1,555
  • 1
  • 18
  • 22
thnetos
  • 1,316
  • 10
  • 9
17

"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.

Rachel K. Westmacott
  • 2,038
  • 20
  • 15
  • 1
    This is mostly true but when you have recursion across multiple functions for example it's not that easy. – John Aug 12 '17 at 16:39
9

For IntelliJ there's an excellent Clojure plugin called Cursive. 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.

dskrvk
  • 1,318
  • 15
  • 24
  • I was using La Clojure with success, but seems to be dying in favour of cursive now https://github.com/JetBrains/la-clojure/blob/master/README.md – leeor Aug 15 '15 at 17:36
  • But how to debug with `Leiningen`, it shows: `Error running 'ring server': Trampoline must be enabled for debugging` – Gank Nov 18 '18 at 14:42
  • That seems to be specific to `ring` or `lein` - perhaps worth posting a separate question? – dskrvk Nov 19 '18 at 00:21
9

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.

John Lawrence Aspden
  • 17,124
  • 11
  • 67
  • 110
6

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

Mallory-Erik
  • 1,750
  • 1
  • 19
  • 24
5

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.

Rodrigo Taboada
  • 2,727
  • 4
  • 24
  • 27
2

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

myguidingstar
  • 673
  • 4
  • 10
1

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

yotsov
  • 775
  • 5
  • 11
1

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.

Dave Liepmann
  • 1,555
  • 1
  • 18
  • 22
Jouni K. Seppänen
  • 43,139
  • 5
  • 71
  • 100
-4

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)])
Community
  • 1
  • 1
Kevin Zhu
  • 2,746
  • 26
  • 23