1 /*
   2  * Copyright (c) 2002-2012, the original author or authors.
   3  *
   4  * This software is distributable under the BSD license. See the terms of the
   5  * BSD license in the documentation provided with this software.
   6  *
   7  * http://www.opensource.org/licenses/bsd-license.php
   8  */
   9 package jdk.internal.jline.internal;
  10 
  11 import java.io.PrintStream;
  12 
  13 import static jdk.internal.jline.internal.Preconditions.checkNotNull;
  14 
  15 /**
  16  * Internal logger.
  17  *
  18  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
  19  * @since 2.0
  20  */
  21 public final class Log
  22 {
  23     ///CLOVER:OFF
  24 
  25     public static enum Level
  26     {
  27         TRACE,
  28         DEBUG,
  29         INFO,
  30         WARN,
  31         ERROR
  32     }
  33 
  34     @SuppressWarnings({"StringConcatenation"})
  35     public static final boolean TRACE = Boolean.getBoolean(Log.class.getName() + ".trace");
  36 
  37     @SuppressWarnings({"StringConcatenation"})
  38     public static final boolean DEBUG = TRACE || Boolean.getBoolean(Log.class.getName() + ".debug");
  39 
  40     private static PrintStream output = System.err;
  41 
  42     public static PrintStream getOutput() {
  43         return output;
  44     }
  45 
  46     public static void setOutput(final PrintStream out) {
  47         output = checkNotNull(out);
  48     }
  49 
  50     /**
  51      * Helper to support rendering messages.
  52      */
  53     @TestAccessible
  54     static void render(final PrintStream out, final Object message) {
  55         if (message.getClass().isArray()) {
  56             Object[] array = (Object[]) message;
  57 
  58             out.print("[");
  59             for (int i = 0; i < array.length; i++) {
  60                 out.print(array[i]);
  61                 if (i + 1 < array.length) {
  62                     out.print(",");
  63                 }
  64             }
  65             out.print("]");
  66         }
  67         else {
  68             out.print(message);
  69         }
  70     }
  71 
  72     @TestAccessible
  73     static void log(final Level level, final Object... messages) {
  74         //noinspection SynchronizeOnNonFinalField
  75         synchronized (output) {
  76             output.format("[%s] ", level);
  77 
  78             for (int i=0; i<messages.length; i++) {
  79                 // Special handling for the last message if its a throwable, render its stack on the next line
  80                 if (i + 1 == messages.length && messages[i] instanceof Throwable) {
  81                     output.println();
  82                     ((Throwable)messages[i]).printStackTrace(output);
  83                 }
  84                 else {
  85                     render(output, messages[i]);
  86                 }
  87             }
  88 
  89             output.println();
  90             output.flush();
  91         }
  92     }
  93 
  94     public static void trace(final Object... messages) {
  95         if (TRACE) {
  96             log(Level.TRACE, messages);
  97         }
  98     }
  99 
 100     public static void debug(final Object... messages) {
 101         if (TRACE || DEBUG) {
 102             log(Level.DEBUG, messages);
 103         }
 104     }
 105 
 106     /**
 107      * @since 2.7
 108      */
 109     public static void info(final Object... messages) {
 110         log(Level.INFO, messages);
 111     }
 112 
 113     public static void warn(final Object... messages) {
 114         log(Level.WARN, messages);
 115     }
 116 
 117     public static void error(final Object... messages) {
 118         log(Level.ERROR, messages);
 119     }
 120 }