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 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/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/CAD4thx9_cN%2Byt%3DkBgE6%2BQSREAf5tSbBjxeUZwUC2_zLjSsQ7EQ%40mail.gmail.com.