SLING-4788 - SlingConfigurationPrinter should use mode aware and only stream the full logs in the zip version and avoid duplicate information

-- Added support for mode aware dumping of config. In zip mode the file content
    would not be added directly but would be added via url only
-- A brief summary would be added for all known files

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1692481 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/commons/log/logback/internal/SlingConfigurationPrinter.java b/src/main/java/org/apache/sling/commons/log/logback/internal/SlingConfigurationPrinter.java
index 151def6..90eb9b5 100644
--- a/src/main/java/org/apache/sling/commons/log/logback/internal/SlingConfigurationPrinter.java
+++ b/src/main/java/org/apache/sling/commons/log/logback/internal/SlingConfigurationPrinter.java
@@ -26,6 +26,10 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import ch.qos.logback.classic.spi.ILoggingEvent;
@@ -39,8 +43,10 @@
  * The <code>SlingConfigurationPrinter</code> is an Apache Felix Web Console
  * plugin to display the currently configured log files.
  */
+@SuppressWarnings("JavadocReference")
 public class SlingConfigurationPrinter {
     private static final CachingDateFormatter SDF = new CachingDateFormatter("yyyy-MM-dd HH:mm:ss");
+    private static final String MODE_ZIP = "zip";
     private final LogbackManager logbackManager;
 
     public SlingConfigurationPrinter(LogbackManager logbackManager) {
@@ -51,38 +57,70 @@
      * @see org.apache.felix.webconsole.ConfigurationPrinter#printConfiguration(java.io.PrintWriter)
      */
     @SuppressWarnings("UnusedDeclaration")
-    public void printConfiguration(PrintWriter printWriter) {
+    public void printConfiguration(PrintWriter printWriter, String mode) {
         LogbackManager.LoggerStateContext ctx = logbackManager.determineLoggerState();
-        dumpLogbackStatus(logbackManager, printWriter);
-        for (Appender<ILoggingEvent> appender : ctx.getAllAppenders()) {
-            if (appender instanceof FileAppender) {
-                final File file = new File(((FileAppender) appender).getFile());
-                if (file.exists()) {
-                    printWriter.print("Log file ");
-                    printWriter.println(file.getAbsolutePath());
-                    printWriter.println("--------------------------------------------------");
-                    FileReader fr = null;
-                    try {
-                        fr = new FileReader(file);
-                        final char[] buffer = new char[512];
-                        int len;
-                        while ((len = fr.read(buffer)) != -1) {
-                            printWriter.write(buffer, 0, len);
-                        }
-                    } catch (IOException ignore) {
-                        // we just ignore this
-                    } finally {
-                        if (fr != null) {
-                            try {
-                                fr.close();
-                            } catch (IOException ignored) {
+
+        dumpLogFileSummary(printWriter, ctx.getAllAppenders());
+
+        if (!MODE_ZIP.equals(mode)) {
+            for (Appender<ILoggingEvent> appender : ctx.getAllAppenders()) {
+                if (appender instanceof FileAppender) {
+                    final File file = new File(((FileAppender) appender).getFile());
+                    if (file.exists()) {
+                        printWriter.print("Log file ");
+                        printWriter.println(file.getAbsolutePath());
+                        printWriter.println("--------------------------------------------------");
+                        FileReader fr = null;
+                        try {
+                            fr = new FileReader(file);
+                            final char[] buffer = new char[512];
+                            int len;
+                            while ((len = fr.read(buffer)) != -1) {
+                                printWriter.write(buffer, 0, len);
+                            }
+                        } catch (IOException ignore) {
+                            // we just ignore this
+                        } finally {
+                            if (fr != null) {
+                                try {
+                                    fr.close();
+                                } catch (IOException ignored) {
+                                }
                             }
                         }
+                        printWriter.println();
                     }
-                    printWriter.println();
                 }
             }
         }
+
+        dumpLogbackStatus(logbackManager, printWriter);
+    }
+
+    private void dumpLogFileSummary(PrintWriter pw, Collection<Appender<ILoggingEvent>> appenders) {
+        pw.println("Summary");
+        pw.println("=======");
+        pw.println();
+        int counter = 0;
+        final String rootDir = logbackManager.getRootDir();
+        for (Appender<ILoggingEvent> appender : appenders) {
+            if (appender instanceof FileAppender) {
+                File file = new File(((FileAppender) appender).getFile());
+                final File dir = file.getParentFile();
+                final String baseName = file.getName();
+                String absolutePath = dir.getAbsolutePath();
+                String displayName = ((FileAppender) appender).getFile();
+                if (absolutePath.startsWith(rootDir)) {
+                    displayName = baseName;
+                }
+                pw.printf("%d. %s %n", ++counter, displayName);
+                final File[] files = getRotatedFiles((FileAppender) appender);
+                for (File f : files) {
+                    pw.printf("  - %s, %s, %s %n", f.getName(), humanReadableByteCount(f.length()), getModifiedDate(f));
+                }
+            }
+        }
+        pw.println();
     }
 
     /**
@@ -96,7 +134,7 @@
     @SuppressWarnings("UnusedDeclaration")
     public URL[] getAttachments(String mode) {
         // we only provide urls for mode zip
-        if ("zip".equals(mode)) {
+        if (MODE_ZIP.equals(mode)) {
             final List<URL> urls = new ArrayList<URL>();
             LogbackManager.LoggerStateContext ctx = logbackManager.determineLoggerState();
             for (Appender<ILoggingEvent> appender : ctx.getAllAppenders()) {
@@ -127,12 +165,23 @@
         if (app instanceof RollingFileAppender) {
             final File dir = file.getParentFile();
             final String baseName = file.getName();
-            return dir.listFiles(new FilenameFilter() {
+            File[] result = dir.listFiles(new FilenameFilter() {
                 @Override
                 public boolean accept(File dir, String name) {
                     return name.startsWith(baseName);
                 }
             });
+
+            //Sort the files in reverse
+            Arrays.sort(result, Collections.reverseOrder(new Comparator<File>() {
+                @Override
+                public int compare(File o1, File o2) {
+                    long o1t = o1.lastModified();
+                    long o2t = o2.lastModified();
+                    return o1t < o2t ? -1 : (o1t == o2t ? 0 : 1);
+                }
+            }));
+            return result;
         }
 
         //Not a RollingFileAppender then just return the actual file
@@ -170,4 +219,29 @@
         return null;
     }
 
+    /**
+     * Returns a human-readable version of the file size, where the input represents
+     * a specific number of bytes. Based on http://stackoverflow.com/a/3758880/1035417
+     */
+    private static String humanReadableByteCount(long bytes) {
+        if (bytes < 0) {
+            return "0";
+        }
+        int unit = 1000;
+        if (bytes < unit) {
+            return bytes + " B";
+        }
+        int exp = (int) (Math.log(bytes) / Math.log(unit));
+        char pre = "kMGTPE".charAt(exp - 1);
+        return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
+    }
+
+    private static String getModifiedDate(File f){
+        long modified = f.lastModified();
+        if (modified == 0){
+            return "UNKNOWN";
+        }
+        return SDF.format(modified);
+    }
+
 }