changeset 193:0461635570a0

Migration of logging from old thermostat to web-gateway Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-June/023617.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-July/023976.html
author Christopher Koehler <chkoehle@redhat.com>
date Tue, 04 Jul 2017 15:03:16 -0400
parents 17a5b2833107
children ba460d69e3b9
files common/core/src/main/java/com/redhat/thermostat/gateway/common/core/config/BasicConfiguration.java common/core/src/main/java/com/redhat/thermostat/gateway/common/util/LogFormatter.java common/core/src/main/java/com/redhat/thermostat/gateway/common/util/LoggingUtil.java common/core/src/test/java/com/redhat/thermostat/gateway/common/util/LogFormatterTest.java distribution/src/bin/thermostat-web-gateway.sh distribution/src/etc/logging.properties
diffstat 6 files changed, 357 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/config/BasicConfiguration.java	Tue Jul 11 16:14:42 2017 -0400
+++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/core/config/BasicConfiguration.java	Tue Jul 04 15:03:16 2017 -0400
@@ -46,9 +46,14 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.redhat.thermostat.gateway.common.util.LoggingUtil;
 
 abstract class BasicConfiguration implements Configuration {
 
+    private static final Logger logger = LoggingUtil.getLogger(BasicConfiguration.class);
     private static final String PROPERTIES_PREFIX = "properties|";
     private static final String FILE_PREFIX = "file|";
 
@@ -67,12 +72,13 @@
     protected static Map<String, Object> loadConfig(String configFile, String basePath) {
         Properties props = new Properties();
         File globalConfig = new File(configFile);
+        logger.fine("Loading config from " + configFile);
         try (FileInputStream fis = new FileInputStream(globalConfig)) {
             props.load(fis);
         } catch (FileNotFoundException e) {
             // ignore
         } catch (IOException e) {
-            e.printStackTrace();
+            logger.log(Level.FINE, "Error reading config properties file", e);
         }
         Map<String, Object> config = new HashMap<>();
         for (Entry<Object, Object> entry: props.entrySet()) {
@@ -95,7 +101,7 @@
                 } catch (FileNotFoundException e) {
                     // ignore
                 } catch (IOException e) {
-                    e.printStackTrace();
+                    logger.log(Level.FINE, "Error reading properties file", e);
                 }
             } else {
                 config.put(key, entry.getValue());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/util/LogFormatter.java	Tue Jul 04 15:03:16 2017 -0400
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.common.util;
+
+import java.util.logging.Formatter;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+public class LogFormatter extends Formatter {
+
+    /**
+     * Gets the shortened package name from a logging class. It's convenient to
+     * read when my.class.package.ClassHere is m.c.p.ClassHere, so this takes a
+     * list of class names from a log record's getSourceClassName() and gets
+     * the shortened name as seen above (without the class at the end). This
+     * means in the above example:<br><br>
+     * <tt>my.class.package.ClassHere</tt><br><br>
+     * causes the following to be returned (assuming it was .split()):<br><br>
+     * <tt>m.c.p</tt><br><br>
+     * It is up to the caller to put the dot and class after the return value.
+     * @param fullLoggingClassNames The array of strings from splitting the
+     *                              log record's getSourceClassName(). This
+     *                              should not be null.
+     * @return A string of the shortened name (without the trailing period and
+     * class name). If the length of the array is <= 1, then an empty string is
+     * returned.
+     */
+    private String getShortenedPackageNameFromSourceClass(String[] fullLoggingClassNames) {
+        StringBuilder shortenedNameBuilder = new StringBuilder();
+
+        if (fullLoggingClassNames.length > 1) {
+            shortenedNameBuilder.append(fullLoggingClassNames[0].charAt(0));
+            for (int i = 1; i < fullLoggingClassNames.length - 1; i++) {
+                shortenedNameBuilder.append(".");
+                shortenedNameBuilder.append(fullLoggingClassNames[i].charAt(0));
+            }
+        }
+
+        return shortenedNameBuilder.toString();
+    }
+
+    @Override
+    public synchronized String format(LogRecord record) {
+        Throwable thrown = record.getThrown();
+        Level level = record.getLevel();
+        String[] fullLoggingClassNames = record.getSourceClassName().split("\\.");
+        String trimmedPackagePrefix = getShortenedPackageNameFromSourceClass(fullLoggingClassNames);
+        String loggingClassName = fullLoggingClassNames[fullLoggingClassNames.length - 1];
+        String indent = "  ";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(level.toString());
+        sb.append(" - ");
+        sb.append(trimmedPackagePrefix);
+        sb.append(".");
+        sb.append(loggingClassName);
+        sb.append(": ");
+        sb.append(record.getMessage());
+        sb.append("\n");
+        while (thrown != null) {
+            sb.append(indent);
+            sb.append("Caused by:\n");
+            sb.append(indent);
+            sb.append(thrown.getClass().getCanonicalName());
+            sb.append(": ");
+            sb.append(thrown.getMessage());
+            sb.append("\n");
+            for (StackTraceElement stackTraceElement : thrown.getStackTrace()) {
+                sb.append(indent);
+                sb.append(stackTraceElement.toString());
+                sb.append("\n");
+            }
+
+            thrown = thrown.getCause();
+            indent = indent.concat("  ");
+        }
+
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/gateway/common/util/LoggingUtil.java	Tue Jul 04 15:03:16 2017 -0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.common.util;
+
+import java.util.logging.Logger;
+
+/**
+ * Contains helper methods for logging.
+ */
+public class LoggingUtil {
+
+    private static final String ROOT_LOGGER_NAME = "com.redhat.thermostat.gateway";
+    private static final Logger ROOT_LOGGER = Logger.getLogger(ROOT_LOGGER_NAME);
+
+    /**
+     * Should not be instantiated.
+     */
+    private LoggingUtil() {
+    }
+
+    /**
+     * Gets the logger for the provided class. It will inherit from the root
+     * logger.
+     * @param cls The class to get the logger for.
+     * @return The logger for the provided class.
+     */
+    public static Logger getLogger(Class<?> cls) {
+        Logger logger = Logger.getLogger(cls.getPackage().getName());
+        logger.setLevel(null); // Inheriting from root logger.
+        return logger;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/gateway/common/util/LogFormatterTest.java	Tue Jul 04 15:03:16 2017 -0400
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.common.util;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import org.junit.Test;
+
+public class LogFormatterTest {
+
+    private static String logMessage = "a message";
+    private static Level logLevel = Level.INFO;
+
+    @Test
+    public void testLogMessage() {
+        LogRecord logRecord = mock(LogRecord.class);
+        when(logRecord.getThrown()).thenReturn(null);
+        when(logRecord.getLevel()).thenReturn(logLevel);
+        when(logRecord.getSourceClassName()).thenReturn("some.random.class.TestClass");
+        when(logRecord.getMessage()).thenReturn(logMessage);
+
+        String expected = logLevel.toString() + " - s.r.c.TestClass: " + logMessage + "\n";
+        String output = new LogFormatter().format(logRecord);
+        assertEquals(expected, output);
+    }
+
+    @Test
+    public void testLogMessageException() {
+        String exceptionMsg = "exception message";
+        Exception exception = new Exception(exceptionMsg);
+
+        LogRecord logRecord = mock(LogRecord.class);
+        when(logRecord.getThrown()).thenReturn(null);
+        when(logRecord.getLevel()).thenReturn(logLevel);
+        when(logRecord.getSourceClassName()).thenReturn("some.random.class.TestClass");
+        when(logRecord.getMessage()).thenReturn(logMessage);
+        when(logRecord.getThrown()).thenReturn(exception);
+
+        String headerMsg = logLevel.toString() + " - s.r.c.TestClass: " + logMessage + "\n" +
+                           "  Caused by:\n" +
+                           "  java.lang.Exception: " + exceptionMsg;
+        String output = new LogFormatter().format(logRecord);
+        assertTrue(output.startsWith(headerMsg));
+    }
+}
--- a/distribution/src/bin/thermostat-web-gateway.sh	Tue Jul 11 16:14:42 2017 -0400
+++ b/distribution/src/bin/thermostat-web-gateway.sh	Tue Jul 04 15:03:16 2017 -0400
@@ -66,7 +66,17 @@
   THERMOSTAT_GATEWAY_HOME="`cygpath -w $THERMOSTAT_GATEWAY_HOME`"
 fi
 
+LOGGING_ARGS=()
+LOG_CONFIG_FILE="${THERMOSTAT_GATEWAY_HOME}/etc/logging.properties"
+if [ -f "${LOG_CONFIG_FILE}" ] ; then
+  if [ $CYGWIN_MODE -eq 1 ]; then
+    LOGGING_ARGS=( "-Djava.util.logging.config.file=`cygpath -w ${LOG_CONFIG_FILE}`" )
+  else
+    LOGGING_ARGS=( "-Djava.util.logging.config.file=${LOG_CONFIG_FILE}" )
+  fi
+fi
+
 THERMOSTAT_GATEWAY_LIBS=${THERMOSTAT_GATEWAY_HOME}/libs
 
 export THERMOSTAT_GATEWAY_HOME
-java -cp "${THERMOSTAT_GATEWAY_LIBS}/*" com.redhat.thermostat.gateway.server.Start
+java -cp "${THERMOSTAT_GATEWAY_LIBS}/*" "${LOGGING_ARGS[@]}" com.redhat.thermostat.gateway.server.Start
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distribution/src/etc/logging.properties	Tue Jul 04 15:03:16 2017 -0400
@@ -0,0 +1,73 @@
+# Copyright 2012-2017 Red Hat, Inc.
+#
+# This file is part of Thermostat.
+#
+# Thermostat is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 2, or (at your
+# option) any later version.
+#
+# Thermostat is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Thermostat; see the file COPYING.  If not see
+# <http://www.gnu.org/licenses/>.
+#
+# Linking this code with other modules is making a combined work
+# based on this code.  Thus, the terms and conditions of the GNU
+# General Public License cover the whole combination.
+#
+# As a special exception, the copyright holders of this code give
+# you permission to link this code with independent modules to
+# produce an executable, regardless of the license terms of these
+# independent modules, and to copy and distribute the resulting
+# executable under terms of your choice, provided that you also
+# meet, for each linked independent module, the terms and conditions
+# of the license of that module.  An independent module is a module
+# which is not derived from or based on this code.  If you modify
+# this code, you may extend this exception to your version of the
+# library, but you are not obligated to do so.  If you do not wish
+# to do so, delete this exception statement from your version.
+
+com.redhat.thermostat.gateway.handlers = java.util.logging.ConsoleHandler
+# If you want a FileHandler instead use:
+#com.redhat.thermostat.gateway.handlers = java.util.logging.FileHandler
+# To add a ConsoleHandler AND FileHandler, use the following line instead.
+#com.redhat.thermostat.gateway.handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
+
+# You may use standard configs for log handlers.
+# See: http://docs.oracle.com/javase/7/docs/api/java/util/logging/FileHandler.html
+
+java.util.logging.ConsoleHandler.formatter = com.redhat.thermostat.gateway.common.util.LogFormatter
+java.util.logging.ConsoleHandler.level = ALL
+
+# For example:
+# Configure console handler to use j.u.l's simple formatter instead of
+# Thermostat's formatter.
+#java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+# Configure a file handler
+#java.util.logging.FileHandler.pattern = %h/.thermostat/logs/thermostat.log
+#java.util.logging.FileHandler.limit = 50000
+#java.util.logging.FileHandler.append = true
+#java.util.logging.FileHandler.count = 1
+#java.util.logging.FileHandler.formatter = com.redhat.thermostat.gateway.common.util.LogFormatter
+
+
+###################################################################
+# Thermostat log level config. If one is not set below, the default
+# level is OFF.
+###################################################################
+# Possible levels are in descending order:
+#com.redhat.thermostat.gateway.level=OFF
+#com.redhat.thermostat.gateway.level=SEVERE
+#com.redhat.thermostat.gateway.level=WARNING
+com.redhat.thermostat.gateway.level=INFO
+#com.redhat.thermostat.gateway.level=CONFIG
+#com.redhat.thermostat.gateway.level=FINE
+#com.redhat.thermostat.gateway.level=FINER
+#com.redhat.thermostat.gateway.level=FINEST
+#com.redhat.thermostat.gateway.level=ALL