Point taken.

The time when it the exception trace becomes annoying is when you're
doing TDD and you start with lots of broken tests.

The other time is pretty much any Clojure stack trace when you're
developing. In most cases, the bug is in your own code but your own
code only represents a tiny percentage of the Java stack. For example,
I really don't feel like I need to see all those variations on invoke.

For example, the following stack trace:

  0: java.lang.Class.cast(Class.java:2990)
  1: clojure.core$cast__2964.invoke(core.clj:218)
  2: clojure.core$_PLUS___3137.invoke(core.clj:553)
  3: com.infolace.format.PrettyWriter$fn__26597.invoke
(PrettyWriter.clj:156)
  4: clojure.lang.MultiFn.invoke(MultiFn.java:156)
  5: com.infolace.format.PrettyWriter$write_token_string__26623.invoke
(PrettyWriter.clj:197)
  6: com.infolace.format.PrettyWriter
$write_line__26628$fn__26630.invoke(PrettyWriter.clj:228)
  7: clojure.lang.AFn.call(AFn.java:32)
  8: clojure.lang.LockingTransaction.runInTransaction
(LockingTransaction.java:202)
  9: com.infolace.format.PrettyWriter$write_line__26628.invoke
(PrettyWriter.clj:223)
 10: com.infolace.format.PrettyWriter
$add_to_buffer__26634$fn__26636.invoke(PrettyWriter.clj:240)
 11: clojure.lang.AFn.call(AFn.java:32)
 12: clojure.lang.LockingTransaction.run(LockingTransaction.java:223)
 13: clojure.lang.LockingTransaction.runInTransaction
(LockingTransaction.java:204)
 14: com.infolace.format.PrettyWriter$add_to_buffer__26634.invoke
(PrettyWriter.clj:237)
 15: com.infolace.format.PrettyWriter$_write__26651.invoke
(PrettyWriter.clj:289)
 16: com.infolace.format.PrettyWriter.write(Unknown Source)
 17: clojure.core$print_simple__5193.invoke(core_print.clj:118)
 18: clojure.core$fn__5196.invoke(core_print.clj:121)
 19: clojure.lang.MultiFn.invoke(MultiFn.java:152)
 20: clojure.core$pr_on__3886.invoke(core.clj:1758)
 21: clojure.core$pr__3889.invoke(core.clj:1768)
 22: com.infolace.pprint$write__10998.doInvoke(pprint.clj:131)
 23: clojure.lang.RestFn.invoke(RestFn.java:415)
 24: clojure.lang.AFn.applyToHelper(AFn.java:174)
 25: clojure.lang.RestFn.applyTo(RestFn.java:137)
 26: clojure.core$apply__3047.doInvoke(core.clj:376)
 27: clojure.lang.RestFn.invoke(RestFn.java:443)
 28: com.infolace.format$fn__26291$fn__26293.invoke(format.clj:1422)
 29: clojure.lang.AFn.applyToHelper(AFn.java:180)
 30: clojure.lang.AFn.applyTo(AFn.java:165)
 31: clojure.core$apply__3047.doInvoke(core.clj:376)
 32: clojure.lang.RestFn.invoke(RestFn.java:428)
 33: com.infolace.format$execute_sub_format__25778$fn__25780.invoke
(format.clj:459)
 34: clojure.lang.AFn.applyToHelper(AFn.java:176)
 35: clojure.lang.AFn.applyTo(AFn.java:165)
 36: clojure.core$apply__3047.doInvoke(core.clj:376)
 37: clojure.lang.RestFn.invoke(RestFn.java:428)
 38: com.infolace.format.utilities$map_passing_context__1.invoke
(utilities.clj:25)
 39: com.infolace.format$execute_sub_format__25778.invoke(format.clj:
452)
 40: com.infolace.format$format_logical_block__26049$fn__26052.invoke
(format.clj:1126)
 41: com.infolace.format$format_logical_block__26049.invoke(format.clj:
1122)
 42: com.infolace.format$logical_block_or_justify__25915.invoke
(format.clj:858)
 43: clojure.lang.AFn.applyToHelper(AFn.java:180)
 44: clojure.lang.AFn.applyTo(AFn.java:165)
 45: clojure.core$apply__3047.doInvoke(core.clj:376)
 46: clojure.lang.RestFn.invoke(RestFn.java:428)
 47: com.infolace.format
