Search code examples
clojure

Clojure: Debugging Println, __LINE_NUMBER__ and __FILE_NAME__


Context

Currently,

(println "x is" x)

just prints out

x is 10

Now, what I want is something like this:

(my-println "x is" x)

to print out:

foo.clj:23> x is 10

Informally, I want my-println to append the _FILE_NAME_ and _LINE_NUMBER_ into my println.

Question:

I know how to use macros. However, I don't know how to extract the _FILE_NAME_ and _LINE_NUMBER_ from the current location in Clojure (whereas C macros make this trivial to do). How do I get the current FILE_NAME_ and _LINE_NUMBER_ ?

Thanks.


Solution

  • (defmacro my-println [x]
      `(do (printf "%s:%s> %s is %s\n"
                   ~*file*
                   ~(:line (meta &form))
                   ~(pr-str x)
                   ~x)
           (flush)))
    

    Looking at this answer again much later, you can be a bit more clever if you like, reducing the runtime costs by interpolating the string constants at compile time:

    (defmacro my-println [x]
      `(println ~(format "%s:%s> %s is"
                         *file*
                         (:line (meta &form))
                         (pr-str x))
                ~x))
    

    As you can see from the macroexpansion, there is no longer any need to invoke relatively-expensive printf code at runtime:

    (let [x 5] (macroexpand '(my-println (+ x 5))))
    (clojure.core/println "foo.clj:1> (+ x 5) is" (+ x 5))