View Javadoc
1   /*
2    * Copyright (c) 2010, 2013, 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 jdk.nashorn.internal.runtime;
27  
28  import java.io.PrintWriter;
29  import java.util.logging.Level;
30  import java.util.logging.Logger;
31  import jdk.nashorn.internal.runtime.options.Options;
32  
33  /**
34   * Wrapper class for Logging system. This is how you are supposed to register a logger and use it
35   */
36  
37  public final class DebugLogger {
38      private final Logger  logger;
39      private final boolean isEnabled;
40  
41      private int indent;
42  
43      private static final int INDENT_SPACE = 4;
44  
45      /**
46       * Constructor
47       *
48       * @param loggerName name of logger - this is the unique key with which it can be identified
49       */
50      public DebugLogger(final String loggerName) {
51          this(loggerName, null);
52      }
53  
54      /**
55       * Constructor
56       *
57       * A logger can be paired with a property, e.g. {@code --log:codegen:info} is equivalent to {@code -Dnashorn.codegen.log}
58       *
59       * @param loggerName name of logger - this is the unique key with which it can be identified
60       * @param property   system property activating the logger on {@code info} level
61       */
62      public DebugLogger(final String loggerName, final String property) {
63          if (property != null && Options.getBooleanProperty(property)) {
64              this.logger = Logging.getOrCreateLogger(loggerName, Level.INFO);
65          } else {
66              this.logger = Logging.getLogger(loggerName);
67          }
68          assert logger != null;
69          this.isEnabled = getLevel() != Level.OFF;
70      }
71  
72      /**
73       * Do not currently support chaining this with parent logger. Logger level null
74       * means disabled
75       * @return level
76       */
77      private Level getLevel() {
78          return logger.getLevel() == null ? Level.OFF : logger.getLevel();
79      }
80  
81      /**
82       * Get the output writer for the logger. Loggers always default to
83       * stderr for output as they are used mainly to output debug info
84       *
85       * Can be inherited so this should not be static.
86       *
87       * @return print writer for log output.
88       */
89      @SuppressWarnings("static-method")
90      public PrintWriter getOutputStream() {
91          return Context.getCurrentErr();
92      }
93  
94      /**
95       * Check if the logger is enabled
96       * @return true if enabled
97       */
98      public boolean isEnabled() {
99          return isEnabled;
100     }
101 
102     /**
103      * If you want to change the indent level of your logger, call indent with a new position.
104      * Positions start at 0 and are increased by one for a new "tab"
105      *
106      * @param pos indent position
107      */
108     public void indent(final int pos) {
109         if (isEnabled) {
110            indent += pos * INDENT_SPACE;
111         }
112     }
113 
114     /**
115      * Add an indent position
116      */
117     public void indent() {
118         indent += INDENT_SPACE;
119     }
120 
121     /**
122      * Unindent a position
123      */
124     public void unindent() {
125         indent -= INDENT_SPACE;
126         if (indent < 0) {
127             indent = 0;
128         }
129     }
130 
131     /**
132      * Check if the logger is above of the level of detail given
133      * @see java.util.logging.Level
134      *
135      * @param level logging level
136      * @return true if level is above the given one
137      */
138     public boolean levelAbove(final Level level) {
139         return getLevel().intValue() > level.intValue();
140     }
141 
142     /**
143      * Shorthand for outputting a log string as log level {@link java.util.logging.Level#FINEST} on this logger
144      * @param str the string to log
145      */
146     public void finest(final String str) {
147         log(Level.FINEST, str);
148     }
149 
150     /**
151      * Shorthand for outputting a log string as log level
152      * {@link java.util.logging.Level#FINEST} on this logger
153      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
154      */
155     public void finest(final Object... objs) {
156         log(Level.FINEST, objs);
157     }
158 
159     /**
160      * Shorthand for outputting a log string as log level
161      * {@link java.util.logging.Level#FINER} on this logger
162      * @param str the string to log
163      */
164     public void finer(final String str) {
165         log(Level.FINER, str);
166     }
167 
168     /**
169      * Shorthand for outputting a log string as log level
170      * {@link java.util.logging.Level#FINER} on this logger
171      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
172      */
173     public void finer(final Object... objs) {
174         log(Level.FINER, objs);
175     }
176 
177     /**
178      * Shorthand for outputting a log string as log level
179      * {@link java.util.logging.Level#FINE} on this logger
180      * @param str the string to log
181      */
182     public void fine(final String str) {
183         log(Level.FINE, str);
184     }
185 
186     /**
187      * Shorthand for outputting a log string as log level
188      * {@link java.util.logging.Level#FINE} on this logger
189      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
190      */
191     public void fine(final Object... objs) {
192         log(Level.FINE, objs);
193     }
194 
195     /**
196      * Shorthand for outputting a log string as log level
197      * {@link java.util.logging.Level#CONFIG} on this logger
198      * @param str the string to log
199      */
200     public void config(final String str) {
201         log(Level.CONFIG, str);
202     }
203 
204     /**
205      * Shorthand for outputting a log string as log level
206      * {@link java.util.logging.Level#CONFIG} on this logger
207      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
208      */
209     public void config(final Object... objs) {
210         log(Level.CONFIG, objs);
211     }
212 
213     /**
214      * Shorthand for outputting a log string as log level
215      * {@link java.util.logging.Level#INFO} on this logger
216      * @param str the string to log
217      */
218     public void info(final String str) {
219         log(Level.INFO, str);
220     }
221 
222     /**
223      * Shorthand for outputting a log string as log level
224      * {@link java.util.logging.Level#FINE} on this logger
225      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
226      */
227     public void info(final Object... objs) {
228         log(Level.INFO, objs);
229     }
230 
231     /**
232      * Shorthand for outputting a log string as log level
233      * {@link java.util.logging.Level#WARNING} on this logger
234      * @param str the string to log
235      */
236     public void warning(final String str) {
237         log(Level.WARNING, str);
238     }
239 
240     /**
241      * Shorthand for outputting a log string as log level
242      * {@link java.util.logging.Level#FINE} on this logger
243      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
244      */
245     public void warning(final Object... objs) {
246         log(Level.WARNING, objs);
247     }
248 
249     /**
250      * Shorthand for outputting a log string as log level
251      * {@link java.util.logging.Level#SEVERE} on this logger
252      * @param str the string to log
253      */
254     public void severe(final String str) {
255         log(Level.SEVERE, str);
256     }
257 
258     /**
259      * Shorthand for outputting a log string as log level
260      * {@link java.util.logging.Level#FINE} on this logger
261      * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
262      */
263     public void severe(final Object... objs) {
264         log(Level.SEVERE, objs);
265     }
266 
267     /**
268      * Output log line on this logger at a given level of verbosity
269      * @see java.util.logging.Level
270      *
271      * @param level minimum log level required for logging to take place
272      * @param str   string to log
273      */
274     public void log(final Level level, final String str) {
275         if (isEnabled) {
276             final StringBuilder sb = new StringBuilder();
277             for (int i = 0 ; i < indent ; i++) {
278                 sb.append(' ');
279             }
280             sb.append(str);
281             logger.log(level, sb.toString());
282         }
283     }
284 
285     /**
286      * Output log line on this logger at a given level of verbosity
287      * @see java.util.logging.Level
288      *
289      * @param level minimum log level required for logging to take place
290      * @param objs  objects for which to invoke toString and concatenate to log
291      */
292     public void log(final Level level, final Object... objs) {
293         if (isEnabled) {
294             final StringBuilder sb = new StringBuilder();
295             for (int i = 0 ; i < indent ; i++) {
296                 sb.append(' ');
297             }
298             for (final Object obj : objs) {
299                 sb.append(obj);
300             }
301             logger.log(level, sb.toString());
302         }
303     }
304 }