Thank you, Sean. That is an excellent example. -austin
On Sunday, January 3, 2021 at 12:48:55 PM UTC-8 Sean Corfield wrote: > Austin, > > You might find a macro like this helpful -- just use it directly instead > of future. You can replace println with whatever sort of logging you want. > > (defmacro logged-future > "Given a body, execute it in a try/catch and log any errors." > [& body] > (let [line (:line (meta &form)) > file *file*] > `(future > (try > ~@body > (catch Throwable t# > (println t# "Unhandled exception at:" > ~file "line:" ~line > "on thread:" > (.getName (Thread/currentThread)))))))) > > > On Sat, Jan 2, 2021 at 5:59 PM Austin Haas <aus...@pettomato.com> wrote: > >> Ah, thanks for pointing that out. I must've overlooked your example, >> because I'd already written off futures. >> >> It seems like what you are suggesting, catch and print, might be about as >> good as I could hope for. If I don't want to block the main thread, then I >> don't see what else I could possibly do but print the exception. I guess I >> could store it somewhere, but in any case, I'd use this same pattern. >> >> Thanks, Justin. >> On Saturday, January 2, 2021 at 1:44:55 PM UTC-8 noise...@gmail.com >> wrote: >> >>> to be clear, in my second example you see the error from the future >>> without using deref >>> >>> good luck finding your solution >>> >>> On Sat, Jan 2, 2021 at 12:50 PM Austin Haas <aus...@pettomato.com> >>> wrote: >>> >>>> Thank you very much for the explanation, Justin. >>>> >>>> I don't see how I can use futures, though, without blocking on the main >>>> thread (to get the exception when it occurs). I'm spawning a long-running >>>> process that never returns a value. >>>> On Saturday, January 2, 2021 at 12:43:14 AM UTC-8 noise...@gmail.com >>>> wrote: >>>> >>>>> By the time the exception is caught, you are already outside the >>>>> context of the Thread which the repl client is interacting with. The >>>>> default exception handler has no information tying the executing thread >>>>> to >>>>> the repl process (not to mention the dynamic variables clojure is using >>>>> to >>>>> associate output from code your client runs with that socket connection). >>>>> >>>>> You probably don't want to rebind the root exception handler to show >>>>> *all* exceptions to your client socket. Which means that you need to set >>>>> up >>>>> some soft of infrastructure connecting the information about the failed >>>>> function to the socket you are listening to. >>>>> >>>>> I find "future" very convenient for this, it uses a pool which will >>>>> perform better than creating Threads ad-hoc, and will capture Exceptions >>>>> and re-throw when you deref (of course, it's up to you to ensure you >>>>> deref, >>>>> or use try/catch and otherwise forward the failure information via the >>>>> catch block). Also, it conveys dynamic bindings for things like >>>>> clojure.core/*out* and clojure.core/*err* that java classes don't know >>>>> about. >>>>> >>>>> (ins)user=> (def fut (future (throw (Exception. "oops")))) >>>>> #'user/fut >>>>> (ins)user=> @fut ; waits until deref to raise the error >>>>> Execution error at user/fn (REPL:11). >>>>> oops >>>>> (ins)user=> (def fut2 (future (try (throw (Exception. "oops")) (catch >>>>> Exception e (println "wat\n" e))))) ; prints instead of raising >>>>> #'user/fut2 >>>>> user=> wat >>>>> #error { >>>>> :cause oops >>>>> :via >>>>> [{:type java.lang.Exception >>>>> :message oops >>>>> :at [user$fn__165 invokeStatic NO_SOURCE_FILE 13]}] >>>>> :trace >>>>> [[user$fn__165 invokeStatic NO_SOURCE_FILE 13] >>>>> [user$fn__165 invoke NO_SOURCE_FILE 13] >>>>> [clojure.core$binding_conveyor_fn$fn__5754 invoke core.clj 2030] >>>>> [clojure.lang.AFn call AFn.java 18] >>>>> [java.util.concurrent.FutureTask run FutureTask.java 264] >>>>> [java.util.concurrent.ThreadPoolExecutor runWorker >>>>> ThreadPoolExecutor.java 1128] >>>>> [java.util.concurrent.ThreadPoolExecutor$Worker run >>>>> ThreadPoolExecutor.java 628] >>>>> [java.lang.Thread run Thread.java 834]]} >>>>> >>>>> >>>>> >>>>> On Thu, Dec 31, 2020 at 1:48 PM Austin Haas <aus...@pettomato.com> >>>>> wrote: >>>>> >>>>>> >>>>>> Problem: When I connect to a socket server and create a thread, >>>>>> exceptions in the thread are printed in the server's process, not the >>>>>> client's. I'd like them to appear in the client's process, where the >>>>>> thread >>>>>> was created. >>>>>> >>>>>> (I'm using the term "process" very generally here, because I don't >>>>>> understand what is going on.) >>>>>> >>>>>> From searching, I understand that there are some other things at >>>>>> play, like System/err, but I don't understand what is happening or how I >>>>>> can work around it. Why does an exception thrown in the client process >>>>>> show >>>>>> in the client process, but an exception thrown in a thread created by >>>>>> the >>>>>> client process shows in the server process? Why doesn't binding *err* in >>>>>> a >>>>>> thread seem to have any effect? Any suggestions or workarounds? >>>>>> >>>>>> I'm not using futures, because this is a long-running process that >>>>>> never returns a value. >>>>>> >>>>>> Example transcript: >>>>>> >>>>>> # Socker server >>>>>> >>>>>> (The only command entered is the first one, which begins with clj. >>>>>> Everything after "user=>" is due to the client below.) >>>>>> >>>>>> $ clj -J-Dclojure.server.myrepl='{:port >>>>>> 5555,:accept,clojure.core.server/repl}' >>>>>> Clojure 1.10.1 >>>>>> user=> My second message. >>>>>> Exception in thread "Thread-0" clojure.lang.ExceptionInfo: My second >>>>>> exception {} >>>>>> at user$eval5$fn__141.invoke(NO_SOURCE_FILE:7) >>>>>> at clojure.lang.AFn.run(AFn.java:22) >>>>>> at java.lang.Thread.run(Thread.java:745) >>>>>> Exception in thread "Thread-1" clojure.lang.ExceptionInfo: My third >>>>>> exception {} >>>>>> at user$eval144$fn__145.invoke(NO_SOURCE_FILE:16) >>>>>> at clojure.lang.AFn.run(AFn.java:22) >>>>>> at java.lang.Thread.run(Thread.java:745) >>>>>> >>>>>> # Client >>>>>> >>>>>> $ nc localhost 5555 >>>>>> user=> (println "My first message.") >>>>>> My first message. >>>>>> nil >>>>>> user=> (throw (ex-info "My first exception." {})) >>>>>> Execution error (ExceptionInfo) at user/eval3 (REPL:2). >>>>>> My first exception. >>>>>> user=> (.start >>>>>> (Thread. >>>>>> (fn [] >>>>>> (println "My second message.") >>>>>> (throw (ex-info "My second exception" {}))))) >>>>>> nil >>>>>> user=> (.start >>>>>> (Thread. >>>>>> (let [out *out* >>>>>> err *err*] >>>>>> (fn [] >>>>>> (binding [*out* out >>>>>> *err* err] >>>>>> (println "My third message.") >>>>>> (throw (ex-info "My third exception" {}))))))) >>>>>> nil >>>>>> My third message. >>>>>> >>>>>> Any clues would be appreciated. Thanks! >>>>>> >>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "Clojure" group. >>>>>> To post to this group, send email to clo...@googlegroups.com >>>>>> Note that posts from new members are moderated - please be patient >>>>>> with your first post. >>>>>> To unsubscribe from this group, send email to >>>>>> clojure+u...@googlegroups.com >>>>>> For more options, visit this group at >>>>>> http://groups.google.com/group/clojure?hl=en >>>>>> --- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "Clojure" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>> send an email to clojure+u...@googlegroups.com. >>>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/clojure/d084b0c0-0a1b-4db2-95a1-f38ff894bfa6n%40googlegroups.com >>>>>> >>>>>> <https://groups.google.com/d/msgid/clojure/d084b0c0-0a1b-4db2-95a1-f38ff894bfa6n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>> . >>>>>> >>>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To post to this group, send email to clo...@googlegroups.com >>>> Note that posts from new members are moderated - please be patient with >>>> your first post. >>>> To unsubscribe from this group, send email to >>>> clojure+u...@googlegroups.com >>>> For more options, visit this group at >>>> http://groups.google.com/group/clojure?hl=en >>>> --- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to clojure+u...@googlegroups.com. >>>> >>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/clojure/8dd61a48-0195-4b2d-bbee-7d24f976268fn%40googlegroups.com >>>> >>>> <https://groups.google.com/d/msgid/clojure/8dd61a48-0195-4b2d-bbee-7d24f976268fn%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@googlegroups.com >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+u...@googlegroups.com. >> > To view this discussion on the web visit >> https://groups.google.com/d/msgid/clojure/82e8cba4-c8a3-4d9a-81be-f703d8e0aa52n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/clojure/82e8cba4-c8a3-4d9a-81be-f703d8e0aa52n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > > > -- > Sean A Corfield -- (904) 302-SEAN > An Architect's View -- https://corfield.org/ > World Singles Networks, LLC. -- https://worldsinglesnetworks.com/ > > "Perfection is the enemy of the good." > -- Gustave Flaubert, French realist novelist (1821-1880) > -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/dd43e7e7-c790-4613-8ab3-3172cb23b822n%40googlegroups.com.