0

How can I capture the exception stacktrace into a file in Scala? I tried with System.setErr but it didn't work, while Console.withErr can be set only for a code snippet and not for the whole app. Any idea? I would like to log to a file all the uncaught exceptions of the app

Edit:

A bit more context: I run inside a spark-shell with a jar added in the classpath. What I do is instantiating an object of a class and the first code ran inside the class is the following, which doesn't give me the
expected print

Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
def uncaughtException(t: Thread, e: Throwable): Unit = {
  logger.error("exception logged")
  println("exception logged")
}
})

throw new Exception("my ex")

but I don't see the print neither in stdout nor in the log file

alexlipa
  • 1,131
  • 2
  • 12
  • 27
  • All uncaught exceptions? Do you mean that you would like to swallow all exceptions and have the app continue to run? – SourceSimian Dec 20 '18 at 23:26
  • What do you mean by "it didn't work"? Which exception wasn't logged? How was it thrown? You should post your `System.setErr()` code. – jwvh Dec 20 '18 at 23:51
  • I just want to log the stacktrace before the app dies. The code I tried used this `System.setErr(new PrintStream( new FileOutputStream("a.txt")))` and the exception was simply a test one `throw new Exception("e")` – alexlipa Dec 22 '18 at 13:58
  • @alexpila your code works for me and I have edited my answer with an example. Let me ask... are you seeing anything from println or your logger framework (not just in the exception)? – SourceSimian Dec 22 '18 at 20:23
  • @alexlipa, Have you read [this](https://stackoverflow.com/help/mcve)? I've tried various ways to reproduce your problem but my attempts always work as expected. Without enough code to recreate your problem we're only guessing at what you're seeing. – jwvh Dec 22 '18 at 21:40

1 Answers1

0

Just use the Thread.setUncaughtExceptionHandler:

Java uncaught global exception handler

Use Thread.currentThread() if your app is single-threaded to get the current thread.

Edit

object ErrorHandling {
  def main(args: Array[String]): Unit = {
    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
      def uncaughtException(t: Thread, e: Throwable): Unit = {
//        logger.error("exception logged")
        println(s"exception logged: $e")
        e.printStackTrace()
      }
    })
    throw new Exception(s"boom")
  }
}

Should give you something like:

exception logged: java.lang.Exception: boom
java.lang.Exception: boom
    at ErrorHandling$.main(ErrorHandling.scala:10)
    at ErrorHandling.main(ErrorHandling.scala)
SourceSimian
  • 682
  • 4
  • 18
  • this works in an example with a main. I am running this as a spark application and I use this code when I am instantiating an object and it doesn't work – alexlipa Dec 23 '18 at 12:58
  • @alexpila When you are dealing with spark, particularly if it is in a distributed cluster, whether or not this will work is totally dependent on what host the statement is executed, and on what thread the exception is thrown. Without seeing your code or knowing anything more about it I cannot even begin to tell you what may be wrong, but when dealing with a Spark app, this is definitely not the right approach to take at all. Spark has various logs, and your exception may already be in one of them. I recommend removing all your log-changing code and checking the master and worker logs. – SourceSimian Dec 23 '18 at 18:11
  • my code is running on master and I am logging in a custom logger I created for my app. Moreover, I am not only logging, but also simply printing some lines and I can't see them in output. I am starting to think it might be something related to threads. I am not sure how can I provide here with a small snippet of the code, because what I have is basically what I wrote above and the whole thing happens after getting a spark context. – alexlipa Dec 26 '18 at 16:30