timbre icon indicating copy to clipboard operation
timbre copied to clipboard

Printing a stack trace should show details for the "cause" Exceptions too

Open peterlindstrom123 opened this issue 3 years ago • 5 comments

The following neatly formatted stack trace printed by Timbre shows no trace of my own code, which makes it useless for figuring out where an error is happening.

                                          java.lang.Thread.run              Thread.java:  834
            java.util.concurrent.ThreadPoolExecutor$Worker.run  ThreadPoolExecutor.java:  628
             java.util.concurrent.ThreadPoolExecutor.runWorker  ThreadPoolExecutor.java: 1128
       jdk.internal.net.http.Http1Exchange.lambda$cancelImpl$9       Http1Exchange.java:  473
  java.util.concurrent.CompletableFuture.completeExceptionally   CompletableFuture.java: 2088
           java.util.concurrent.CompletableFuture.postComplete   CompletableFuture.java:  506
      java.util.concurrent.CompletableFuture$UniHandle.tryFire   CompletableFuture.java:  907
              java.util.concurrent.CompletableFuture.uniHandle   CompletableFuture.java:  930
jdk.internal.net.http.MultiExchange.lambda$responseAsyncImpl$7       MultiExchange.java:  339
          jdk.internal.net.http.MultiExchange.getExceptionalCF       MultiExchange.java:  412
        jdk.internal.net.http.MultiExchange.toTimeoutException       MultiExchange.java:  463
                java.net.ConnectException: HTTP connect timed out
java.net.http.HttpConnectTimeoutException: HTTP connect timed out
java.net.http.HttpConnectTimeoutException: HTTP connect timed out

But when I call a normal Java .printStackTrace, I see my own code in the details for one of the java.net.http.HttpConnectTimeoutExceptions

peterlindstrom123 avatar Sep 11 '20 12:09 peterlindstrom123

@peterlindstrom123 Hi there!

Could you please try provide a minimum reproducible example?

With the default config in v4.10.0 I'm seeing causes displayed as expected:

(timbre/error (ex-info "Ex.1" {} (ex-info "Ex.2" {} (ex-info "Ex.3" {}))) "Foo") ; =>
Sep 12 15:49 Schrebermann.local ERROR [taoensso.timbre:804] - Foo
nrepl.middleware.interruptible-eval/evaluate/fn  interruptible_eval.clj:   91
                              clojure.core/eval                core.clj: 3214
                                            ...                              
                      taoensso.timbre/eval14635               REPL Input     
                          taoensso.timbre/-log!              timbre.clj:  358
                             clojure.core/deref                core.clj: 2320
                                            ...                              
                   taoensso.timbre/eval14635/fn               REPL Input     
clojure.lang.ExceptionInfo: Ex.3
clojure.lang.ExceptionInfo: Ex.2
clojure.lang.ExceptionInfo: Ex.1

Thanks!

ptaoussanis avatar Sep 12 '20 15:09 ptaoussanis

Hi,

I'm not sure what you mean.

Is all of this output related to Ex.3?

nrepl.middleware.interruptible-eval/evaluate/fn  interruptible_eval.clj:   91
                              clojure.core/eval                core.clj: 3214
                                            ...                              
                      taoensso.timbre/eval14635               REPL Input     
                          taoensso.timbre/-log!              timbre.clj:  358
                             clojure.core/deref                core.clj: 2320
                                            ...                              
                   taoensso.timbre/eval14635/fn               REPL Input     

?

If that's correct, then as far as I can tell, my problem was that no source files or line numbers are mentioned for Ex.2 or Ex.1. A normal Java stack trace would show them all.

Obviously the details for all of the source exceptions are relevant?

peterlindstrom123 avatar Sep 13 '20 12:09 peterlindstrom123

Yeah, hiding the chain of traces is a big mistake. I believe https://github.com/AvisoNovate/pretty is the culprit really. To deal with this I had to create my own :output-fn which basically uses clojure.stacktrace/print-cause-trace.

lnostdal avatar Aug 18 '21 07:08 lnostdal

Just to follow-up on this- I'm still not completely clear on what's being requested here.

It'd be helpful to have the following:

  • An example that I can run at the REPL
  • What output you're seeing
  • What output you'd rather see

Thanks!

ptaoussanis avatar Mar 22 '22 17:03 ptaoussanis

Of course this is pointless here in this example, but in other cases the exception and the cause traces are both actually needed. Compare:

