Class MonolineFormatter

java.lang.Object
java.util.logging.Formatter
org.apache.sis.util.logging.MonolineFormatter

public class MonolineFormatter extends Formatter
A formatter writing log messages on a single line. Compared to the JDK SimpleFormatter, this formatter uses only one line per message instead of two. For example, messages formatted by MonolineFormatter may look like:
Logging example
00:01CONFIG [MyApplication] Read configuration from “my-application/setup.xml”.
00:03INFO [EPSGFactory] Connected to the EPSG database version 9.1 on Derby 10.14.
00:12WARNING [NetcdfStore] Read “foo.nc” in 0.2 second.
By default, MonolineFormatter shows only the level and the message. One or two additional fields can be inserted between the level and the message if the setTimeFormat(String) or setSourceFormat(String) methods are invoked with o non-null argument. Examples:
  • setTimeFormat("HH:mm:ss") for formatting the time like 00:00:04", as time elapsed since the MonolineFormatter creation time.
  • setSourceFormat("logger:long") for formatting the full logger name (e.g. "org.apache.sis.storage.netcdf").
  • setSourceFormat("class:short") for formatting the short class name, without package (e.g. "NetcdfStore").

Configuration from logging.properties

The format can also be set from a logging.properties file. For example, user can cut and paste the following properties into logging.properties: See setTimeFormat(String) and setSourceFormat(String) for more information about the above time and source properties. Encoding and logging level are configured separately, typically on the JDK ConsoleHandler like below:

Thread safety

