sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1492763 - in /sis/branches/JDK7: application/sis-console/src/main/java/org/apache/sis/console/ core/sis-utility/src/main/java/org/apache/sis/internal/util/ core/sis-utility/src/main/java/org/apache/sis/util/logging/ core/sis-utility/src/te...
Date Thu, 13 Jun 2013 17:00:46 GMT
Author: desruisseaux
Date: Thu Jun 13 17:00:45 2013
New Revision: 1492763

URL: http://svn.apache.org/r1492763
Log:
Some cleaning in MonolineFormatter.

Modified:
    sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/Command.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/PerformanceLevel.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/X364Test.java

Modified: sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/Command.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/Command.java?rev=1492763&r1=1492762&r2=1492763&view=diff
==============================================================================
--- sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/Command.java [UTF-8] (original)
+++ sis/branches/JDK7/application/sis-console/src/main/java/org/apache/sis/console/Command.java [UTF-8] Thu Jun 13 17:00:45 2013
@@ -26,7 +26,6 @@ import org.opengis.referencing.operation
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.logging.MonolineFormatter;
 
 
@@ -224,7 +223,7 @@ public final class Command {
      * @param args Command-line options.
      */
     public static void main(final String[] args) {
-        MonolineFormatter.configureConsoleHandler(Logging.getLogger(""), null);
+        MonolineFormatter.install();
         final Command c;
         try {
             c = new Command(args);

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java?rev=1492763&r1=1492762&r2=1492763&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java [UTF-8] Thu Jun 13 17:00:45 2013
@@ -16,7 +16,9 @@
  */
 package org.apache.sis.internal.util;
 
+import java.util.Arrays;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -37,18 +39,18 @@ import org.apache.sis.util.CharSequences
  * @see org.apache.sis.io.wkt.Colors
  */
 public enum X364 {
-    /** Reset all attributes to their default value. */ RESET               ((byte)  0),
-    /** Normal intensity (not {@link #BOLD}).        */ NORMAL              ((byte) 22),
-    /** Bold intensity.                              */ BOLD                ((byte)  1),
-    /** Faint intensity.                             */ FAINT               ((byte)  2),
-    /** Red foreground color, normal intensity.      */ FOREGROUND_RED      ((byte) 31),
-    /** Green foreground color, normal intensity.    */ FOREGROUND_GREEN    ((byte) 32),
-    /** Yellow foreground color, normal intensity.   */ FOREGROUND_YELLOW   ((byte) 33),
-    /** Blue foreground color, normal intensity.     */ FOREGROUND_BLUE     ((byte) 34),
-    /** Magenta foreground color, normal intensity.  */ FOREGROUND_MAGENTA  ((byte) 35),
-    /** Cyan foreground color, normal intensity.     */ FOREGROUND_CYAN     ((byte) 36),
-    /** Gray foreground color, normal intensity.     */ FOREGROUND_GRAY     ((byte) 37),
-    /** Reset the foreground color.                  */ FOREGROUND_DEFAULT  ((byte) 39),
+    /** Reset all attributes to their default value. */ RESET               ((byte)  0, null),
+    /** Normal intensity (not {@link #BOLD}).        */ NORMAL              ((byte) 22, null),
+    /** Bold intensity.                              */ BOLD                ((byte)  1, null),
+    /** Faint intensity.                             */ FAINT               ((byte)  2, null),
+    /** Red foreground color, normal intensity.      */ FOREGROUND_RED      ((byte) 31, "red"),
+    /** Green foreground color, normal intensity.    */ FOREGROUND_GREEN    ((byte) 32, "green"),
+    /** Yellow foreground color, normal intensity.   */ FOREGROUND_YELLOW   ((byte) 33, "yellow"),
+    /** Blue foreground color, normal intensity.     */ FOREGROUND_BLUE     ((byte) 34, "blue"),
+    /** Magenta foreground color, normal intensity.  */ FOREGROUND_MAGENTA  ((byte) 35, "magenta"),
+    /** Cyan foreground color, normal intensity.     */ FOREGROUND_CYAN     ((byte) 36, "cyan"),
+    /** Gray foreground color, normal intensity.     */ FOREGROUND_GRAY     ((byte) 37, "gray"),
+    /** Reset the foreground color.                  */ FOREGROUND_DEFAULT  ((byte) 39, null),
     /** Red background color, normal intensity.      */ BACKGROUND_RED      (FOREGROUND_RED),
     /** Green background color, normal intensity.    */ BACKGROUND_GREEN    (FOREGROUND_GREEN),
     /** Yellow background color, normal intensity.   */ BACKGROUND_YELLOW   (FOREGROUND_YELLOW),
@@ -59,6 +61,17 @@ public enum X364 {
     /** Reset the background color.                  */ BACKGROUND_DEFAULT  (FOREGROUND_DEFAULT);
 
     /**
+     * The list of codes having a non-null {@linkplain #color} name.
+     * They are the codes in the range 31 to 37 inclusive.
+     *
+     * @see #forColorName(String)
+     */
+    private static final X364[] NAMED;
+    static {
+        NAMED = Arrays.copyOfRange(values(), 4, 11);
+    }
+
+    /**
      * The first character of the {@link #START} escape string.
      */
     public static final char ESCAPE = '\u001B';
@@ -96,12 +109,19 @@ public enum X364 {
     private transient X364 foreground, background;
 
     /**
+     * The color name, or {@code null} if none.
+     */
+    public final String color;
+
+    /**
      * Creates a new code.
      *
-     * @param code The X.364 code.
+     * @param code  The X.364 numerical code.
+     * @param color The color name, or {@code null} if none.
      */
-    private X364(final byte code) {
+    private X364(final byte code, final String color) {
         this.code  = code;
+        this.color = color;
         foreground = this;
         background = this;
     }
@@ -112,7 +132,7 @@ public enum X364 {
      * @param code The X.364 code.
      */
     private X364(final X364 foreground) {
-        this((byte) (foreground.code + 10));
+        this((byte) (foreground.code + 10), foreground.color);
         this.foreground = foreground;
         this.background = foreground.background = this;
     }
@@ -230,6 +250,24 @@ search: do {
     }
 
     /**
+     * Returns the enumeration value for the given color name.
+     * The search is case-insensitive.
+     *
+     * @param  color The color name.
+     * @return The code for the given color name.
+     * @throws IllegalArgumentException If no code has been found for the given color name.
+     */
+    public static X364 forColorName(String color) throws IllegalArgumentException {
+        color = CharSequences.trimWhitespaces(color);
+        for (final X364 code : NAMED) {
+            if (color.equalsIgnoreCase(code.color)) {
+                return code;
+            }
+        }
+        throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "color", color));
+    }
+
+    /**
      * Returns {@code true} if we think that the operating system supports ANSI sequences.
      * This method performs a very naive and approximative check. Result is just a hint and
      * may be wrong.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java?rev=1492763&r1=1492762&r2=1492763&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/Logging.java [UTF-8] Thu Jun 13 17:00:45 2013
@@ -204,7 +204,7 @@ public final class Logging extends Stati
      * @param  logger Where to log the error.
      * @param  error  The error that occurred.
      * @return {@code true} if the error has been logged, or {@code false} if the logger
-     *         doesn't log anything at the {@link Level#WARNING WARNING} level.
+     *         doesn't log anything at {@link Level#WARNING}.
      */
     public static boolean unexpectedException(final Logger logger, final Throwable error) {
         return unexpectedException(logger, null, null, error, Level.WARNING);
@@ -235,7 +235,7 @@ public final class Logging extends Stati
      * @param method  The method where the error occurred, or {@code null}.
      * @param error   The error.
      * @return {@code true} if the error has been logged, or {@code false} if the logger
-     *         doesn't log anything at the {@link Level#WARNING WARNING} level.
+     *         doesn't log anything at {@link Level#WARNING}.
      *
      * @see #recoverableException(Logger, Class, String, Throwable)
      * @see #severeException(Logger, Class, String, Throwable)
@@ -255,7 +255,7 @@ public final class Logging extends Stati
      * @param method  The method where the error occurred, or {@code null}.
      * @param error   The error.
      * @return {@code true} if the error has been logged, or {@code false} if the logger
-     *         doesn't log anything at the {@link Level#WARNING WARNING} level.
+     *         doesn't log anything at {@link Level#WARNING}.
      *
      * @see #recoverableException(Class, String, Throwable)
      */
@@ -392,6 +392,27 @@ public final class Logging extends Stati
     }
 
     /**
+     * Invoked when an unexpected error occurred while configuring the system. The error shall not
+     * prevent the application from working, but may change the behavior in some minor aspects.
+     *
+     * {@example if the <code>org.apache.sis.util.logging.MonolineFormatter.time</code> pattern declared
+     * in the <code>jre/lib/logging.properties</code> file is illegal, then <code>MonolineFormatter</code>
+     * while log this problem and use a default time pattern.}
+     *
+     * @param classe  The class where the error occurred.
+     * @param method  The method name where the error occurred.
+     * @param error   The error.
+     * @return {@code true} if the error has been logged, or {@code false} if the logger
+     *         doesn't log anything at {@link Level#CONFIG}.
+     *
+     * @see #unexpectedException(Class, String, Throwable)
+     */
+    static boolean configurationException(final Class<?> classe, final String method, final Throwable error) {
+        final String classname = (classe != null) ? classe.getName() : null;
+        return unexpectedException(null, classname, method, error, Level.CONFIG);
+    }
+
+    /**
      * Invoked when a recoverable error occurs. This method is similar to
      * {@link #unexpectedException(Class,String,Throwable) unexpectedException}
      * except that it doesn't log the stack trace and uses a lower logging level.
@@ -400,13 +421,11 @@ public final class Logging extends Stati
      * @param method  The method name where the error occurred.
      * @param error   The error.
      * @return {@code true} if the error has been logged, or {@code false} if the logger
-     *         doesn't log anything at the {@link Level#FINE FINE} level.
+     *         doesn't log anything at {@link Level#FINE}.
      *
      * @see #unexpectedException(Class, String, Throwable)
      */
-    public static boolean recoverableException(final Class<?> classe, final String method,
-                                               final Throwable error)
-    {
+    public static boolean recoverableException(final Class<?> classe, final String method, final Throwable error) {
         return recoverableException(null, classe, method, error);
     }
 
@@ -420,7 +439,7 @@ public final class Logging extends Stati
      * @param method  The method name where the error occurred.
      * @param error   The error.
      * @return {@code true} if the error has been logged, or {@code false} if the logger
-     *         doesn't log anything at the {@link Level#FINE FINE} level.
+     *         doesn't log anything at {@link Level#FINE}.
      *
      * @see #unexpectedException(Logger, Class, String, Throwable)
      * @see #severeException(Logger, Class, String, Throwable)
@@ -442,7 +461,7 @@ public final class Logging extends Stati
      * @param method  The method name where the error occurred.
      * @param error   The error.
      * @return {@code true} if the error has been logged, or {@code false} if the logger
-     *         doesn't log anything at the {@link Level#SEVERE SEVERE} level.
+     *         doesn't log anything at {@link Level#SEVERE}.
      *
      * @see #unexpectedException(Logger, Class, String, Throwable)
      * @see #recoverableException(Logger, Class, String, Throwable)

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java?rev=1492763&r1=1492762&r2=1492763&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java [UTF-8] Thu Jun 13 17:00:45 2013
@@ -23,6 +23,7 @@ import java.text.FieldPosition;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.TimeZone;
+import java.util.Locale;
 import java.util.Arrays;
 import java.util.TreeMap;
 import java.util.SortedMap;
@@ -32,27 +33,42 @@ import net.jcip.annotations.ThreadSafe;
 import org.apache.sis.internal.system.OS;
 import org.apache.sis.internal.util.X364;
 import org.apache.sis.io.IO;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.io.LineAppender;
-
-// Related to JDK7
-import java.util.Objects;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.Configuration;
+import org.apache.sis.util.Debug;
 
 
 /**
- * A formatter writing log messages on a single line. Compared to {@link SimpleFormatter}, this
- * formatter uses only one line per message instead of two. For example a message formatted by
- * {@code MonolineFormatter} looks like:
+ * A formatter writing log messages on a single line. Compared to the JDK {@link SimpleFormatter},
+ * this formatter uses only one line per message instead of two. For example messages formatted by
+ * {@code MonolineFormatter} may look like:
  *
- * {@preformat text
- *     FINE   A log message logged with level FINE from the "org.apache.sis.util" logger.
- * }
+ * <blockquote><table style="color:#FFFFFF; background:black" class="compact">
+ * <tr><td style="background:blue"><code>CONFIG</code></td>
+ *     <td><code><b>[MyApplication]</b> Read configuration from “my-application/setup.xml”.</code></td>
+ * <tr><td style="background:green"><code>INFO</code></td>
+ *     <td><code><b>[DirectEpsgFactory]</b> Connected to the EPSG database version 6.9 on JavaDB 10.8.</code></td>
+ * <tr><td style="background:goldenrod"><code>WARNING</code></td>
+ *     <td><code><b>[DefaultTemporalExtent]</b> This operation requires the “sis-temporal” module.</code></td>
+ * </table></blockquote>
+ *
+ * By default, {@code MonolineFormatter} shows only the level and the message. One or two additional
+ * fields can be inserted between the level and the message if the {@link #setTimeFormat(String)} or
+ * {@link #setSourceFormat(String)} methods are invoked with o non-null argument. Examples:
+ *
+ * <ul>
+ *   <li>{@code setTimeFormat("HH:mm:ss")} for formatting the time like {@code 00:00:04"},
+ *       as time elapsed since the {@code MonolineFormatter} creation time.</li>
+ *   <li>{@code setSourceFormat("logger:long")} for formatting the full logger name
+ *       (e.g. {@code "org.apache.sis.storage.netcdf"}).</li>
+ *   <li>{@code setSourceFormat("class:short")} for formatting the short class name,
+ *       without package (e.g. {@code "NetcdfStore"}).</li>
+ * </ul>
  *
- * By default, {@code MonolineFormatter} displays only the level and the message. Additional
- * fields can be formatted if {@link #setTimeFormat(String)} or {@link #setSourceFormat(String)}
- * methods are invoked with a non-null argument. The format can also be set from the
- * {@code jre/lib/logging.properties} file. For example, user can cut and paste the following
- * properties into {@code logging.properties}:
+ * {@section Configuration from <code>logging.properties</code>}
+ * The format can also be set from the {@code jre/lib/logging.properties} file.
+ * For example, user can cut and paste the following properties into {@code logging.properties}:
  *
  * {@preformat text
  *     ###########################################################################
@@ -73,12 +89,12 @@ import java.util.Objects;
  *     org.apache.sis.util.logging.MonolineFormatter.source = class:short
  * }
  *
- * The example below sets the {@code MonolineFormatter} for the whole system with level {@code FINE}
- * and {@code "Cp850"} page encoding (which is appropriate for some DOS console on old Windows).
+ * See {@link #setTimeFormat(String)} and {@link #setSourceFormat(String)} for more information about the
+ * above {@code time} and {@code source} properties. Encoding and logging level are configured separately,
+ * typically on the JDK {@link ConsoleHandler} like below:
  *
  * {@preformat text
- *     java.util.logging.ConsoleHandler.formatter = org.apache.sis.util.logging.MonolineFormatter
- *     java.util.logging.ConsoleHandler.encoding = Cp850
+ *     java.util.logging.ConsoleHandler.encoding = UTF-8
  *     java.util.logging.ConsoleHandler.level = FINE
  * }
  *
@@ -86,27 +102,23 @@ import java.util.Objects;
  * @since   0.3 (derived from geotk-2.0)
  * @version 0.3
  * @module
+ *
+ * @see SimpleFormatter
+ * @see Handler#setFormatter(Formatter)
  */
 @ThreadSafe
 public class MonolineFormatter extends Formatter {
-    /**
-     * The string to write before any log message.
-     */
-    private static final String MARGIN = "";
-
     /** Do not format source class name.       */ private static final int NO_SOURCE    = 0;
-    /** Explicit value for 'none'.             */ private static final int NO_SOURCE_EX = 1;
-    /** Format the source logger without base. */ private static final int LOGGER_SHORT = 2;
-    /** Format the source logger only.         */ private static final int LOGGER_LONG  = 3;
-    /** Format the class name without package. */ private static final int CLASS_SHORT  = 4;
-    /** Format the fully qualified class name. */ private static final int CLASS_LONG   = 5;
+    /** Format the source logger without base. */ private static final int LOGGER_SHORT = 1;
+    /** Format the source logger only.         */ private static final int LOGGER_LONG  = 2;
+    /** Format the class name without package. */ private static final int CLASS_SHORT  = 3;
+    /** Format the fully qualified class name. */ private static final int CLASS_LONG   = 4;
 
     /**
      * The label to use in the {@code logging.properties} for setting the source format.
      */
-    private static final String[] FORMAT_LABELS = new String[6];
+    private static final String[] FORMAT_LABELS = new String[5];
     static {
-        FORMAT_LABELS[NO_SOURCE_EX] = "none";
         FORMAT_LABELS[LOGGER_SHORT] = "logger:short";
         FORMAT_LABELS[LOGGER_LONG ] = "logger:long";
         FORMAT_LABELS[ CLASS_SHORT] = "class:short";
@@ -114,15 +126,14 @@ public class MonolineFormatter extends F
     }
 
     /**
-     * Logs at level below this threshold will be printed in faint color.
-     * Logs at this level or above will be printed in normal color. This
-     * threshold is set to the default level of console handlers.
+     * Log records at level below this threshold will be printed in faint color.
+     * Logs records at this level or above will be printed in normal color.
+     * This threshold is set to the default level of console handlers.
      */
     private static final Level LEVEL_THRESHOLD = Level.INFO;
 
     /**
-     * A comparator for logging level. This comparator sorts finest levels first
-     * and severe levels last.
+     * A comparator for logging level. This comparator sorts finest levels first and severe levels last.
      */
     private static final Comparator<Level> COMPARATOR = new Comparator<Level>() {
         @Override public int compare(final Level l1, final Level l2) {
@@ -137,16 +148,33 @@ public class MonolineFormatter extends F
     };
 
     /**
-     * Minimal number of stack trace elements to print before and after the "interesting".
-     * elements. The "interesting" elements are the first stack trace elements, and the
-     * element which point to the method that produced the log record.
+     * Whether the logging level should be visible or not.
+     * We do not provide the option to hide the levels for now.
+     */
+    private static final boolean SHOW_LEVEL = true;
+
+    /**
+     * Minimal number of stack trace elements to print before and after the "interesting" elements.
+     * The "interesting" elements are the first stack trace elements, and the element which point
+     * to the method that produced the log record.
      *
-     * @see #printAbridged(Throwable, PrintWriter, String, String, String)
+     * @see #printAbridged(Throwable, Appendable, String, String, String, String)
      */
     private static final int CONTEXT_STACK_TRACE_ELEMENTS = 2;
 
     /**
+     * The string to write on the left side of the first line of every log records.
+     * The default value is an empty string. This field can not be null.
+     *
+     * @see #getHeader()
+     * @see #setHeader(String)
+     */
+    private String header = "";
+
+    /**
      * The colors to apply, or {@code null} if none.
+     *
+     * @see #colors()
      */
     private SortedMap<Level,X364> colors;
 
@@ -183,7 +211,7 @@ public class MonolineFormatter extends F
     /**
      * The format to use for formatting elapsed time, or {@code null} if there is none.
      */
-    private SimpleDateFormat timeFormat = null;
+    private SimpleDateFormat timeFormat;
 
     /**
      * One of the following constants: {@link #NO_SOURCE}, {@link #LOGGER_SHORT},
@@ -192,27 +220,35 @@ public class MonolineFormatter extends F
     private int sourceFormat = NO_SOURCE;
 
     /**
-     * Buffer for formatting messages. We will reuse this buffer in order to reduce memory
-     * allocations. This is the buffer used internally by {@link #writer}.
+     * Buffer for formatting messages. We will reuse this buffer in order to reduce memory allocations.
+     * This is the buffer used internally by {@link #writer}.
      */
     private final StringBuffer buffer;
 
     /**
      * The line writer. This object transforms all {@code "\r"}, {@code "\n"} or {@code "\r\n"}
      * occurrences into a single line separator. This line separator will include space for the
-     * margin, if needed.
+     * left margin, if needed.
      */
     private final LineAppender writer;
 
     /**
+     * The printer wrapping the {@link #writer}. This is used for {@link Throwable#printStackTrace(PrintWriter)} calls.
+     * We don't use the printer for other usage in order to avoid unnecessary indirections and synchronizations.
+     */
+    private final PrintWriter printer;
+
+    /**
      * Constructs a default {@code MonolineFormatter}.
      *
      * {@section Auto-configuration from the handler}
      * Formatters are often associated to a particular handler. If this handler is known, giving it at
-     * construction time can help this formatter to configure itself. This handler is only a hint - no
-     * reference to this handler will be kept.
+     * construction time can help this formatter to configure itself. This handler is only a hint - it
+     * will not be modified, and no reference to that handler will be kept by this constructor.
      *
      * @param handler The handler to be used with this formatter, or {@code null} if unknown.
+     *
+     * @see Handler#setFormatter(Formatter)
      */
     public MonolineFormatter(final Handler handler) {
         this.startMillis = System.currentTimeMillis();
@@ -241,30 +277,23 @@ loop:   for (int i=0; ; i++) {
             }
         }
         /*
-         * Creates the buffer and the printer. We will expand the tabulations with 4 characters.
-         * This apply to the stack trace formatted by Throwable.printStackTrace(PrintWriter);
-         * The default (8 characters) is a bit wide...
-         */
-        final StringWriter str = new StringWriter();
-        writer = new LineAppender(str, System.lineSeparator(), true);
-        buffer = str.getBuffer().append(MARGIN);
-        writer.setTabulationWidth(4);
-        /*
          * Configures this formatter according the properties, if any.
          */
         final LogManager manager = LogManager.getLogManager();
         final String classname = MonolineFormatter.class.getName();
+        header = manager.getProperty(classname + ".header");
+        if (header == null) {
+            header = "";
+        }
         try {
-            setTimeFormat(manager.getProperty(classname + ".time"));
+            timeFormat(manager.getProperty(classname + ".time"));
         } catch (IllegalArgumentException exception) {
-            // Can't use the logging framework, since we are configuring it.
-            // Display the exception name only, not the trace.
-            System.err.println(exception);
+            Logging.configurationException(MonolineFormatter.class, "<init>", exception);
         }
         try {
-            setSourceFormat(manager.getProperty(classname + ".source"));
+            sourceFormat(manager.getProperty(classname + ".source"));
         } catch (IllegalArgumentException exception) {
-            System.err.println(exception);
+            Logging.configurationException(MonolineFormatter.class, "<init>", exception);
         }
         /*
          * Applies the default set of colors only if the handler is writing to the console.
@@ -274,39 +303,77 @@ loop:   for (int i=0; ; i++) {
          * printing in an other console (e.g. using the Unix "tail" command).
          */
         if (handler instanceof ConsoleHandler && X364.isAnsiSupported()) {
-            colors = new TreeMap<>(COMPARATOR);
-            final SortedMap<Level,X364> colors = this.colors;
-            colors.put(Level.ALL,     X364.BACKGROUND_GRAY);
-            colors.put(Level.CONFIG,  X364.BACKGROUND_BLUE);
-            colors.put(Level.INFO,    X364.BACKGROUND_GREEN);
-            colors.put(Level.WARNING, X364.BACKGROUND_YELLOW);
-            colors.put(Level.SEVERE,  X364.BACKGROUND_RED);
-            colors.put(PerformanceLevel.PERFORMANCE, X364.BACKGROUND_CYAN);
+            resetLevelColors();
         }
         faintSupported = OS.current() != OS.MAC_OS;
+        /*
+         * Creates the buffer and the printer. We will expand the tabulations with 4 characters.
+         * This apply to the stack trace formatted by Throwable.printStackTrace(PrintWriter);
+         * The default (8 characters) is a little bit too wide...
+         */
+        final StringWriter str = new StringWriter();
+        writer  = new LineAppender(str, System.lineSeparator(), true);
+        buffer  = str.getBuffer().append(header);
+        printer = new PrintWriter(IO.asWriter(writer));
+        writer.setTabulationWidth(4);
     }
 
     /**
-     * Returns the format for displaying elapsed time. This is the pattern specified
-     * to the last call to {@link #setTimeFormat}, or the patten specified in the
+     * Returns the string to write on the left side of the first line of every log records, or {@code null} if none.
+     * This is a string to be shown just before the level.
+     *
+     * @return The string to write on the left side of the first line of every log records, or {@code null} if none.
+     */
+    public synchronized String getHeader() {
+        // All other properties in MonolineFormatter are defined in such a way
+        // that null means "none", so we do the same here for consistency.
+        return header.isEmpty() ? null : header;
+    }
+
+    /**
+     * Sets the string to write on the left side of the first line of every log records.
+     *
+     * @param header The string to write on the left side of the first line of every log records,
+     *        or {@code null} if none.
+     */
+    public synchronized void setHeader(String header) {
+        if (header == null) { // See comment in getHeader().
+            header = "";
+        }
+        this.header = header;
+    }
+
+    /**
+     * Returns the format for elapsed time, or {@code null} if the time is not shown.
+     * This method returns the pattern specified by the last call to the
+     * {@link #setTimeFormat(String)} method, or the patten specified by the
      * {@code org.apache.sis.util.logging.MonolineFormatter.time} property in the
      * {@code jre/lib/logging.properties} file.
      *
-     * @return The time pattern, or {@code null} if time is not formatted.
+     * @return The time pattern, or {@code null} if elapsed time is not formatted.
      */
     public synchronized String getTimeFormat() {
         return (timeFormat != null) ? timeFormat.toPattern() : null;
     }
 
     /**
-     * Sets the format for displaying elapsed time. The pattern must matches the format specified
-     * in {@link SimpleDateFormat}, but for the time part only (not the date). For example, the
-     * pattern {@code "HH:mm:ss.SSS"} will display the elapsed time in hours, minutes, seconds
-     * and milliseconds.
+     * Sets the format for elapsed time, or hides the time field. The pattern must matches the
+     * format specified in {@link SimpleDateFormat}, but for the time part only (no date).
      *
-     * @param pattern The time patter, or {@code null} to disable time formatting.
+     * {@example The <code>"HH:mm:ss.SSS"</code> pattern will display the elapsed time in hours,
+     * minutes, seconds and milliseconds.}
+     *
+     * @param  pattern The time pattern, or {@code null} to disable time formatting.
+     * @throws IllegalArgumentException If the given pattern is invalid.
      */
-    public synchronized void setTimeFormat(final String pattern) {
+    public synchronized void setTimeFormat(final String pattern) throws IllegalArgumentException {
+        timeFormat(pattern);
+    }
+
+    /**
+     * Implementation of {@link #setTimeFormat(String)}, to be invoked also by the constructor.
+     */
+    private void timeFormat(String pattern) throws IllegalArgumentException {
         if (pattern == null) {
             timeFormat = null;
         } else if (timeFormat == null) {
@@ -318,44 +385,50 @@ loop:   for (int i=0; ; i++) {
     }
 
     /**
-     * Returns the format for displaying the source. This is the pattern specified
-     * to the last call to {@link #setSourceFormat}, or the patten specified in the
+     * Returns the format for the source, or {@code null} is the source is not shown.
+     * This method returns the source format specified by the last call to the
+     * {@link #setSourceFormat(String)} method, or the format specified by the
      * {@code org.apache.sis.util.logging.MonolineFormatter.source} property in the
      * {@code jre/lib/logging.properties} file.
      *
-     * @return The source pattern, or {@code null} if source is not formatted.
+     * @return The source format, or {@code null} if source is not formatted.
      */
     public synchronized String getSourceFormat() {
         return FORMAT_LABELS[sourceFormat];
     }
 
     /**
-     * Sets the format for displaying the source. The pattern can be {@code null}, {@code "none"},
-     * {@code "logger:short"}, {@code "class:short"}, {@code "logger:long"} or {@code "class:long"}.
-     * The 4 last choices are made of two parts separated by a {@code ':'} character:
-     *
-     * <ol>
-     *   <li>{@code "logger"} for the {@linkplain LogRecord#getLoggerName logger name}, or
-     *       {@code "class"} for the {@linkplain LogRecord#getSourceClassName source class name}.
-     *       The source class name usually contains the logger name since (by convention) logger
-     *       names are package names, but this is not mandatory neither enforced.</li>
-     *
-     *   <li>{@code "long"} for the full logger or class name, or {@code "short"} for only
-     *       the part following the last dot character.</li>
-     * </ol>
-     *
-     * The difference between a {@code null} and {@code "none"} is that {@code null}
-     * may be replaced by a default value, while {@code "none"} means that the caller
-     * explicitly requested no source.
-     *
-     * @param format The format for displaying the source.
-     */
-    public synchronized void setSourceFormat(String format) {
-        if (format != null) {
-            format = format.trim().toLowerCase();
+     * Sets the format for displaying the source, or hides the source field.
+     * The given format can be any of the following values, from more verbose to less verbose:
+     *
+     * <ul>
+     *   <li>{@code null} for hiding the source field.</li>
+     *   <li>{@code "class:long"}   for the {@linkplain LogRecord#getSourceClassName() source class name}</li>
+     *   <li>{@code "logger:long"}  for the {@linkplain LogRecord#getLoggerName() logger name}</li>
+     *   <li>{@code "class:short"}  for the source class name without the package part.</li>
+     *   <li>{@code "logger:short"} for the logger name without the package part.</li>
+     * </ul>
+     *
+     * The source class name usually contains the logger name since (by convention) logger
+     * names are package names, but this is not mandatory neither enforced.
+     *
+     * @param  format The format for displaying the source, or {@code null} if the source shall not be formatted.
+     * @throws IllegalArgumentException If the given argument is not one of the recognized format names.
+     */
+    public synchronized void setSourceFormat(final String format) throws IllegalArgumentException {
+        sourceFormat(format);
+    }
+
+    /**
+     * Implementation of {@link #setSourceFormat(String)}, to be invoked also by the constructor.
+     */
+    private void sourceFormat(String format) throws IllegalArgumentException {
+        if (format == null) {
+            sourceFormat = NO_SOURCE;
         }
+        format = CharSequences.trimWhitespaces(format).toLowerCase(Locale.US);
         for (int i=0; i<FORMAT_LABELS.length; i++) {
-            if (Objects.equals(FORMAT_LABELS[i], format)) {
+            if (format.equals(FORMAT_LABELS[i])) {
                 sourceFormat = i;
                 return;
             }
@@ -364,35 +437,41 @@ loop:   for (int i=0; ; i++) {
     }
 
     /**
-     * Returns the color used for the given level. By default there is no color for any level.
-     * Colors should be used only if this formatter is associated to a {@link Handler} writing
-     * to an ANSI X3.64 compatible terminal.
+     * Returns the color used for the given level, or {@code null} if none.
+     * The current set of supported colors are {@code "red"}, {@code "green"}, {@code "yellow"}, {@code "blue"},
+     * {@code "magenta"}, {@code "cyan"} and {@code "gray"}. This set may be extended in any future SIS version.
      *
      * @param  level The level for which to get the color.
      * @return The color for the given level, or {@code null} if none.
-     *
-     * @todo Not yet public because X364 is not a public enumeration.
      */
-    final synchronized X364 getLevelColor(final Level level) {
-        return (colors != null) ? colors.get(level) : null;
+    public synchronized String getLevelColor(final Level level) {
+        if (colors != null) {
+            final X364 code = colors.get(level);
+            if (code != null) {
+                return code.color;
+            }
+        }
+        return null;
     }
 
     /**
-     * Sets the color to use for the given level. This method should be invoked only if this
-     * formatter is associated to a {@link Handler} writing to an ANSI X3.64 compatible terminal.
+     * Sets the color to use for the given level, or {@code null} for removing colorization.
+     * This method should be invoked only if this formatter is associated to a {@link Handler}
+     * writing to a terminal supporting <cite>ANSI escape codes</cite>
+     * (a.k.a. ECMA-48, ISO/IEC 6429 and X3.64 standards).
      *
-     * @param level The level for which to set a new color.
-     * @param color The new color, or {@code null} if none.
+     * <p>The given {@code color} argument shall be one of the values documented in the
+     * {@link #getLevelColor(Level)} method.</p>
      *
-     * @todo Not yet public because X364 is not a public enumeration.
+     * @param  level The level for which to set a new color.
+     * @param  color The case-insensitive new color, or {@code null} if none.
+     * @throws IllegalArgumentException If the given color is not one of the recognized values.
      */
-    final synchronized void setLevelColor(final Level level, final X364 color) {
+    public synchronized void setLevelColor(final Level level, final String color) throws IllegalArgumentException {
         boolean changed = false;
         if (color != null) {
-            if (colors == null) {
-                colors = new TreeMap<>(COMPARATOR);
-            }
-            changed = (colors.put(level, color) != color);
+            final X364 code = X364.forColorName(color).background();
+            changed = (colors().put(level, code) != code);
         } else if (colors != null) {
             changed = (colors.remove(level) != null);
             if (colors.isEmpty()) {
@@ -406,22 +485,58 @@ loop:   for (int i=0; ; i++) {
     }
 
     /**
-     * Clears all colors setting. If this formatter was inserting X3.64 escape sequences
-     * for colored output, invoking this method will force the formatting of plain text.
+     * Returns the {@link #colors} map, creating it if needed.
+     */
+    private SortedMap<Level,X364> colors() {
+        if (colors == null) {
+            colors = new TreeMap<>(COMPARATOR);
+        }
+        return colors;
+    }
+
+    /**
+     * Resets the colors to the default values. This method does not check if <cite>ANSI escape codes</cite>
+     * are supported or not - this check must be done by the caller.
+     */
+    private void resetLevelColors() {
+        final SortedMap<Level,X364> colors = colors();
+        colors.clear();
+        colors.put(Level.ALL,     X364.BACKGROUND_GRAY);
+        colors.put(Level.CONFIG,  X364.BACKGROUND_BLUE);
+        colors.put(Level.INFO,    X364.BACKGROUND_GREEN);
+        colors.put(Level.WARNING, X364.BACKGROUND_YELLOW);
+        colors.put(Level.SEVERE,  X364.BACKGROUND_RED);
+        colors.put(PerformanceLevel.PERFORMANCE, X364.BACKGROUND_CYAN);
+    }
+
+    /**
+     * Resets the colors setting to its default value.
+     *
+     * <ul>
+     *   <li>If {@code enabled} is {@code true}, then this method defines a default set of colors.</li>
+     *   <li>If {@code enabled} is {@code false}, then this method resets the formatting to plain text.</li>
+     * </ul>
      *
-     * @todo Not yet public because X364 is not a public enumeration.
+     * This method does not check if <cite>ANSI escape codes</cite> are supported or not.
+     * This check must be done by the caller.
+     *
+     * @param enabled {@code true} for defining a default set of colors, or {@code false} for removing all colors.
      */
-    final synchronized void clearLevelColors() {
-        colors = null;
-        colorLevels = null;
-        colorSequences = null;
+    public synchronized void resetLevelColors(final boolean enabled) {
+        if (enabled) {
+            resetLevelColors();
+        } else {
+            colors = null;
+            colorLevels = null;
+            colorSequences = null;
+        }
     }
 
     /**
-     * Interpolates the color for the given level. If there is no color specified explicitly for the given color,
+     * Gets the color for the given level. If there is no explicit color for the given level,
      * returns the color of the first level below the given one for which a color is specified.
      */
-    private String interpolateColor(final Level level) {
+    private String colorAt(final Level level) {
         if (colorSequences == null) {
             colorSequences = new String[colors.size()];
             colorLevels = new int[colorSequences.length];
@@ -440,6 +555,7 @@ loop:   for (int i=0; ; i++) {
 
     /**
      * Formats the given log record and return the formatted string.
+     * See the <a href="#overview">class javadoc</a> for information on the log format.
      *
      * @param  record The log record to be formatted.
      * @return A formatted log record.
@@ -450,10 +566,10 @@ loop:   for (int i=0; ; i++) {
         final boolean colors  = (this.colors != null);
         final boolean emphase = !faintSupported || (level.intValue() >= LEVEL_THRESHOLD.intValue());
         final StringBuffer buffer = this.buffer;
-        buffer.setLength(MARGIN.length());
+        buffer.setLength(header.length());
         /*
-         * Formats the time (e.g. "00:00:12.365"). The time pattern can be set either
-         * programmatically by a call to setTimeFormat(...), or in logging.properties
+         * Appends the time (e.g. "00:00:12.365"). The time pattern can be set either
+         * programmatically by a call to 'setTimeFormat(…)', or in logging.properties
          * file with the "org.apache.sis.util.logging.MonolineFormatter.time" property.
          */
         if (timeFormat != null) {
@@ -462,13 +578,13 @@ loop:   for (int i=0; ; i++) {
             buffer.append(' ');
         }
         /*
-         * Formats the level (e.g. "FINE"). We do not provide
-         * the option to turn level off for now.
+         * Appends the level (e.g. "FINE"). We do not provide the option to turn level off for now.
+         * This level will be formatted with a colorized background if ANSI escape sequences are enabled.
          */
         int margin = buffer.length();
-        if (true) {
+        if (SHOW_LEVEL) {
             if (colors) {
-                buffer.append(interpolateColor(level));
+                buffer.append(colorAt(level));
             }
             final int offset = buffer.length();
             buffer.append(level.getLocalizedName());
@@ -481,7 +597,8 @@ loop:   for (int i=0; ; i++) {
             margin++;
         }
         /*
-         * Adds the source. It may be either the source logger or the source class name.
+         * Appends the logger name or source class name, in long of short form.
+         * The name may be formatted in bold characters if ANSI escape sequences are enabled.
          */
         String source;
         switch (sourceFormat) {
@@ -511,9 +628,8 @@ loop:   for (int i=0; ; i++) {
             buffer.append(' ');
         }
         /*
-         * Now format the message. We will use a line separator made of the
-         * usual EOL ("\r", "\n", or "\r\n", which is plateform specific)
-         * following by some amout of space in order to align message body.
+         * Now prepare the LineAppender for the message. We set a line separator prefixed by some
+         * amount of spaces in order to align message body on the column after the level name.
          */
         String bodyLineSeparator = writer.getLineSeparator();
         final String lineSeparator = System.lineSeparator();
@@ -526,31 +642,35 @@ loop:   for (int i=0; ; i++) {
         }
         final Throwable exception = record.getThrown();
         String message = formatMessage(record);
+        int length = 0;
         if (message != null) {
-            message = message.substring(0, trim(message));
+            length = CharSequences.skipTrailingWhitespaces(message, 0, message.length());
         }
+        /*
+         * Up to this point, we wrote directly in the StringBuilder for performance reasons.
+         * Now for the message part, we need to use the LineAppender in order to replace EOL
+         * and tabulations.
+         */
         try {
+            if (message != null) {
+                writer.append(message, 0, length);
+            }
             if (exception != null) {
-                // If there is no message, print directly the exception.
                 if (message != null) {
-                    writer.append(message).append(lineSeparator);
-                    writer.append("Caused by: ");
+                    writer.append("\nCaused by: "); // LineAppender will replace '\n' by the system EOL.
                 }
                 if (level.intValue() >= LEVEL_THRESHOLD.intValue()) {
-                    exception.printStackTrace(new PrintWriter(IO.asWriter(writer)));
+                    exception.printStackTrace(printer);
                 } else {
                     printAbridged(exception, writer, record.getLoggerName(),
-                            record.getSourceClassName(), record.getSourceMethodName(), lineSeparator);
+                            record.getSourceClassName(), record.getSourceMethodName());
                 }
-            } else {
-                // If there is no message, print "null".
-                writer.append(message);
             }
             writer.flush();
         } catch (IOException e) {
             throw new AssertionError(e);
         }
-        buffer.setLength(trim(buffer));
+        buffer.setLength(CharSequences.skipTrailingWhitespaces(buffer, 0, buffer.length()));
         if (colors && !emphase) {
             buffer.append(X364.NORMAL.sequence());
         }
@@ -569,8 +689,7 @@ loop:   for (int i=0; ; i++) {
      * @param sourceMethodName  The name of the method that emitted the log.
      */
     private static void printAbridged(Throwable exception, final Appendable writer,
-            final String loggerName, final String sourceClassName, final String sourceMethodName,
-            final String lineSeparator) throws IOException
+            final String loggerName, final String sourceClassName, final String sourceMethodName) throws IOException
     {
         StackTraceElement previous = null;
         // Arbitrary limit of 10 causes to format.
@@ -622,21 +741,21 @@ loop:   for (int i=0; ; i++) {
             /*
              * Now format the exception, then redo the loop for the cause (if any).
              */
-            writer.append(String.valueOf(exception)).append(lineSeparator);
+            writer.append(String.valueOf(exception)).append('\n'); // LineAppender will replace '\n' by the system EOL.
             for (int i=0; i<stopIndex; i++) {
                 if (i == CONTEXT_STACK_TRACE_ELEMENTS) {
                     final int numToSkip = (logProducer - 2*CONTEXT_STACK_TRACE_ELEMENTS);
                     if (numToSkip > 1) {
-                        more(writer, numToSkip, true, lineSeparator);
+                        more(writer, numToSkip, true);
                         i += numToSkip;
                     }
                 }
                 if (i == logProducer) {
-                    writer.append("  \u2192"); // Right arrow
+                    writer.append("  →");
                 }
-                writer.append("\tat ").append(String.valueOf(trace[i])).append(lineSeparator);
+                writer.append("\tat ").append(String.valueOf(trace[i])).append('\n');
             }
-            more(writer, trace.length - stopIndex, false, lineSeparator);
+            more(writer, trace.length - stopIndex, false);
             exception = exception.getCause();
             if (exception == null) break;
             writer.append("Caused by: ");
@@ -646,51 +765,55 @@ loop:   for (int i=0; ; i++) {
     /**
      * Formats the number of stack trace elements that where skipped.
      */
-    private static void more(final Appendable writer, final int numToSkip, final boolean con,
-            final String lineSeparator) throws IOException
-    {
+    private static void more(final Appendable writer, final int numToSkip, final boolean con) throws IOException {
         if (numToSkip > 0) {
             writer.append("... ").append(String.valueOf(numToSkip)).append(" more");
             if (con) {
                 writer.append(" ...");
             }
-            writer.append(lineSeparator);
+            writer.append('\n'); // LineAppender will replace '\n' by the system EOL.
         }
     }
 
     /**
-     * Returns the length of the given characters sequences without the trailing spaces
-     * or line feed.
+     * Installs a {@code MonolineFormatter} for the root logger and its children.
+     * If a {@code MonolineFormatter} is already installed, then it will be returned unchanged.
+     * If a {@link SimpleFormatter} was installed, then it will be removed in order to avoid sending
+     * the same records twice to the console.
+     *
+     * @return The new or existing {@code MonolineFormatter}. The formatter output can be configured
+     *         using the {@link #setTimeFormat(String)} and {@link #setSourceFormat(String)} methods.
+     * @throws SecurityException If this method does not have the permission to install the formatter.
      */
-    private static int trim(final CharSequence message) {
-        int length = message.length();
-        while (length != 0 && Character.isWhitespace(message.charAt(length-1))) {
-            length--;
-        }
-        return length;
+    @Configuration
+    public static MonolineFormatter install()  throws SecurityException {
+        return install(Logging.getLogger(""), null);
     }
 
     /**
-     * Setups a {@code MonolineFormatter} for the specified logger and its children. This method
-     * searches for all instances of {@link ConsoleHandler} using the {@link SimpleFormatter}. If
-     * such instances are found, they are replaced by a single instance of {@code MonolineFormatter}.
-     * If no such {@link ConsoleHandler} are found, then a new one is created with a new
-     * {@code MonolineFormatter}.
+     * Installs a {@code MonolineFormatter} for the specified logger and its children.
+     * If a {@code MonolineFormatter} is already installed, then it will be returned unchanged.
+     * If a {@link SimpleFormatter} was installed, then it will be removed in order to avoid sending
+     * the same records twice to the console.
+     *
+     * {@section Specifying a log level}
+     * This method can opportunistically set the handler levels. If the given level is non-null,
+     * then every {@link Handler}s using the {@code MonolineFormatter} may be set to that level.
+     * The given level is only a hint - this method may ignores it if the current configuration
+     * already uses a finer level.
      *
-     * <p>In addition, this method can set the handler levels. If the level is non-null, then every
-     * {@link Handler}s using the monoline formatter may be set to the specified level. Whatever
-     * the given level is used or not depends on current configuration. The choice is based on
-     * heuristic rules that may change in any future version. Developers are encouraged to avoid
-     * non-null level except for debugging purpose, since a user trying to configure his logging
-     * properties file may find confusing to see his setting ignored.</p>
+     * <p>This method is provided mostly for debugging purpose, as a quick way to increase the
+     * logging verbosity.</p>
      *
      * @param  logger The base logger to apply the change on.
      * @param  level The desired level, or {@code null} if no level should be set.
-     * @return The registered {@code MonolineFormatter}, or {@code null} if the registration failed.
-     *         If non-null, the formatter output can be configured using the {@link #setTimeFormat}
-     *         and {@link #setSourceFormat} methods.
-     */
-    public static MonolineFormatter configureConsoleHandler(final Logger logger, final Level level) {
+     * @return The new or existing {@code MonolineFormatter}. The formatter output can be configured
+     *         using the {@link #setTimeFormat(String)} and {@link #setSourceFormat(String)} methods.
+     * @throws SecurityException If this method does not have the permission to install the formatter.
+     */
+    @Debug
+    @Configuration
+    public static MonolineFormatter install(final Logger logger, final Level level) throws SecurityException {
         MonolineFormatter monoline = null;
         boolean foundConsoleHandler = false;
         Handler[] handlers = logger.getHandlers();
@@ -714,22 +837,12 @@ loop:   for (int i=0; ; i++) {
                     /*
                      * A ConsoleHandler using the SimpleFormatter has been found. Replaces
                      * the SimpleFormatter by MonolineFormatter, creating it if necessary.
-                     * If the handler setting fail with an exception, then we will continue
-                     * to use the old J2SE handler instead.
                      */
-                    try {
-                        setLevel(handler, level);
-                    } catch (SecurityException exception) {
-                        unexpectedException(exception);
-                    }
+                    setLevel(handler, level);
                     if (monoline == null) {
                         monoline = new MonolineFormatter(handler);
                     }
-                    try {
-                        handler.setFormatter(monoline);
-                    } catch (SecurityException exception) {
-                        unexpectedException(exception);
-                    }
+                    handler.setFormatter(monoline);
                 }
             }
         }
@@ -772,20 +885,11 @@ loop:   for (int i=0; ; i++) {
      * set at the specified level. The formatter is returned for convenience.
      */
     private static MonolineFormatter addHandler(final Logger logger, final Level level) {
-        MonolineFormatter monoline = null;
-        try {
-            final Handler handler = new ConsoleHandler();
-            monoline = new MonolineFormatter(handler);
-            handler.setFormatter(monoline);
-            setLevel(handler, level);
-            logger.addHandler(handler);
-        } catch (SecurityException exception) {
-            unexpectedException(exception);
-            /*
-             * Returns without any change to the J2SE configuration. It will not
-             * prevent to program to work; just produces different logging outputs.
-             */
-        }
+        final Handler handler = new ConsoleHandler();
+        final MonolineFormatter monoline = new MonolineFormatter(handler);
+        handler.setFormatter(monoline);
+        setLevel(handler, level);
+        logger.addHandler(handler);
         return monoline;
     }
 
@@ -802,11 +906,4 @@ loop:   for (int i=0; ; i++) {
             }
         }
     }
-
-    /**
-     * Invoked when an error occurs during the initialization.
-     */
-    private static void unexpectedException(final Exception exception) {
-        Logging.unexpectedException(MonolineFormatter.class, "configureConsoleHandler", exception);
-    }
 }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/PerformanceLevel.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/PerformanceLevel.java?rev=1492763&r1=1492762&r2=1492763&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/PerformanceLevel.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/logging/PerformanceLevel.java [UTF-8] Thu Jun 13 17:00:45 2013
@@ -44,7 +44,7 @@ import static org.apache.sis.util.Argume
  *   <li>The {@link Logger#setLevel(Level)} can be invoked, together with
  *       {@link java.util.logging.Handler#setLevel(Level)} on all relevant logging targets
  *       (console or file, <i>etc.</i>).</li>
- *   <li>The {@link MonolineFormatter#configureConsoleHandler(Logger, Level)} convenience
+ *   <li>The {@link MonolineFormatter#install(Logger, Level)} convenience
  *       method can be invoked.</li>
  * </ul>
  *

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/X364Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/X364Test.java?rev=1492763&r1=1492762&r2=1492763&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/X364Test.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/util/X364Test.java [UTF-8] Thu Jun 13 17:00:45 2013
@@ -36,6 +36,18 @@ import static org.apache.sis.internal.ut
 @DependsOn(org.apache.sis.util.CharSequencesTest.class)
 public final strictfp class X364Test extends TestCase {
     /**
+     * Tests {@link X364#forColorName(String)}.
+     */
+    @Test
+    public void testForColorName() {
+        for (final X364 value : X364.values()) {
+            if (value.color != null) {
+                assertSame(value.color, value.foreground(), X364.forColorName(value.color));
+            }
+        }
+    }
+
+    /**
      * Tests the {@link X364#plain(String)} method.
      */
     @Test



Mime
View raw message