Improve logging control. (FELIX-1789)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@888871 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java
index 37a755f..f9cc701 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/ConfigInstaller.java
@@ -26,6 +26,7 @@
 import java.util.Properties;
 
 import org.apache.felix.fileinstall.ArtifactInstaller;
+import org.apache.felix.fileinstall.internal.Util.Logger;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -155,7 +156,8 @@
         Configuration oldConfiguration = findExistingConfiguration(pid, factoryPid);
         if (oldConfiguration != null)
         {
-            Util.log(context, 0, "Updating configuration from " + pid
+            Util.log(context, Util.getGlobalLogLevel(context),
+                Logger.LOG_DEBUG, "Updating configuration from " + pid
                 + (factoryPid == null ? "" : "-" + factoryPid) + ".cfg", null);
             return oldConfiguration;
         }
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
index ae79b37..8d0a792 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
@@ -45,6 +45,7 @@
 import org.apache.felix.fileinstall.ArtifactListener;
 import org.apache.felix.fileinstall.ArtifactTransformer;
 import org.apache.felix.fileinstall.ArtifactUrlTransformer;
+import org.apache.felix.fileinstall.internal.Util.Logger;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
@@ -82,7 +83,7 @@
 	public final static String FILENAME = "felix.fileinstall.filename";
     public final static String POLL = "felix.fileinstall.poll";
     public final static String DIR = "felix.fileinstall.dir";
-    public final static String DEBUG = "felix.fileinstall.debug";
+    public final static String LOG_LEVEL = "felix.fileinstall.log.level";
     public final static String TMPDIR = "felix.fileinstall.tmpdir";
     public final static String FILTER = "felix.fileinstall.filter";
     public final static String START_NEW_BUNDLES = "felix.fileinstall.bundles.new.start";
@@ -96,7 +97,7 @@
     File watchedDirectory;
     File tmpDir;
     long poll;
-    long debug;
+    int logLevel;
     boolean startBundles;
     String filter;
     BundleContext context;
@@ -121,7 +122,7 @@
         this.properties = properties;
         this.context = context;
         poll = getLong(properties, POLL, 2000);
-        debug = getLong(properties, DEBUG, -1);
+        logLevel = getInt(properties, LOG_LEVEL, 0);
         originatingFileName = (String) properties.get(FILENAME);
         watchedDirectory = getFile(properties, DIR, new File("./load"));
         prepareDir(watchedDirectory);
@@ -156,7 +157,7 @@
     public void start() {
         if (noInitialDelay)
         {
-            log("Starting initial scan", null);
+            log(Logger.LOG_DEBUG, "Starting initial scan", null);
             initializeCurrentManagedBundles();
             Set/*<File>*/ files = scanner.scan(true);
             if (files != null)
@@ -174,9 +175,10 @@
      */
     public void run()
     {
-        log("{" + POLL + " (ms) = " + poll + ", "
+        log(Logger.LOG_DEBUG,
+            "{" + POLL + " (ms) = " + poll + ", "
                 + DIR + " = " + watchedDirectory.getAbsolutePath() + ", "
-                + DEBUG + " = " + debug + ", "
+                + LOG_LEVEL + " = " + logLevel + ", "
                 + START_NEW_BUNDLES + " = " + startBundles + ", "
                 + TMPDIR + " = " + tmpDir + ", "
                 + FILTER + " = " + filter + "}", null);
@@ -225,7 +227,7 @@
                     // FileInstall bundle has been uninstalled, exiting loop
                     return;
                 }
-                log("In main loop, we have serious trouble", e);
+                log(Logger.LOG_ERROR, "In main loop, we have serious trouble", e);
             }
         }
     }
@@ -240,7 +242,9 @@
                 Artifact artifact = (Artifact) entry.getValue();
                 if (artifact.getBundleId() == bundleEvent.getBundle().getBundleId())
                 {
-                    log("Bundle " + bundleEvent.getBundle().getBundleId() + " has been uninstalled", null);
+                    log(Logger.LOG_DEBUG,
+                        "Bundle " + bundleEvent.getBundle().getBundleId()
+                            + " has been uninstalled", null);
                     currentManagedArtifacts.remove(entry.getKey());
                     break;
                 }
@@ -299,7 +303,8 @@
                     }
                     catch (IOException e)
                     {
-                        log("Unable to create jar for: " + file.getAbsolutePath(), e);
+                        log(Logger.LOG_WARNING,
+                            "Unable to create jar for: " + file.getAbsolutePath(), e);
                         continue;
                     }
                 }
@@ -428,7 +433,8 @@
             }
             catch (Exception e)
             {
-                log("Unable to transform artifact: " + artifact.getPath().getAbsolutePath(), e);
+                log(Logger.LOG_WARNING,
+                    "Unable to transform artifact: " + artifact.getPath().getAbsolutePath(), e);
             }
             return false;
         }
