[ONOS-3528] Enable logging exception when Executor.execute invoked

Change-Id: I4df7c9a0bc0607c16c4c36103447ce8a8f14ffa7
diff --git a/utils/misc/src/main/java/org/onlab/util/Tools.java b/utils/misc/src/main/java/org/onlab/util/Tools.java
index 9bc6436..89bc300 100644
--- a/utils/misc/src/main/java/org/onlab/util/Tools.java
+++ b/utils/misc/src/main/java/org/onlab/util/Tools.java
@@ -100,10 +100,31 @@
      * @return thread factory
      */
     public static ThreadFactory groupedThreads(String groupName, String pattern) {
+        return groupedThreads(groupName, pattern, log);
+    }
+
+    /**
+     * Returns a thread factory that produces threads named according to the
+     * supplied name pattern and from the specified thread-group. The thread
+     * group name is expected to be specified in slash-delimited format, e.g.
+     * {@code onos/intent}. The thread names will be produced by converting
+     * the thread group name into dash-delimited format and pre-pended to the
+     * specified pattern. If a logger is specified, it will use the logger to
+     * print out the exception if it has any.
+     *
+     * @param groupName group name in slash-delimited format to indicate hierarchy
+     * @param pattern   name pattern
+     * @param logger    logger
+     * @return thread factory
+     */
+    public static ThreadFactory groupedThreads(String groupName, String pattern, Logger logger) {
+        if (logger == null) {
+            return groupedThreads(groupName, pattern);
+        }
         return new ThreadFactoryBuilder()
                 .setThreadFactory(groupedThreadFactory(groupName))
                 .setNameFormat(groupName.replace(GroupedThreadFactory.DELIMITER, "-") + "-" + pattern)
-                .setUncaughtExceptionHandler((t, e) -> log.error("Uncaught exception on " + t.getName(), e))
+                .setUncaughtExceptionHandler((t, e) -> logger.error("Uncaught exception on " + t.getName(), e))
                 .build();
     }