user1383359
user1383359

Reputation: 2753

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.

Upvotes: 5

Views: 1176

Answers (2)

amalloy
amalloy

Reputation: 91857

(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))

Upvotes: 10

Juha Syrjälä
Juha Syrjälä

Reputation: 34271

Java logging frameworks like log4j and logback provide this kind of functionality. You can configure logging system to add the line numbers to log messages. File name may be more difficult, but at least you can have the namespace there.

You can use clojure.logging to provide nice interface to the logging frameworks.

Upvotes: 0

Related Questions