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 */
9package jdk.internal.jline.internal;
10
11import java.io.PrintStream;
12
13import 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 */
21public 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}
121