WHIRR-722: Improve user and system level logging capability
diff --git a/CHANGES.txt b/CHANGES.txt
index f3fc5ba..98d82f8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -6,6 +6,8 @@
 
   IMPROVEMENTS
 
+    WHIRR-722. Improve user and system level logging capability. (graham)
+
     WHIRR-721. Improve robustness of volume device detection. (graham)
 
   BUG FIXES
diff --git a/conf/log4j-cli.xml b/conf/log4j-cli.xml
index e12dbbf..4d0b14b 100644
--- a/conf/log4j-cli.xml
+++ b/conf/log4j-cli.xml
@@ -23,13 +23,6 @@
 -->
 <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
     debug="false">
-    
-  <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> 
-    <param name="Threshold" value="INFO" />
-    <layout class="org.apache.log4j.PatternLayout"> 
-      <param name="ConversionPattern" value="%m%n"/> 
-    </layout> 
-  </appender>
   
   <appender name="ROLLINGFILE" class="org.apache.log4j.DailyRollingFileAppender">
     <param name="File" value="whirr.log" />
@@ -41,10 +34,8 @@
     </layout>
   </appender>
 
-  <logger name="org.apache.whirr" additivity="false">
-    <level value="DEBUG" />
-    <appender-ref ref="CONSOLE" />
-    <appender-ref ref="ROLLINGFILE" />
+  <logger name="org.apache.whirr">
+    <level value="INFO" />
   </logger>
 
   <logger name="jclouds.compute">
@@ -60,7 +51,6 @@
   </logger>
 
   <root>
-    <priority value="INFO" />
     <appender-ref ref="ROLLINGFILE" />
   </root>
 
diff --git a/core/src/main/java/org/apache/whirr/ClusterSpec.java b/core/src/main/java/org/apache/whirr/ClusterSpec.java
index 8ca973a..d0707c5 100644
--- a/core/src/main/java/org/apache/whirr/ClusterSpec.java
+++ b/core/src/main/java/org/apache/whirr/ClusterSpec.java
@@ -196,7 +196,9 @@
     
     KERBEROS_REALM(String.class, false, "Kerberos realm to use in security configuration"),
                              
-    AWS_EC2_PLACEMENT_GROUP(String.class, false, "If given, use this existing EC2 placement group. (aws-ec2 specific option)");
+    AWS_EC2_PLACEMENT_GROUP(String.class, false, "If given, use this existing EC2 placement group. (aws-ec2 specific option)"),
+    
+    QUIET(Boolean.class, false,  "Adjust user level, console logging verbosity.");
     
     private Class<?> type;
     private boolean multipleArguments;
@@ -329,6 +331,8 @@
 
   private Map<String,Node> byonNodes;
   
+  private boolean isQuiet;
+  
   public ClusterSpec() throws ConfigurationException {
     this(new PropertiesConfiguration());
   }
@@ -404,6 +408,8 @@
 
     setByonNodes(byonNodes);
     
+    setQuiet(config.getBoolean(Property.QUIET.getConfigName(), Boolean.FALSE));
+    
     Map<String, List<String>> fr = new HashMap<String, List<String>>();
     String firewallPrefix = Property.FIREWALL_RULES.getConfigName();
     Pattern firewallRuleKeyPattern = Pattern.compile("^".concat(Pattern.quote(firewallPrefix).concat("(?:\\.(.+))?$")));
@@ -609,6 +615,10 @@
     }
     return blobStoreProvider;
   }