@@ -446,7 +452,8 @@
             }
             catch (Exception e)
             {
-                log("Unable to transform artifact: " + artifact.getPath().getAbsolutePath(), e);
+                log(Logger.LOG_WARNING,
+                    "Unable to transform artifact: " + artifact.getPath().getAbsolutePath(), e);
             }
             return false;
         }
@@ -459,7 +466,8 @@
                 && !artifact.getTransformed().equals(artifact.getPath())
                 && !artifact.getTransformed().delete())
         {
-            log("Unable to delete transformed artifact: " + artifact.getTransformed().getAbsolutePath(), null);
+            log(Logger.LOG_WARNING,
+                "Unable to delete transformed artifact: " + artifact.getTransformed().getAbsolutePath(), null);
         }
     }
 
@@ -469,7 +477,8 @@
                 && !artifact.getJaredDirectory().equals(artifact.getPath())
                 && !artifact.getJaredDirectory().delete())
         {
-            log("Unable to delete jared artifact: " + artifact.getJaredDirectory().getAbsolutePath(), null);
+            log(Logger.LOG_WARNING,
+                "Unable to delete jared artifact: " + artifact.getJaredDirectory().getAbsolutePath(), null);
         }
     }
 
@@ -506,7 +515,8 @@
     {
         if (!dir.exists() && !dir.mkdirs())
         {
-            log("Cannot create folder "
+            log(Logger.LOG_ERROR,
+                "Cannot create folder "
                 + dir
                 + ". Is the folder write-protected?", null);
             throw new RuntimeException("Cannot create folder: " + dir);
@@ -514,7 +524,8 @@
 
         if (!dir.isDirectory())
         {
-            log("Cannot use "
+            log(Logger.LOG_ERROR,
+                "Cannot use "
                 + dir
                 + " because it's not a directory", null);
             throw new RuntimeException(
@@ -531,9 +542,9 @@
      * @param e
      *            The throwable to log
      */
-    void log(String message, Throwable e)
+    void log(int msgLevel, String message, Throwable e)
     {
-        Util.log(context, debug, message, e);
+        Util.log(context, logLevel, msgLevel, message, e);
     }
 
     /**
@@ -572,6 +583,31 @@
      * @param dflt the default value
      * @return the property as a long or the default value
      */
+    int getInt(Dictionary properties, String property, int dflt)
+    {
+        String value = (String) properties.get(property);
+        if (value != null)
+        {
+            try
+            {
+                return Integer.parseInt(value);
+            }
+            catch (Exception e)
+            {
+                log(Logger.LOG_WARNING, property + " set, but not a int: " + value, null);
+            }
+        }
+        return dflt;
+    }
+
+    /**
+     * Retrieve a property as a long.
+     *
+     * @param properties the properties to retrieve the value from
+     * @param property the name of the property to retrieve
+     * @param dflt the default value
+     * @return the property as a long or the default value
+     */
     long getLong(Dictionary properties, String property, long dflt)
     {
         String value = (String) properties.get(property);
@@ -583,7 +619,7 @@
             }
             catch (Exception e)
             {
-                log(property + " set, but not a long: " + value, null);
+                log(Logger.LOG_WARNING, property + " set, but not a long: " + value, null);
             }
         }
         return dflt;
@@ -825,11 +861,11 @@
             }
             installationFailures.remove(path);
             currentManagedArtifacts.put(path, artifact);
-            log("Installed " + path, null);
+            log(Logger.LOG_DEBUG, "Installed " + path, null);
         }
         catch (Exception e)
         {
-            log("Failed to install artifact: " + path, e);
+            log(Logger.LOG_WARNING, "Failed to install artifact: " + path, e);
 
             // Add it our bad jars list, so that we don't
             // attempt to install it again and again until the underlying
@@ -855,7 +891,8 @@
                 if (v.equals(bv)) {
                     is.reset();
                     if (Util.loadChecksum(b, context) != checksum) {
-                        log("A bundle with the same symbolic name (" + sn + ") and version (" + vStr + ") is already installed.  Updating this bundle instead.", null);
+                        log(Logger.LOG_WARNING,
+                            "A bundle with the same symbolic name (" + sn + ") and version (" + vStr + ") is already installed.  Updating this bundle instead.", null);
                         Util.storeChecksum(b, checksum, context);
                         b.update(is);
                     }
@@ -898,20 +935,22 @@
                 bundle = context.getBundle(artifact.getBundleId());
                 if (bundle == null)
                 {
-                    log("Failed to uninstall bundle: "
+                    log(Logger.LOG_WARNING,
+                        "Failed to uninstall bundle: "
                         + path + " with id: "
                         + artifact.getBundleId()
                         + ". The bundle has already been uninstalled", null);
                     return null;
                 }
-                log("Uninstalling bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ")", null);
+                log(Logger.LOG_DEBUG,
+                    "Uninstalling bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ")", null);
                 bundle.uninstall();
             }
-            log("Uninstalled " + path, null);
+            log(Logger.LOG_DEBUG, "Uninstalled " + path, null);
         }
         catch (Exception e)
         {
-            log("Failed to uninstall artifact: " + artifact.getPath(), e);
+            log(Logger.LOG_WARNING, "Failed to uninstall artifact: " + artifact.getPath(), e);
         }
         return bundle;
     }
@@ -934,7 +973,8 @@
                 bundle = context.getBundle(artifact.getBundleId());
                 if (bundle == null)
                 {
-                    log("Failed to update bundle: "
+                    log(Logger.LOG_WARNING,
+                        "Failed to update bundle: "
                         + path + " with ID "
                         + artifact.getBundleId()
                         + ". The bundle has been uninstalled", null);
@@ -958,7 +998,8 @@
                 bundle = context.getBundle(artifact.getBundleId());
                 if (bundle == null)
                 {
-                    log("Failed to update bundle: "
+                    log(Logger.LOG_WARNING,
+                        "Failed to update bundle: "
                         + path + " with ID "
                         + artifact.getBundleId()
                         + ". The bundle has been uninstalled", null);
@@ -975,11 +1016,11 @@
                     in.close();
                 }
             }
-            log("Updated " + path, null);
+            log(Logger.LOG_DEBUG, "Updated " + path, null);
         }
         catch (Throwable t)
         {
-            log("Failed to update artifact " + artifact.getPath(), t);
+            log(Logger.LOG_WARNING, "Failed to update artifact " + artifact.getPath(), t);
         }
         return bundle;
     }
@@ -1026,13 +1067,12 @@
             try
             {
                 bundle.start();
-                log("Started bundle: " + bundle.getLocation(), null);
+                log(Logger.LOG_DEBUG, "Started bundle: " + bundle.getLocation(), null);
             }
             catch (BundleException e)
             {
-                log("Error while starting bundle: " + bundle.getLocation(), e);
+                log(Logger.LOG_WARNING, "Error while starting bundle: " + bundle.getLocation(), e);
             }
         }
     }
-
 }
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
index 26415b4..27ef3d0 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/FileInstall.java
@@ -30,6 +30,7 @@
 import org.apache.felix.fileinstall.ArtifactListener;
 import org.apache.felix.fileinstall.ArtifactTransformer;
 import org.apache.felix.fileinstall.ArtifactUrlTransformer;
