Ensure uncaught exceptions are logged into server error log

Normally these go to stdout, but in daemon mode that is usually
the useless /dev/null device.

Bug: issue 483
Change-Id: Ida8d0c91744410b316ba32834a2307b10bc312f8
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index 3130f3c..3e10336 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -45,6 +45,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.Thread.UncaughtExceptionHandler;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -91,6 +92,12 @@
   @Override
   public int run() throws Exception {
     mustHaveValidSite();
+    Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+      @Override
+      public void uncaughtException(Thread t, Throwable e) {
+        log.error("Thread " + t.getName() + " threw exception", e);
+      }
+    });
 
     if (runId != null) {
       runFile = new File(new File(getSitePath(), "logs"), "gerrit.run");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index 0ba38b1..28b91c7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -19,6 +19,10 @@
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.Thread.UncaughtExceptionHandler;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -56,6 +60,15 @@
     }
   }
 
+  private static final Logger log = LoggerFactory.getLogger(WorkQueue.class);
+  private static final UncaughtExceptionHandler LOG_UNCAUGHT_EXCEPTION =
+      new UncaughtExceptionHandler() {
+        @Override
+        public void uncaughtException(Thread t, Throwable e) {
+          log.error("WorkQueue thread " + t.getName() + " threw exception", e);
+        }
+      };
+
   private Executor defaultQueue;
   private final IdGenerator idGenerator;
   private final CopyOnWriteArrayList<Executor> queues;
@@ -137,6 +150,7 @@
         public Thread newThread(final Runnable task) {
           final Thread t = parent.newThread(task);
           t.setName(prefix + "-" + tid.getAndIncrement());
+          t.setUncaughtExceptionHandler(LOG_UNCAUGHT_EXCEPTION);
           return t;
         }
       });