$execute_format__26433$fn__26435$fn__26437.invoke(format.clj:1717)
 48: clojure.lang.AFn.applyToHelper(AFn.java:176)
 49: clojure.lang.AFn.applyTo(AFn.java:165)
 50: clojure.core$apply__3047.doInvoke(core.clj:376)
 51: clojure.lang.RestFn.invoke(RestFn.java:428)
 52: com.infolace.format.utilities$map_passing_context__1.invoke
(utilities.clj:25)
 53: com.infolace.format$execute_format__26433$fn__26435.invoke
(format.clj:1709)
 54: com.infolace.format$execute_format__26433.invoke(format.clj:1708)
 55: com.infolace.format$cl_format__25640.doInvoke(format.clj:25)
 56: clojure.lang.RestFn.invoke(RestFn.java:445)
 57: user$eval__26709.invoke(Unknown Source)
 58: clojure.lang.Compiler.eval(Compiler.java:4168)
 59: clojure.core$eval__3741.invoke(core.clj:1497)
 60: swank.commands.basic$eval_region__609.invoke(basic.clj:35)
 61: swank.commands.basic$listener_eval__618.invoke(basic.clj:49)
 62: clojure.lang.Var.invoke(Var.java:327)
 63: user$eval__26706.invoke(Unknown Source)
 64: clojure.lang.Compiler.eval(Compiler.java:4168)
 65: clojure.core$eval__3741.invoke(core.clj:1497)
 66: swank.core$eval_in_emacs_package__275.invoke(core.clj:55)
 67: swank.core$eval_for_emacs__351.invoke(core.clj:122)
 68: clojure.lang.Var.invoke(Var.java:335)
 69: clojure.lang.AFn.applyToHelper(AFn.java:180)
 70: clojure.lang.Var.applyTo(Var.java:444)
 71: clojure.core$apply__3047.doInvoke(core.clj:376)
 72: clojure.lang.RestFn.invoke(RestFn.java:428)
 73: swank.core$eval_from_control__278.invoke(core.clj:62)
 74: swank.core$eval_loop__281.invoke(core.clj:67)
 75: swank.core$spawn_repl_thread__409$fn__437$fn__439.invoke(core.clj:
167)
 76: clojure.lang.AFn.applyToHelper(AFn.java:172)
 77: clojure.lang.AFn.applyTo(AFn.java:165)
 78: clojure.core$apply__3047.doInvoke(core.clj:376)
 79: clojure.lang.RestFn.invoke(RestFn.java:428)
 80: swank.core$spawn_repl_thread__409$fn__437.doInvoke(core.clj:164)
 81: clojure.lang.RestFn.invoke(RestFn.java:402)
 82: clojure.lang.AFn.run(AFn.java:38)
 83: java.lang.Thread.run(Thread.java:619)

Really could be reduced to:


  2: clojure.core$_PLUS___3137.invoke(core.clj:553)
  3: com.infolace.format.PrettyWriter$fn__26597.invoke
(PrettyWriter.clj:156)
  5: com.infolace.format.PrettyWriter$write_token_string__26623.invoke
(PrettyWriter.clj:197)
  6: com.infolace.format.PrettyWriter
$write_line__26628$fn__26630.invoke(PrettyWriter.clj:228)
  9: com.infolace.format.PrettyWriter$write_line__26628.invoke
(PrettyWriter.clj:223)
 10: com.infolace.format.PrettyWriter
$add_to_buffer__26634$fn__26636.invoke(PrettyWriter.clj:240)
 14: com.infolace.format.PrettyWriter$add_to_buffer__26634.invoke
(PrettyWriter.clj:237)
 15: com.infolace.format.PrettyWriter$_write__26651.invoke
(PrettyWriter.clj:289)
 16: com.infolace.format.PrettyWriter.write(Unknown Source)
 22: com.infolace.pprint$write__10998.doInvoke(pprint.clj:131)
 28: com.infolace.format$fn__26291$fn__26293.invoke(format.clj:1422)
 33: com.infolace.format$execute_sub_format__25778$fn__25780.invoke
(format.clj:459)
 38: com.infolace.format.utilities$map_passing_context__1.invoke