+import org.apache.felix.fileinstall.internal.Util.Logger;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -73,7 +74,8 @@
         }
         catch (NoClassDefFoundError e)
         {
-            Util.log(context, 0, "ConfigAdmin is not available, some features will be disabled", e);
+            Util.log(context, Util.getGlobalLogLevel(context), Logger.LOG_DEBUG,
+                "ConfigAdmin is not available, some features will be disabled", e);
         }
 
         padmin = new ServiceTracker(context, PackageAdmin.class.getName(), null);
@@ -103,7 +105,7 @@
 
         set(ht, DirectoryWatcher.POLL);
         set(ht, DirectoryWatcher.DIR);
-        set(ht, DirectoryWatcher.DEBUG);
+        set(ht, DirectoryWatcher.LOG_LEVEL);
         set(ht, DirectoryWatcher.FILTER);
         set(ht, DirectoryWatcher.TMPDIR);
         set(ht, DirectoryWatcher.START_NEW_BUNDLES);
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java
index 6bbdad4..b098e16 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java
@@ -170,6 +170,24 @@
         return val;
     }
 
+    public static int getGlobalLogLevel(BundleContext context)
+    {
+        String s = (String) context.getProperty(DirectoryWatcher.LOG_LEVEL);
+        s = (s == null)
+            ? System.getProperty(DirectoryWatcher.LOG_LEVEL.toUpperCase().replace('.', '_'))
+            : s;
+        s = (s == null) ? "1" : s;
+        int logLevel = 1;
+        try
+        {
+            logLevel = Integer.parseInt(s);
+        }
+        catch (NumberFormatException ex)
+        {
+        }
+        return logLevel;
+    }
+
     /**
      * Log a message and optional throwable. If there is a log service we use
      * it, otherwise we log to the console
@@ -179,9 +197,10 @@
      * @param e
      *            The throwable to log
      */
-    public static void log(BundleContext context, long debug, String message, Throwable e)
+    public static void log(BundleContext context, int logLevel,
+        int msgLevel, String message, Throwable e)
     {
-        getLogger(context).log(debug > 0, message, e);
+        getLogger(context).log(logLevel, msgLevel, message, e);
     }
 
     private static Logger getLogger(BundleContext context)
