Stacktraces

10 views
Skip to first unread message

Mark McGranaghan

unread,
Oct 27, 2010, 12:00:43 PM10/27/10
to Clojure Dev
Hi All,

Following up on discussions at the Conj, I'd like to start a thread
here about Clojure stacktrace handling and how it might borrow from
clj-stacktrace.

Clojure's default stacktrace handling seems to give users a lot of
trouble. When I introduce a programmer to Clojure, one of the most
common reactions is that the stacktraces are brutal. E.g.:

http://twitter.com/hirodusk/status/19636865978
http://twitter.com/ww/status/22054747463

Whereas I think a lot of initial user reactions to Clojure should be
ignored ("too many parens"), in this case I think user sentiments are
well founded.

Here is a script demonstrating three different stacktraces handling
options that are currently available: default Java handling,
clojure.stacktrace, and clj-stacktrace:
http://gist.github.com/649282

And the results of running that script:
http://gist.github.com/649289

You may or may not find the clj-stacktrace representation desirable,
but it at least highlights that that we have the option of designing
Clojure stacktrace representations instead of dumping them more-or-
less straight through from Java.

I think that the implementation approach of clj-stacktrace could be
useful for Clojure to adopt regardless of what printing format is
desired. That approach is to first parse the exception into Clojure
data structures, then to apply any filtering or transformation logic
to this data structure, and then finally to print the stacktrace from
the manipulated data.

For example, here is the pprint'ed data structure generated by clj-
stacktrace.core on the exception given in the example:
http://gist.github.com/649326

I'd be very interested to hear others' thoughts on the stacktrace
situation.

- Mark

David Nolen

unread,
Oct 27, 2010, 12:19:46 PM10/27/10
to cloju...@googlegroups.com

--
You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
To post to this group, send email to cloju...@googlegroups.com.
To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.


I think clj-stacktrace is great but I never much cared for the alignment of the output. I find something more along the lines of Python's stacktrace more pleasing.


Note also that I removed pretty much everything that does not actually come from user code. I think this should be the default and that there should be knobs to show more verbose stack traces. This would be much friendlier to newcomers.

Note that I include the offending lines referenced by the stacktrace. Lisp sexprs make single line contexts somewhat less useful but that's why I think there should be another knob for configuring how much context you want to show (# of lines before and after).

David

Stuart Halloway

unread,
Oct 27, 2010, 12:26:11 PM10/27/10
to cloju...@googlegroups.com
Hi Mark,

Please start a page at dev.confluence.org to capture the decisions being proposed/made. My suspicion is that we can all agree on the following:

* converting to data
* canonicalizing names

And will continue to argue about

* specific formatting.

Whatever we come up should capture the "everything prior to formatting" part in a function. That way individual tools (or users) can configure the last bit as they see fit.

Another tagentially-related thing to consider: a generic exception type in Clojure, bearing a map of information. This would get rid of many superfluous project-specific gen-classes, plus the compilation and binary dependencies that ensue.

Stu

Phil Hagelberg

unread,
Oct 27, 2010, 1:06:15 PM10/27/10
to cloju...@googlegroups.com
On Wed, Oct 27, 2010 at 9:00 AM, Mark McGranaghan <mmcg...@gmail.com> wrote:
> Here is a script demonstrating three different stacktraces handling
> options that are currently available: default Java handling,
> clojure.stacktrace, and clj-stacktrace:
> http://gist.github.com/649282
>
> And the results of running that script:
> http://gist.github.com/649289
>
> You may or may not find the clj-stacktrace representation desirable,
> but it at least highlights that that we have the option of designing
> Clojure stacktrace representations instead of dumping them more-or-
> less straight through from Java.
>
> I think that the implementation approach of clj-stacktrace could be
> useful for Clojure to adopt regardless of what printing format is
> desired. That approach is to first parse the exception into Clojure
> data structures, then to apply any filtering or transformation logic
> to this data structure, and then finally to print the stacktrace from
> the manipulated data.

Agreed! I'm a huge fan of the alignment, not to mention the colorized
stack traces. Customizable filtering is also pretty important.

Thanks for moving the discussion forward. =)

-Phil

Phil Hagelberg

unread,
Oct 27, 2010, 2:05:38 PM10/27/10
to cloju...@googlegroups.com
> Another tagentially-related thing to consider: a generic exception type in Clojure, bearing a map of information. This would get rid of many superfluous project-specific gen-classes, plus the compilation and binary dependencies that ensue.