user> (clojure.stacktrace/print-cause-trace (Exception. "hi" (Exception. "cause")))                                                                                                                                                                                                         
java.lang.Exception: hi                                                                                                                                                                                                                                                                     
 at user$eval11357.invokeStatic (NO_SOURCE_FILE:1)                                                                                                                                                                                                                                          
    user$eval11357.invoke (NO_SOURCE_FILE:1)                                                                                                                                                                                                                                                
    clojure.lang.Compiler.eval (Compiler.java:7194)                                                                                                                                                                                                                                         
    clojure.lang.Compiler.eval (Compiler.java:7149)                                                                                                                                                                                                                                         
    clojure.core$eval.invokeStatic (core.clj:3215)                                                                                                                                                                                                                                          
    clojure.core$eval.invoke (core.clj:3211)                                                                                                                                                                                                                                                
    nrepl.middleware.interruptible_eval$evaluate$fn__1245$fn__1246.invoke (interruptible_eval.clj:87)                                                                                                                                                                                       
    clojure.lang.AFn.applyToHelper (AFn.java:152)                                                                                                                                                                                                                                           
    clojure.lang.AFn.applyTo (AFn.java:144)                                                                                                                                                                                                                                                 
    clojure.core$apply.invokeStatic (core.clj:667)                                                                                                                                                                                                                                          
    clojure.core$with_bindings_STAR_.invokeStatic (core.clj:1990)                                                                                                                                                                                                                           
    clojure.core$with_bindings_STAR_.doInvoke (core.clj:1990)                                                                                                                                                                                                                               
    clojure.lang.RestFn.invoke (RestFn.java:425)                                                                                                                                                                                                                                            
    nrepl.middleware.interruptible_eval$evaluate$fn__1245.invoke (interruptible_eval.clj:87)                                                                                                                                                                                                
    clojure.main$repl$read_eval_print__9206$fn__9209.invoke (main.clj:437)                                                                                                                                                                                                                  
    clojure.main$repl$read_eval_print__9206.invoke (main.clj:437)                                                                                                                                                                                                                           
    clojure.main$repl$fn__9215.invoke (main.clj:458)                                                                                                                                                                                                                                        
    clojure.main$repl.invokeStatic (main.clj:458)                                                                                                                                                                                                                                           
    clojure.main$repl.doInvoke (main.clj:368)                                                                                                                                                                                                                                               
    clojure.lang.RestFn.invoke (RestFn.java:1523)                                                                                                                                                                                                                                           
    nrepl.middleware.interruptible_eval$evaluate.invokeStatic (interruptible_eval.clj:84)                                                                                                                                                                                                   
    nrepl.middleware.interruptible_eval$evaluate.invoke (interruptible_eval.clj:56)                                                                                                                                                                                                         
    nrepl.middleware.interruptible_eval$interruptible_eval$fn__1278$fn__1282.invoke (interruptible_eval.clj:152)                                                                                                                                                                            
    clojure.lang.AFn.run (AFn.java:22)                                                                                                                                                                                                                                                      
    nrepl.middleware.session$session_exec$main_loop__1348$fn__1352.invoke (session.clj:218)                                                                                                                                                                                                 
    nrepl.middleware.session$session_exec$main_loop__1348.invoke (session.clj:217)                                                                                                                                                                                                          
    clojure.lang.AFn.run (AFn.java:22)                                                                                                                                                                                                                                                      
    java.lang.Thread.run (Thread.java:833)                                                                                                                                                                                                                                                  