The same MonolineFormatter instance can be safely used by many threads without synchronization on the part of the caller. Subclasses should make sure that any overridden methods remain safe to call from multiple threads.
Since:
0.3
Version:
1.0
See Also:
  • Field Details

    • NO_SOURCE

      private static final int NO_SOURCE
      Do not format source class name.
      See Also:
    • LOGGER_SHORT

      private static final int LOGGER_SHORT
      Format the source logger without base.
      See Also:
    • LOGGER_LONG

      private static final int LOGGER_LONG
      Format the source logger only.
      See Also:
    • CLASS_SHORT

      private static final int CLASS_SHORT
      Format the class name without package.
      See Also:
    • CLASS_LONG

      private static final int CLASS_LONG
      Format the fully qualified class name.
      See Also:
    • METHOD

      private static final int METHOD
      Format the class name and method name.
      See Also:
    • FORMAT_LABELS

      private static final String[] FORMAT_LABELS
      The label to use in the logging.properties for setting the source format.
    • LEVEL_THRESHOLD

      private static final Level LEVEL_THRESHOLD
      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.
    • COMPARATOR

      private static final Comparator<Level> COMPARATOR
      A comparator for logging level. This comparator sorts finest levels first and severe levels last.
    • SHOW_LEVEL

      private static final boolean SHOW_LEVEL
      Whether the logging level should be visible or not. We do not provide the option to hide the levels for now.
      See Also:
    • CONTINUATION_MARGIN

      private static final int CONTINUATION_MARGIN
      Number of characters or spaces to colorize at the beginning of lines that are continuation of a single log record. This count includes the Strings.CONTINUATION_MARK character. Should not be smaller than 2 since algorithm in this class needs one white space after Strings.CONTINUATION_MARK.
      See Also:
    • CONTEXT_STACK_TRACE_ELEMENTS

      private static final int CONTEXT_STACK_TRACE_ELEMENTS
      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 Also:
    • MAX_CAUSES

      private static final int MAX_CAUSES
      Maximal amount of causes to print in stack traces. This is an arbitrary limit.
      See Also:
    • colors

      private SortedMap<Level,X364> colors
      The colors to apply, or null if none.
      See Also:
    • faintSupported

      private final boolean faintSupported
      true if the faint X.364 code is supported. On MacOS, faint colors produce bad output.
    • colorLevels

      private transient int[] colorLevels
      Numerical values of levels for which to apply colors in increasing order. Computed from colors when first needed or when the color map changes.
    • colorSequences

      private transient String[] colorSequences
      X3.64 sequences of colors matching the levels declared in colorLevels. Computed from colors when first needed or when the color map changes.
    • levelWidth

      private final int levelWidth
      The minimum amount of characters to use for writing logging level before the message. If the logging level is shorter, remaining characters will be padded with spaces. This is used in order to align the messages.
      See Also:
    • startMillis

      private final long startMillis
      Time of MonolineFormatter creation, in milliseconds elapsed since January 1, 1970.
    • timeFormat

      private SimpleDateFormat timeFormat
      The format to use for formatting elapsed time, or null if there is none.
    • messageFormat

      private transient AutoMessageFormat messageFormat
      The message format, or null if not yet created.
    • messagePattern

      private transient String messagePattern
      Value of the last call to MessageFormat.applyPattern(String). Saved in order to avoid calling applyPattern(String) in the common case where the same message is logged many times with different arguments.
    • sourceFormat

      private int sourceFormat
      One of the following constants: NO_SOURCE, LOGGER_SHORT, LOGGER_LONG, CLASS_SHORT, CLASS_LONG or METHOD.
    • buffer

      private final StringBuffer buffer
      Buffer for formatting messages. We will reuse this buffer in order to reduce memory allocations. This is the buffer used internally by writer.

      This buffer is also arbitrarily chosen as our synchronization lock. The rational is that all operations on StringBuffer are synchronized anyway. So by reusing it for our lock, we will take only one monitor instead of two.

    • writer

      private final LineAppender writer
      The line writer. This object transforms all "\r", "\n" or "\r\n" occurrences into a single line separator. This line separator will include space for the left margin, if needed.
    • printer

      private final PrintWriter printer
      The printer wrapping the writer. This is used for Throwable.printStackTrace(PrintWriter) calls. We don't use the printer for other usage in order to avoid unnecessary indirections and synchronizations.
  • Constructor Details

    • MonolineFormatter

      public MonolineFormatter()
      Constructs a default MonolineFormatter. This no-argument constructor is invoked by the logging system if the logging.properties file contains the following line:
      Since:
      1.0
    • MonolineFormatter

      public MonolineFormatter(Handler handler)
      Constructs a MonolineFormatter configured for the given handler.

      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 - it will not be modified, and no reference to that handler will be kept by this constructor.
      Parameters:
      handler - The handler to be used with this formatter, or null if unknown.
      See Also:
  • Method Details

    • levelWidth

      static int levelWidth(Level threshold)
      Returns the length of the widest level name, taking in account only the standard levels equals or greater than the given threshold.
    • getHeader

      public String getHeader()
      Returns the string to write on the left side of the first line of every log records, or null if none. This is a string to be shown just before the level.
      Returns:
      the string to write on the left side of the first line of every log records, or null if none.
    • setHeader

      public void setHeader(String header)
      Sets the string to write on the left side of the first line of every log records.
      Parameters:
      header - The string to write on the left side of the first line of every log records, or null if none.
    • getTimeFormat

      public String getTimeFormat()
      Returns the format for elapsed time, or null if the time is not shown. This method returns the pattern specified by the last call to the setTimeFormat(String) method, or the patten specified by the org.apache.sis.util.logging.MonolineFormatter.time property in the jre/lib/logging.properties file.
      Returns:
      the time pattern, or null if elapsed time is not formatted.
    • setTimeFormat

      public void setTimeFormat(String pattern) throws IllegalArgumentException
      Sets the format for elapsed time, or hides the time field. The pattern must matches the format specified in SimpleDateFormat, but for the time part only (no date).
      Example: The "HH:mm:ss.SSS" pattern will display the elapsed time in hours, minutes, seconds and milliseconds.
      Parameters:
      pattern - the time pattern, or null to disable time formatting.
      Throws:
      IllegalArgumentException - if the given pattern is invalid.
    • timeFormat

      private void timeFormat(String pattern) throws IllegalArgumentException
      Implementation of setTimeFormat(String), to be invoked also by the constructor.
      Throws:
      IllegalArgumentException
    • getSourceFormat

      public String getSourceFormat()
      Returns the format for the source, or null is the source is not shown. This method returns the source format specified by the last call to the setSourceFormat(String) method, or the format specified by the org.apache.sis.util.logging.MonolineFormatter.source property in the jre/lib/logging.properties file.
      Returns:
      the source format, or null if source is not formatted.
    • setSourceFormat

      public void setSourceFormat(String format) throws IllegalArgumentException
      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:
      • null for hiding the source field.
      • "class:long" for the source class name
      • "logger:long" for the logger name
      • "class:short" for the source class name without the package part.
      • "logger:short" for the logger name without the package part.
      • "class.method" for the short class name followed by the source method 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.
      Parameters:
      format - the format for displaying the source, or null if the source shall not be formatted.
      Throws:
      IllegalArgumentException - if the given argument is not one of the recognized format names.
    • sourceFormat

      private void sourceFormat(String format) throws IllegalArgumentException
      Implementation of setSourceFormat(String), to be invoked also by the constructor.
      Throws:
      IllegalArgumentException
    • getLevelColor

      public String getLevelColor(Level level)
      Returns the color used for the given level, or null if none. The current set of supported colors are "red", "green", "yellow", "blue", "magenta", "cyan" and "gray". This set may be extended in any future SIS version.
      Parameters:
      level - the level for which to get the color.
      Returns:
      the color for the given level, or null if none.
    • setLevelColor

      public void setLevelColor(Level level, String color) throws IllegalArgumentException
      Sets the color to use for the given level, or null for removing colorization. This method should be invoked only if this formatter is associated to a Handler writing to a terminal supporting ANSI escape codes (a.k.a. ECMA-48, ISO/IEC 6429 and X3.64 standards).

      The given color argument shall be one of the values documented in the getLevelColor(Level) method.

      Parameters:
      level - the level for which to set a new color.
      color - the case-insensitive new color, or null if none.
      Throws:
      IllegalArgumentException - if the given color is not one of the recognized values.
    • colors

      private SortedMap<Level,X364> colors()
      Returns the colors map, creating it if needed.
    • resetLevelColors

      private void resetLevelColors()
      Resets the colors to the default values. This method does not check if ANSI escape codes are supported or not - this check must be done by the caller.
    • resetLevelColors

      public void resetLevelColors(boolean enabled)
      Resets the colors setting to its default value.
      • If enabled is true, then this method defines a default set of colors.
      • If enabled is false, then this method resets the formatting to plain text.
      This method does not check if ANSI escape codes are supported or not. This check must be done by the caller.
      Parameters:
      enabled - true for defining a default set of colors, or false for removing all colors.
    • colorAt

      private String colorAt(Level level)
      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.
    • format

      public String format(LogRecord record)
      Formats the given log record and returns the formatted string. See the class javadoc for information on the log format.
      Specified by:
      format in class Formatter
      Parameters:
      record - the log record to be formatted.
      Returns:
      a formatted log record.
    • formatMessage

      public String formatMessage(LogRecord record)
      Returns the localized message from the given log record. First this method gets the raw message from the given record. Then there is choices:
      • If the given record specifies a resource bundle, then the message is used as a key for fetching the localized resources in the given bundle.
      • If the given record specifies one or more parameters and if the message seems to use the MessageFormat syntax, then the message is formatted by MessageFormat.
      Overrides:
      formatMessage in class Formatter
      Parameters:
      record - The log record from which to get a localized message.
      Returns:
      the localized message.
    • printAbridged

      private static void printAbridged(Throwable exception, Appendable writer, String loggerName, String sourceClassName, String sourceMethodName) throws IOException
      Prints an abridged stack trace. This method is invoked when the record is logged at at low logging level (typically less than Level.INFO).
      Parameters:
      exception - the exception to be logged.
      writer - where to print the stack trace.
      loggerName - the name of the logger when the log will be sent.
      sourceClassName - the name of the class that emitted the log.
      sourceMethodName - the name of the method that emitted the log.
      Throws:
      IOException
    • more

      private static void more(Appendable writer, int numToSkip, boolean con) throws IOException
      Formats the number of stack trace elements that where skipped.
      Throws:
      IOException
    • install

      @Configuration public static MonolineFormatter install() throws SecurityException
      Installs a MonolineFormatter for the root logger, or returns the existing instance if any. This method performs the following choices:
      • If a ConsoleHandler is associated to the root logger, then:
        • If that handler already uses a MonolineFormatter, then the existing formatter is returned.
        • Otherwise the ConsoleHandler formatter is replaced by a new MonolineFormatter instance, and that new instance is returned. We perform this replacement in order to avoid sending twice the same records to the console.
      • Otherwise a new ConsoleHandler using a new MonolineFormatter is created and added to the root logger.
      Implementation note: The current implementation does not check for duplicated ConsoleHandler instances, and does not check if any child logger has a ConsoleHandler.
      Returns:
      the new or existing MonolineFormatter. The formatter output can be configured using the setTimeFormat(String) and setSourceFormat(String) methods.
      Throws:
      SecurityException - if this method does not have the permission to install the formatter.
    • install

      @Debug @Configuration public static MonolineFormatter install(Logger logger, Level level) throws SecurityException
      Installs a MonolineFormatter for the specified logger, or returns the existing instance if any. This method performs the following steps:
      • If a ConsoleHandler is associated to the given logger, then:
        • If that handler already uses a MonolineFormatter, then the existing formatter is returned.
        • Otherwise the ConsoleHandler formatter is replaced by a new MonolineFormatter instance, and that new instance is returned. We perform this replacement in order to avoid sending twice the same records to the console.
      • Otherwise:
        • The Logger.setUseParentHandlers(boolean) flag is set to false for avoiding duplicated loggings if a ConsoleHandler instance exists in the parent handlers.
        • Parent handlers that are not ConsoleHandler instances are added to the given logger in order to preserve similar behavior as before the call to setUseParentHandlers(false).
        • A new ConsoleHandler using a new MonolineFormatter is created and added to the given logger.
      Implementation note: The current implementation does not check for duplicated ConsoleHandler instances, and does not check if any child logger has a ConsoleHandler.

      Specifying a log level

      This method can opportunistically set the handler level. If the given level is non-null, then the ConsoleHandler using the MonolineFormatter will be set to that level. This is mostly a convenience for temporary increase of logging verbosity for debugging purpose. This functionality should not be used in production environment, since it overwrite user's level setting.
      Parameters:
      logger - the base logger to apply the change on.
      level - the desired level, or null if no level should be set.
      Returns:
      the new or existing MonolineFormatter. The formatter output can be configured using the setTimeFormat(String) and setSourceFormat(String) methods.
      Throws:
      SecurityException - if this method does not have the permission to install the formatter.