Actually clojure.contrib.condition does this. It's not well-known; I
think people could benefit from wider knowledge of it. I think it's a
good candidate for eventual promotion, but it probably needs to see
wider usage first. It's quite useful.

-Phil

Rich Hickey

unread,
Oct 27, 2010, 4:15:32 PM10/27/10
to cloju...@googlegroups.com
You missed the current behavior of clojure.repl/pst

The data structure idea is fine, all strings maybe not.

Also, needs a good strategy for distinguishing the kinds of entries
(e.g. fns vs methods)

As Stu said, a Confluence page would be the next step.

Rich

Mark McGranaghan

unread,
Oct 30, 2010, 6:51:57 PM10/30/10
to Clojure Dev


On Oct 27, 1:15 pm, Rich Hickey <richhic...@gmail.com> wrote:
> You missed the current behavior of clojure.repl/pst

Ah, right. clojure.repl/pst does is indeed a lot nicer that the other
baked-in Clojure options. Updated gists:
http://gist.github.com/649282

> The data structure idea is fine, all strings maybe not.
>
> Also, needs a good strategy for distinguishing the kinds of entries  
> (e.g. fns vs methods)
>
> As Stu said, a Confluence page would be the next step.

http://dev.clojure.org/display/design/Stacktraces

It seems to me that a good next step would be finding the right data
representation for stacktraces. clj-stacktrace uses something like:

{:class java.lang.Exception,
:message "I regret to inform you that you are doing it wrong.",
:trace-elems
({:annon-fn false,
:fn "biz",
:ns "user",
:clojure true,
:file "trace_test.clj",
:line 8}
...)
:cause {...}}

:class -- the exception.Class
:message -- the message String directly from .getMessage
:cause -- if present, a map with the same structure as an outermost
exception
:trace-elems -- a seq of maps representing stack trace elems

The stack trace element maps are shaped as follows:

:file -- String of source file name
:line -- Integer of source line number of the enclosing form

(for Java only)
:java -- true
:class -- String of the name of the class to which the method belongs
:method -- String of the method name

(for Clojure only)
:clojure -- true
:ns -- String representing the namespace of the function
:fn -- String representing the name of the enclosing var for the
function
:annon-fn -- true iff the function is anonymous

Using (nested) maps and seqs makes a lot of sense to me. I also think
that the elements in the exception map are pretty solid. I'm not as
sure about the elements of the stack trace line maps. :file and :line
seem obvious, but the design for representing Java vs. Clojure
exception data is lacking. What do others think about this aspect in
particular and exception/stacktrace data representation in general?

- Mark

Mark McGranaghan

unread,
Oct 30, 2010, 6:56:39 PM10/30/10
to Clojure Dev
I also like the idea of a generic, map-bearing exception. This would
both eliminate exception class proliferation and provide a single,
universal concrete type that Clojure application code could catch (and
then branch on arbitrarily based on map inspection).

The reasons I haven't used Condition in the past are 1) it forced a
clojure.contrib dependency and 2) that it descends from Throwable and
not Exception. My understanding was that apps should in general catch
Exception, since Errors (the other subclass of Throwable) are used to
indicate unrecoverable errors. So if you throw a Throwable it won't be
caught by most application code. Maybe I am misunderstanding something
there?
http://gist.github.com/655786

- Mark

> -Phil

Alex Miller

unread,
Oct 30, 2010, 10:22:46 PM10/30/10
to cloju...@googlegroups.com
+1 re extending Exception vs Throwable


From: Mark McGranaghan <mmcg...@gmail.com>
To: Clojure Dev <cloju...@googlegroups.com>
Sent: Sat, October 30, 2010 5:56:39 PM
Subject: Re: Stacktraces
--
You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
To post to this group, send email to cloju...@googlegroups.com.
To unsubscribe from this group, send email to clojure-dev+unsub...@googlegroups.com.

Laurent PETIT

unread,
Nov 1, 2010, 5:58:59 PM11/1/10
to cloju...@googlegroups.com
RuntimeException please

2010/10/31 Alex Miller <alexd...@yahoo.com>
To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.

Laurent PETIT

unread,
Nov 1, 2010, 6:00:50 PM11/1/10
to cloju...@googlegroups.com


2010/10/31 Mark McGranaghan <mmcg...@gmail.com>

Hi, one of the reasons I did not use it was that it could not work well across threads. Maybe the new behaviour recently introduced into 1.3 for bindings may help in this area ?

 

- Mark

> -Phil
Reply all
Reply to author
Forward
0 new messages