(utilities.clj:25)
 39: com.infolace.format$execute_sub_format__25778.invoke(format.clj:
452)
 40: com.infolace.format$format_logical_block__26049$fn__26052.invoke
(format.clj:1126)
 41: com.infolace.format$format_logical_block__26049.invoke(format.clj:
1122)
 42: com.infolace.format$logical_block_or_justify__25915.invoke
(format.clj:858)
 47: com.infolace.format
$execute_format__26433$fn__26435$fn__26437.invoke(format.clj:1717)
 52: com.infolace.format.utilities$map_passing_context__1.invoke
(utilities.clj:25)
 53: com.infolace.format$execute_format__26433$fn__26435.invoke
(format.clj:1709)
 54: com.infolace.format$execute_format__26433.invoke(format.clj:1708)
 55: com.infolace.format$cl_format__25640.doInvoke(format.clj:25)

And then that could be further cleaned up to be much easier to read.
(Somebody posted some code to do that.)

This reduces the length of the stack track by a factor of ~4 and makes
it much easier to understand what my code thought it was doing.

But if you're in a production environment where the stack trace is
your only evidence, you may want to have all the data from the trace
in case it really did blow up because of a bug in Rich's code.

But as you say, different strokes for different folks :-). The neat
thing about Clojure (and lisps in general) is that it's pretty easy to
customize your environment to work the way you want.

On Feb 11, 3:17 am, Chas Emerick <cemer...@snowtide.com> wrote:
> Thanks for the pointer....
>
> Different strokes for different folks, I guess.  Any time I've had a  
> tool try to be smart with what error information is being provided, I  
> end up discovering that an important tidbit was being elided (usually  
> for some hours while tracking down a bug).  Exceptions are (or should  
> be) exceptional, so I've never thought that reading them was onerous.
>
> Of course, it's entirely possible that my stuff may fall out of the  
> "for most apps" category more often than most? :-)
>
> - Chas
>
> On Feb 11, 2009, at 12:25 AM, Tom Faulhaber wrote:
>
>
>
> > So rather than choosing between a stack depth and scanning through
> > noise, it might be better to just filter out the (obvious) noise. This
> > includes stuff that's down in the runtime (for most apps) and stuff
> > that is up above the test.
>
> > Shane Celis used that approach in his unit_test library. I forked and
> > updated it to a little more modern Clojure and I have been very happy
> > with it. The relevant code is here:http://gist.github.com/61846and
> > the full project is here:http://github.com/tomfaulhaber/unit_test/
>
> > This solves the problem of trying to figure out the "right" depth.
> > Plus even if you figure out the right depth, you still usually end up
> > with a lot of garbage on the top of your stack. I've found that a
> > little simple filtering makes the traces *much* more readable.
>
> > Tom
>
> > On Feb 10, 7:01 pm, Chas Emerick <cemer...@snowtide.com> wrote:
> >> On Feb 10, 2009, at 8:52 PM, Stuart Sierra wrote:
>
> >>> Ok, new behavior in SVN rev. 449:  Full stack traces are printed by
> >>> default.  Bind *stack-trace-depth* to an integer to limit the depth.
>
> >> That's great, Stuart, thank you very much.
>
> >>>> On Feb 10, 2:01 pm, Jeffrey Straszheim  
> >>>> <straszheimjeff...@gmail.com>
> >>>> wrote:
>
> >>>>> I've found that, in general, the stack dumps you get back from
> >>>>> Java (into
> >>>>> Clojure-land) are pretty unhelpful.
>
> >>>> I found that at first too, before someone showed me that you often
> >>>> have to look at the nested "cause" ((.getCause e), I think) of the
> >>>> exception, sometimes 5-10 layers deep, to see the real problem.  It
> >>>> is
> >>>> almost always buried in there somewhere.
>
> >> Absolutely true -- there's often lots of noise in stack traces, but
> >> there's gems in there if you're willing to scan through them (and  
> >> once
> >> you get the hang of it, your eyeballs learn how to ignore the noise).
> >> Just FWIW, we only use test-is in an automated test context that is
> >> bootstrapped by ant and hudson, so the full stack traces really need
> >> to be in the logs anyway in order for the testing to be maximally
> >> useful.
>
> >> - Chas
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to