+  
+  public boolean isQuiet() {
+    return isQuiet;
+  }
 
   /**
    * Probably jclouds should provide a similar mechanism
@@ -981,6 +991,10 @@
     this.byonNodes = byonNodes;
   }
   
+  public void setQuiet(boolean isQuiet) {
+    this.isQuiet = isQuiet;
+  }
+
   public void setVersion(String version) {
     this.version = version;
   }
@@ -1106,7 +1120,7 @@
         getByonNodes()
     );
   }
-  
+    
   public String toString() {
     return Objects.toStringHelper(this).omitNullValues()
       .add("instanceTemplates", getInstanceTemplates())
diff --git a/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java b/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java
index 71bc3da..5110761 100644
--- a/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java
+++ b/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java
@@ -80,17 +80,19 @@
         .describedAs("config.properties")
         .ofType(String.class);
 
-    parser.accepts("quiet", "Be less verbose");
-
     this.factory = factory;
     this.stateStoreFactory = stateStoreFactory;
 
     optionSpecs = Maps.newHashMap();
     for (Property property : EnumSet.allOf(Property.class)) {
-      ArgumentAcceptingOptionSpec<?> spec = parser
-        .accepts(property.getSimpleName(), property.getDescription())
-        .withRequiredArg()
-        .ofType(property.getType());
+      ArgumentAcceptingOptionSpec<?> spec = null;
+      if (property.getType().equals(Boolean.class)) {
+        spec = parser.accepts(property.getSimpleName(), property.getDescription()).withOptionalArg()
+            .ofType(property.getType());
+      } else {
+        spec = parser.accepts(property.getSimpleName(), property.getDescription()).withRequiredArg()
+            .ofType(property.getType());
+      }   
       if (property.hasMultipleArguments()) {
         spec.withValuesSeparatedBy(',');
       }
@@ -112,6 +114,9 @@
       } else {
         value = optionSet.valueOf(option);
       }
+      if (value == null && property.getType().equals(Boolean.class) && optionSet.has(property.getSimpleName())) {
+        value = Boolean.TRUE.toString();
+      }
       if (value != null) {
         optionsConfig.setProperty(property.getConfigName(), value);
       }
@@ -165,7 +170,7 @@
 
   protected void printProviderInfo(PrintStream out, PrintStream err,
       ClusterSpec clusterSpec, OptionSet optionSet) {
-    if (!optionSet.has("quiet")) {
+    if (!clusterSpec.isQuiet()) {
       out.println(String.format("Running on provider %s using identity %s", clusterSpec.getProvider(), clusterSpec.getIdentity()));
     }
   }
diff --git a/core/src/test/java/org/apache/whirr/command/AbstractClusterCommandTest.java b/core/src/test/java/org/apache/whirr/command/AbstractClusterCommandTest.java
index 2d6cb6f..d4486f6 100644
--- a/core/src/test/java/org/apache/whirr/command/AbstractClusterCommandTest.java
+++ b/core/src/test/java/org/apache/whirr/command/AbstractClusterCommandTest.java
@@ -48,14 +48,61 @@
     };
 
     Map<String, File> keys = KeyPair.generateTemporaryFiles();
-    OptionSet optionSet = clusterCommand.parser.parse(
+    OptionSet optionSet = clusterCommand.parser.parse("--quiet",
         "--service-name", "overridden-test-service",
         "--config", "whirr-override-test.properties",
         "--private-key-file", keys.get("private").getAbsolutePath()
     );
     ClusterSpec clusterSpec = clusterCommand.getClusterSpec(optionSet);
+    assertThat(optionSet.has("quiet"), is(true));
+    assertThat(clusterSpec.isQuiet(), is(true));
     assertThat(clusterSpec.getServiceName(), is("overridden-test-service"));
     assertThat(clusterSpec.getClusterName(), is("test-cluster"));
+    
+    optionSet = clusterCommand.parser.parse("--quiet", "true",
+        "--service-name", "overridden-test-service",
+        "--config", "whirr-override-test.properties",
+        "--private-key-file", keys.get("private").getAbsolutePath()
+    );
+     clusterSpec = clusterCommand.getClusterSpec(optionSet);
+    assertThat(optionSet.has("quiet"), is(true));
+    assertThat(clusterSpec.isQuiet(), is(true));
+    assertThat(clusterSpec.getServiceName(), is("overridden-test-service"));
+    assertThat(clusterSpec.getClusterName(), is("test-cluster"));
+
+    optionSet = clusterCommand.parser.parse("--quiet", "false",
+        "--service-name", "overridden-test-service",
+        "--config", "whirr-override-test.properties",
+        "--private-key-file", keys.get("private").getAbsolutePath()
+    );
+     clusterSpec = clusterCommand.getClusterSpec(optionSet);
+    assertThat(optionSet.has("quiet"), is(true));
+    assertThat(clusterSpec.isQuiet(), is(false));
+    assertThat(clusterSpec.getServiceName(), is("overridden-test-service"));
+    assertThat(clusterSpec.getClusterName(), is("test-cluster"));  
+  
+    optionSet = clusterCommand.parser.parse("--quiet", "some-value",
+        "--service-name", "overridden-test-service",
+        "--config", "whirr-override-test.properties",
+        "--private-key-file", keys.get("private").getAbsolutePath()
+    );
+     clusterSpec = clusterCommand.getClusterSpec(optionSet);
+    assertThat(optionSet.has("quiet"), is(true));
+    assertThat(clusterSpec.isQuiet(), is(false));
+    assertThat(clusterSpec.getServiceName(), is("overridden-test-service"));
+    assertThat(clusterSpec.getClusterName(), is("test-cluster"));
+    
+    optionSet = clusterCommand.parser.parse(
+        "--service-name", "overridden-test-service",
+        "--config", "whirr-override-test.properties",
+        "--private-key-file", keys.get("private").getAbsolutePath()
+    );
+     clusterSpec = clusterCommand.getClusterSpec(optionSet);
+    assertThat(optionSet.has("quiet"), is(false));
+    assertThat(clusterSpec.isQuiet(), is(false));
+    assertThat(clusterSpec.getServiceName(), is("overridden-test-service"));
+    assertThat(clusterSpec.getClusterName(), is("test-cluster"));
+    
   }
 
   /**
diff --git a/src/site/xdoc/configuration-guide.xml b/src/site/xdoc/configuration-guide.xml
index e30a6fd..0849e1a 100644
--- a/src/site/xdoc/configuration-guide.xml
+++ b/src/site/xdoc/configuration-guide.xml
@@ -88,6 +88,16 @@
         <td>Whether or not to automatically terminate all nodes when cluster
          launch fails for some reason.</td>
       </tr>
+      <tr valign="top">
+        <td>
+          <tt>whirr.quiet</tt>
+        </td>
+        <td>
+          <tt>--quiet</tt>
+        </td>
+        <td>false</td>
+        <td>Adjust user level, console logging verbosity. System level logs controlled via <tt>conf/log4j-cli.xml</tt>.</td>
+      </tr>
     </table>
     <subsection name="Instance Templates Options"></subsection>
     <table border="0">