1 /*
2  * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.tools.sjavac;
27 
28 import java.io.PrintWriter;
29 import java.io.StringWriter;
30 import java.io.Writer;
31 import java.util.Locale;
32 
33 /**
34  * Utility class only for sjavac logging.
35  *
36  * Logging in sjavac has special requirements when running in server/client
37  * mode. Most of the log messages is generated server-side, but the server
38  * is typically spawned by the client in the background, so the user usually
39  * does not see the server stdout/stderr. For this reason log messages needs
40  * to relayed back to the client that performed the request that generated the
41  * log message. To support this use case this class maintains a per-thread log
42  * instance so that each connected client can have its own instance that
43  * relays messages back to the requesting client.
44  *
45  * On the client-side (or when running sjavac without server-mode) there will
46  * typically just be one Log instance.
47  *
48  *  <p><b>This is NOT part of any supported API.
49  *  If you write code that depends on this, you do so at your own risk.
50  *  This code and its internal interfaces are subject to change or
51  *  deletion without notice.</b>
52  */
53 public class Log {
54 
55     public enum Level {
56         ERROR,
57         WARN,
58         INFO,
59         DEBUG,
60         TRACE;
61     }
62 
63     private static Log stdOutErr = new Log(new PrintWriter(System.out), new PrintWriter(System.err));
64     private static ThreadLocal<Log> loggers = new ThreadLocal<>();
65 
66     protected PrintWriter err; // Used for error and warning messages
67     protected PrintWriter out; // Used for other messages
68     protected Level level = Level.INFO;
69 
Log(Writer out, Writer err)70     public Log(Writer out, Writer err) {
71         this.out = out == null ? null : new PrintWriter(out, true);
72         this.err = err == null ? null : new PrintWriter(err, true);
73     }
74 
setLogForCurrentThread(Log log)75     public static void setLogForCurrentThread(Log log) {
76         loggers.set(log);
77     }
78 
setLogLevel(String l)79     public static void setLogLevel(String l) {
80         setLogLevel(Level.valueOf(l.toUpperCase(Locale.US)));
81     }
82 
setLogLevel(Level l)83     public static void setLogLevel(Level l) {
84         get().level = l;
85     }
86 
trace(String msg)87     static public void trace(String msg) {
88         log(Level.TRACE, msg);
89     }
90 
debug(String msg)91     static public void debug(String msg) {
92         log(Level.DEBUG, msg);
93     }
94 
info(String msg)95     static public void info(String msg) {
96         log(Level.INFO, msg);
97     }
98 
warn(String msg)99     static public void warn(String msg) {
100         log(Level.WARN, msg);
101     }
102 
error(String msg)103     static public void error(String msg) {
104         log(Level.ERROR, msg);
105     }
106 
error(Throwable t)107     static public void error(Throwable t) {
108         log(Level.ERROR, t);
109     }
110 
log(Level l, String msg)111     static public void log(Level l, String msg) {
112         get().printLogMsg(l, msg);
113     }
114 
debug(Throwable t)115     public static void debug(Throwable t) {
116         log(Level.DEBUG, t);
117     }
118 
log(Level l, Throwable t)119     public static void log(Level l, Throwable t) {
120         StringWriter sw = new StringWriter();
121         t.printStackTrace(new PrintWriter(sw, true));
122         log(l, sw.toString());
123     }
124 
isDebugging()125     static public boolean isDebugging() {
126         return get().isLevelLogged(Level.DEBUG);
127     }
128 
isLevelLogged(Level l)129     protected boolean isLevelLogged(Level l) {
130         return l.ordinal() <= level.ordinal();
131     }
132 
get()133     public static Log get() {
134         Log log = loggers.get();
135         return log != null ? log : stdOutErr;
136     }
137 
printLogMsg(Level msgLevel, String msg)138     protected void printLogMsg(Level msgLevel, String msg) {
139         if (isLevelLogged(msgLevel)) {
140             PrintWriter pw = msgLevel.ordinal() <= Level.WARN.ordinal() ? err : out;
141             pw.println(msg);
142         }
143     }
144 }
145