@@ -206,8 +225,13 @@
 
     interface Logger
     {
+        static final int LOG_ERROR = 1;
+        static final int LOG_WARNING = 2;
+        static final int LOG_INFO = 3;
+        static final int LOG_DEBUG = 4;
+
         boolean isValidLogger(BundleContext context);
-        void log(boolean debug, java.lang.String message, java.lang.Throwable throwable);
+        void log(int logLevel, int msgLevel, String message, Throwable throwable);
     }
 
     static class StdOutLogger implements Logger
@@ -216,19 +240,25 @@
         {
             return true;
         }
-        public void log(boolean debug, String message, Throwable throwable)
+
+        public void log(int logLevel, int msgLevel, String message, Throwable throwable)
         {
-            System.out.println(message + (throwable == null ? "" : ": " + throwable));
-            if (debug && throwable != null)
+            // Only print the message if logging is enabled and
+            // the message level is less than or equal to the log
+            // level.
+            if ((logLevel > 0) && (msgLevel <= logLevel))
             {
-                throwable.printStackTrace(System.out);
+                System.out.println(message + ((throwable == null) ? "" : ": " + throwable));
+                if (throwable != null)
+                {
+                    throwable.printStackTrace(System.out);
+                }
             }
         }
     }
 
     static class OsgiLogger extends StdOutLogger
     {
-
         private BundleContext context;
 
         OsgiLogger(BundleContext context)
@@ -250,28 +280,23 @@
             return context == this.context;
         }
 
-        public void log(boolean debug, String message, Throwable throwable)
+        public void log(int logLevel, int msgLevel, String message, Throwable throwable)
         {
-            LogService log = getLogService();
-            if (log != null)
+            // Only print the message if logging is enabled and
+            // the message level is less than or equal to the log
+            // level.
+            if ((logLevel > 0) && (msgLevel <= logLevel))
             {
-                if (throwable != null)
+                LogService log = getLogService();
+                if (log != null)
                 {
-                    log.log(LogService.LOG_ERROR, message, throwable);
-                    if (debug)
-                    {
-                        throwable.printStackTrace();
-                    }
+                    log.log(msgLevel, message, throwable);
                 }
                 else
                 {
-                    log.log(LogService.LOG_INFO, message);
+                    super.log(logLevel, msgLevel, message, throwable);
                 }
             }
-            else
-            {
-                super.log(debug, message, throwable);
-            }
         }
 
         private LogService getLogService()
@@ -286,7 +311,6 @@
         }
     }
 
-
     /**
      * Jar up a directory
      *
diff --git a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
index a5f632e..0259007 100644
--- a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
+++ b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
@@ -150,7 +150,7 @@
     public void testParameterAfterInitialization()
     {
         props.put( DirectoryWatcher.POLL, "500" );
-        props.put( DirectoryWatcher.DEBUG, "1" );
+        props.put( DirectoryWatcher.LOG_LEVEL, "1" );
         props.put( DirectoryWatcher.START_NEW_BUNDLES, "false" );
         props.put( DirectoryWatcher.DIR, new File( "src/test/resources" ).getAbsolutePath() );
         props.put( DirectoryWatcher.TMPDIR, new File( "src/test/resources" ).getAbsolutePath() );
@@ -161,7 +161,7 @@
         dw = new DirectoryWatcher( props, mockBundleContext );
 
         assertEquals( "POLL parameter correctly read", 500l, dw.poll );
-        assertEquals( "DEBUG parameter correctly read", 1l, dw.debug );
+        assertEquals( "LOG_LEVEL parameter correctly read", 1, dw.logLevel );
         assertTrue( "DIR parameter correctly read", dw.watchedDirectory.getAbsolutePath().endsWith(
             "src" + File.separatorChar + "test" + File.separatorChar + "resources" ) );
         assertTrue( "TMPDIR parameter correctly read", dw.tmpDir.getAbsolutePath().endsWith(
@@ -182,7 +182,7 @@
         assertTrue( "DIR parameter correctly read", dw.watchedDirectory.getAbsolutePath().endsWith(
             "src" + File.separatorChar + "test" + File.separatorChar + "resources" ) );
         assertEquals( "Default POLL parameter correctly read", 2000l, dw.poll );
-        assertEquals( "Default DEBUG parameter correctly read", -1l, dw.debug );
+        assertEquals( "Default LOG_LEVEL parameter correctly read", 0, dw.logLevel );
         assertTrue( "Default TMPDIR parameter correctly read", dw.tmpDir.getAbsolutePath().startsWith(
                 new File(System.getProperty("java.io.tmpdir")).getAbsolutePath()) );
         assertEquals( "Default START_NEW_BUNDLES parameter correctly read", true, dw.startBundles );