Caused by: java.lang.Exception: cause                                                                                                                                                                                                                                                       
 at user$eval11357.invokeStatic (NO_SOURCE_FILE:1)                                                                                                                                                                                                                                          
    user$eval11357.invoke (NO_SOURCE_FILE:1)                                                                                                                                                                                                                                                
    clojure.lang.Compiler.eval (Compiler.java:7194)                                                                                                                                                                                                                                         
    clojure.lang.Compiler.eval (Compiler.java:7149)                                                                                                                                                                                                                                         
    clojure.core$eval.invokeStatic (core.clj:3215)                                                                                                                                                                                                                                          
    clojure.core$eval.invoke (core.clj:3211)                                                                                                                                                                                                                                                
    nrepl.middleware.interruptible_eval$evaluate$fn__1245$fn__1246.invoke (interruptible_eval.clj:87)                                                                                                                                                                                       
    clojure.lang.AFn.applyToHelper (AFn.java:152)                                                                                                                                                                                                                                           
    clojure.lang.AFn.applyTo (AFn.java:144)                                                                                                                                                                                                                                                 
    clojure.core$apply.invokeStatic (core.clj:667)                                                                                                                                                                                                                                          
    clojure.core$with_bindings_STAR_.invokeStatic (core.clj:1990)                                                                                                                                                                                                                           
    clojure.core$with_bindings_STAR_.doInvoke (core.clj:1990)                                                                                                                                                                                                                               
    clojure.lang.RestFn.invoke (RestFn.java:425)                                                                                                                                                                                                                                            
    nrepl.middleware.interruptible_eval$evaluate$fn__1245.invoke (interruptible_eval.clj:87)                                                                                                                                                                                                
    clojure.main$repl$read_eval_print__9206$fn__9209.invoke (main.clj:437)                                                                                                                                                                                                                  
    clojure.main$repl$read_eval_print__9206.invoke (main.clj:437)                                                                                                                                                                                                                           
    clojure.main$repl$fn__9215.invoke (main.clj:458)                                                                                                                                                                                                                                        
    clojure.main$repl.invokeStatic (main.clj:458)                                                                                                                                                                                                                                           
    clojure.main$repl.doInvoke (main.clj:368)                                                                                                                                                                                                                                               
    clojure.lang.RestFn.invoke (RestFn.java:1523)                                                                                                                                                                                                                                           
    nrepl.middleware.interruptible_eval$evaluate.invokeStatic (interruptible_eval.clj:84)                                                                                                                                                                                                   
    nrepl.middleware.interruptible_eval$evaluate.invoke (interruptible_eval.clj:56)                                                                                                                                                                                                         
    nrepl.middleware.interruptible_eval$interruptible_eval$fn__1278$fn__1282.invoke (interruptible_eval.clj:152)                                                                                                                                                                            
    clojure.lang.AFn.run (AFn.java:22)                                                                                                                                                                                                                                                      
    nrepl.middleware.session$session_exec$main_loop__1348$fn__1352.invoke (session.clj:218)                                                                                                                                                                                                 
    nrepl.middleware.session$session_exec$main_loop__1348.invoke (session.clj:217)                                                                                                                                                                                                          
    clojure.lang.AFn.run (AFn.java:22)                                                                                                                                                                                                                                                      
    java.lang.Thread.run (Thread.java:833)  

i.e. both traces vs.

2022-03-23T05:54:54.850Z bullseyeclub-5006 DEBUG [user:61] -                                                                                                                                                                                                                                
   nrepl.middleware.interruptible-eval/evaluate/fn  interruptible_eval.clj:   87                                                                                                                                                                                                            
                                               ...                                                                                                                                                                                                                                          
                       clojure.core/with-bindings*                core.clj: 1990 (repeats 2 times)                                                                                                                                                                                          
                                clojure.core/apply                core.clj:  667                                                                                                                                                                                                            
                                               ...                                                                                                                                                                                                                                          
nrepl.middleware.interruptible-eval/evaluate/fn/fn  interruptible_eval.clj:   87                                                                                                                                                                                                            
                                 clojure.core/eval                core.clj: 3215                                                                                                                                                                                                            
                                               ...                                                                                                                                                                                                                                          
                             user$eval11359.invoke          NO_SOURCE_FILE:   61                                                                                                                                                                                                            
                       user$eval11359.invokeStatic          NO_SOURCE_FILE:   61                                                                                                                                                                                                            
                             taoensso.timbre/-log!             timbre.cljc:  534                                                                                                                                                                                                            
                                clojure.core/deref                core.clj: 2337                                                                                                                                                                                                            
                                               ...                                                                                                                                                                                                                                          
                   user$eval11359$fn__11360.invoke          NO_SOURCE_FILE:   61                                                                                                                                                                                                            
java.lang.Exception: cause                                                                                                                                                                                                                                                                  
java.lang.Exception: hi    

..which has only one of the traces.

lnostdal avatar Mar 23 '22 06:03 lnostdal

@lnostdal Hi Lars, thanks for the clear example! Apologies for the delay replying. This does indeed appear to be the current behaviour of https://github.com/AvisoNovate/pretty.

A couple possibilities:

  1. [Immediate workaround] alter-var-root could be used to change the default stacktrace fn.
  2. [Future Timbre version] default-output-fn could be given an option to specify a different/custom stacktrace fn.

How does (2) sound? Would also be open to ideas re: alternative stracktrace implementations!

Cheers :-)

ptaoussanis avatar Oct 18 '22 16:10 ptaoussanis

Hi there! I'm doing something similar to nr. 1 now - but nr. 2 seems like a better idea.

I don't know about alternatives to the pretty printing done by aviso, but this stacktrace stuff was so important to me I wanted all the details and even noise no matter what - so I just ended up doing: (with-out-str (clojure.stacktrace/print-cause-trace err))

lnostdal avatar Oct 18 '22 18:10 lnostdal

Great, thanks for the feedback @lnostdal.

@lnostdal @peterlindstrom123 An :error-output-fn option will be added to default-output-fn in a forthcoming release. This'll allow one to easily swap in an alternative stacktrace implementation 👍

ptaoussanis avatar Oct 19 '22 08:10 ptaoussanis