aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/runtime/logging/DebugLogger.java')
-rw-r--r--src/jdk/nashorn/internal/runtime/logging/DebugLogger.java606
1 files changed, 606 insertions, 0 deletions
diff --git a/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java b/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java
new file mode 100644
index 00000000..084f7658
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime.logging;
+
+import java.io.PrintWriter;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.logging.LoggingPermission;
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.events.RuntimeEvent;
+
+/**
+ * Wrapper class for Logging system. This is how you are supposed to register a logger and use it
+ */
+
+public final class DebugLogger {
+
+ /** Disabled logger used for all loggers that need an instance, but shouldn't output anything */
+ public static final DebugLogger DISABLED_LOGGER = new DebugLogger("disabled", Level.OFF, false);
+
+ private final Logger logger;
+ private final boolean isEnabled;
+
+ private int indent;
+
+ private static final int INDENT_SPACE = 4;
+
+ /** A quiet logger only logs {@link RuntimeEvent}s and does't output any text, regardless of level */
+ private final boolean isQuiet;
+
+ /**
+ * Constructor
+ *
+ * A logger can be paired with a property, e.g. {@code --log:codegen:info} is equivalent to {@code -Dnashorn.codegen.log}
+ *
+ * @param loggerName name of logger - this is the unique key with which it can be identified
+ * @param loggerLevel level of the logger
+ * @param isQuiet is this a quiet logger, i.e. enabled for things like e.g. RuntimeEvent:s, but quiet otherwise
+ */
+ public DebugLogger(final String loggerName, final Level loggerLevel, final boolean isQuiet) {
+ this.logger = instantiateLogger(loggerName, loggerLevel);
+ this.isQuiet = isQuiet;
+ assert logger != null;
+ this.isEnabled = getLevel() != Level.OFF;
+ }
+
+ private static Logger instantiateLogger(final String name, final Level level) {
+ final Logger logger = java.util.logging.Logger.getLogger(name);
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ for (final Handler h : logger.getHandlers()) {
+ logger.removeHandler(h);
+ }
+
+ logger.setLevel(level);
+ logger.setUseParentHandlers(false);
+ final Handler c = new ConsoleHandler();
+
+ c.setFormatter(new Formatter() {
+ @Override
+ public String format(final LogRecord record) {
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append('[')
+ .append(record.getLoggerName())
+ .append("] ")
+ .append(record.getMessage())
+ .append('\n');
+
+ return sb.toString();
+ }
+ });
+ logger.addHandler(c);
+ c.setLevel(level);
+ return null;
+ }
+ }, createLoggerControlAccCtxt());
+
+ return logger;
+ }
+
+ /**
+ * Do not currently support chaining this with parent logger. Logger level null
+ * means disabled
+ * @return level
+ */
+ public Level getLevel() {
+ return logger.getLevel() == null ? Level.OFF : logger.getLevel();
+ }
+
+ /**
+ * Get the output writer for the logger. Loggers always default to
+ * stderr for output as they are used mainly to output debug info
+ *
+ * Can be inherited so this should not be static.
+ *
+ * @return print writer for log output.
+ */
+ @SuppressWarnings("static-method")
+ public PrintWriter getOutputStream() {
+ return Context.getCurrentErr();
+ }
+
+ /**
+ * Add quotes around a string
+ * @param str string
+ * @return quoted string
+ */
+ public static String quote(final String str) {
+ if (str.isEmpty()) {
+ return "''";
+ }
+
+ char startQuote = '\0';
+ char endQuote = '\0';
+ char quote = '\0';
+
+ if (str.startsWith("\\") || str.startsWith("\"")) {
+ startQuote = str.charAt(0);
+ }
+ if (str.endsWith("\\") || str.endsWith("\"")) {
+ endQuote = str.charAt(str.length() - 1);
+ }
+
+ if (startQuote == '\0' || endQuote == '\0') {
+ quote = startQuote == '\0' ? endQuote : startQuote;
+ }
+ if (quote == '\0') {
+ quote = '\'';
+ }
+
+ return (startQuote == '\0' ? quote : startQuote) + str + (endQuote == '\0' ? quote : endQuote);
+ }
+
+ /**
+ * Check if the logger is enabled
+ * @return true if enabled
+ */
+ public boolean isEnabled() {
+ return isEnabled;
+ }
+
+ /**
+ * Check if the logger is enabled
+ * @param logger logger to check, null will return false
+ * @return true if enabled
+ */
+ public static boolean isEnabled(final DebugLogger logger) {
+ return logger != null && logger.isEnabled();
+ }
+
+ /**
+ * If you want to change the indent level of your logger, call indent with a new position.
+ * Positions start at 0 and are increased by one for a new "tab"
+ *
+ * @param pos indent position
+ */
+ public void indent(final int pos) {
+ if (isEnabled) {
+ indent += pos * INDENT_SPACE;
+ }
+ }
+
+ /**
+ * Add an indent position
+ */
+ public void indent() {
+ indent += INDENT_SPACE;
+ }
+
+ /**
+ * Unindent a position
+ */
+ public void unindent() {
+ indent -= INDENT_SPACE;
+ if (indent < 0) {
+ indent = 0;
+ }
+ }
+
+ private static void logEvent(final RuntimeEvent<?> event) {
+ if (event != null) {
+ final Global global = Context.getGlobal();
+ if (global.has("Debug")) {
+ final ScriptObject debug = (ScriptObject)global.get("Debug");
+ final ScriptFunction addRuntimeEvent = (ScriptFunction)debug.get("addRuntimeEvent");
+ ScriptRuntime.apply(addRuntimeEvent, debug, event);
+ }
+ }
+ }
+
+ /**
+ * Check if the logger is above the level of detail given
+ * @see java.util.logging.Level
+ *
+ * The higher the level, the more severe the warning
+ *
+ * @param level logging level
+ * @return true if level is above the given one
+ */
+ public boolean levelCoarserThan(final Level level) {
+ return getLevel().intValue() > level.intValue();
+ }
+
+ /**
+ * Check if the logger is above or equal to the level
+ * of detail given
+ * @see java.util.logging.Level
+ *
+ * The higher the level, the more severe the warning
+ *
+ * @param level logging level
+ * @return true if level is above the given one
+ */
+ public boolean levelCoarserThanOrEqual(final Level level) {
+ return getLevel().intValue() >= level.intValue();
+ }
+
+ /**
+ * Check if the logger is below the level of detail given
+ * @see java.util.logging.Level
+ *
+ * The higher the level, the more severe the warning
+ *
+ * @param level logging level
+ * @return true if level is above the given one
+ */
+ public boolean levelFinerThan(final Level level) {
+ return getLevel().intValue() < level.intValue();
+ }
+
+ /**
+ * Check if the logger is below or equal to the level
+ * of detail given
+ * @see java.util.logging.Level
+ *
+ * The higher the level, the more severe the warning
+ *
+ * @param level logging level
+ * @return true if level is above the given one
+ */
+ public boolean levelFinerThanOrEqual(final Level level) {
+ return getLevel().intValue() <= level.intValue();
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level {@link java.util.logging.Level#FINEST} on this logger
+ * @param str the string to log
+ */
+ public void finest(final String str) {
+ log(Level.FINEST, str);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level {@link java.util.logging.Level#FINEST} on this logger
+ * @param event optional runtime event to log
+ * @param str the string to log
+ */
+ public void finest(final RuntimeEvent<?> event, final String str) {
+ finest(str);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINEST} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void finest(final Object... objs) {
+ log(Level.FINEST, objs);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINEST} on this logger
+ * @param event optional runtime event to log
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void finest(final RuntimeEvent<?> event, final Object... objs) {
+ finest(objs);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINER} on this logger
+ * @param str the string to log
+ */
+ public void finer(final String str) {
+ log(Level.FINER, str);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINER} on this logger
+ * @param event optional runtime event to log
+ * @param str the string to log
+ */
+ public void finer(final RuntimeEvent<?> event, final String str) {
+ finer(str);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINER} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void finer(final Object... objs) {
+ log(Level.FINER, objs);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINER} on this logger
+ * @param event optional runtime event to log
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void finer(final RuntimeEvent<?> event, final Object... objs) {
+ finer(objs);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param str the string to log
+ */
+ public void fine(final String str) {
+ log(Level.FINE, str);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param event optional runtime event to log
+ * @param str the string to log
+ */
+ public void fine(final RuntimeEvent<?> event, final String str) {
+ fine(str);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void fine(final Object... objs) {
+ log(Level.FINE, objs);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param event optional runtime event to log
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void fine(final RuntimeEvent<?> event, final Object... objs) {
+ fine(objs);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#CONFIG} on this logger
+ * @param str the string to log
+ */
+ public void config(final String str) {
+ log(Level.CONFIG, str);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#CONFIG} on this logger
+ * @param event optional runtime event to log
+ * @param str the string to log
+ */
+ public void config(final RuntimeEvent<?> event, final String str) {
+ config(str);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#CONFIG} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void config(final Object... objs) {
+ log(Level.CONFIG, objs);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#CONFIG} on this logger
+ * @param event optional runtime event to log
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void config(final RuntimeEvent<?> event, final Object... objs) {
+ config(objs);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#INFO} on this logger
+ * @param str the string to log
+ */
+ public void info(final String str) {
+ log(Level.INFO, str);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#INFO} on this logger
+ * @param event optional runtime event to log
+ * @param str the string to log
+ */
+ public void info(final RuntimeEvent<?> event, final String str) {
+ info(str);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void info(final Object... objs) {
+ log(Level.INFO, objs);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param event optional runtime event to log
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void info(final RuntimeEvent<?> event, final Object... objs) {
+ info(objs);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#WARNING} on this logger
+ * @param str the string to log
+ */
+ public void warning(final String str) {
+ log(Level.WARNING, str);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#WARNING} on this logger
+ * @param event optional runtime event to log
+ * @param str the string to log
+ */
+ public void warning(final RuntimeEvent<?> event, final String str) {
+ warning(str);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void warning(final Object... objs) {
+ log(Level.WARNING, objs);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ * @param event optional runtime event to log
+ */
+ public void warning(final RuntimeEvent<?> event, final Object... objs) {
+ warning(objs);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#SEVERE} on this logger
+ * @param str the string to log
+ */
+ public void severe(final String str) {
+ log(Level.SEVERE, str);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#SEVERE} on this logger
+ * @param str the string to log
+ * @param event optional runtime event to log
+ */
+ public void severe(final RuntimeEvent<?> event, final String str) {
+ severe(str);
+ logEvent(event);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#SEVERE} on this logger
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void severe(final Object... objs) {
+ log(Level.SEVERE, objs);
+ }
+
+ /**
+ * Shorthand for outputting a log string as log level
+ * {@link java.util.logging.Level#FINE} on this logger
+ * @param event optional runtime event to log
+ * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+ */
+ public void severe(final RuntimeEvent<?> event, final Object... objs) {
+ severe(objs);
+ logEvent(event);
+ }
+
+ /**
+ * Output log line on this logger at a given level of verbosity
+ * @see java.util.logging.Level
+ *
+ * @param level minimum log level required for logging to take place
+ * @param str string to log
+ */
+ public void log(final Level level, final String str) {
+ if (isEnabled && !isQuiet) {
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0 ; i < indent ; i++) {
+ sb.append(' ');
+ }
+ sb.append(str);
+ logger.log(level, sb.toString());
+ }
+ }
+
+ /**
+ * Output log line on this logger at a given level of verbosity
+ * @see java.util.logging.Level
+ *
+ * @param level minimum log level required for logging to take place
+ * @param objs objects for which to invoke toString and concatenate to log
+ */
+ public void log(final Level level, final Object... objs) {
+ if (isEnabled && !isQuiet) {
+ final StringBuilder sb = new StringBuilder();
+ for (final Object obj : objs) {
+ sb.append(obj);
+ }
+ log(level, sb.toString());
+ }
+ }
+
+ /**
+ * Access control context for logger level and instantiation permissions
+ * @return access control context
+ */
+ private static AccessControlContext createLoggerControlAccCtxt() {
+ final Permissions perms = new Permissions();
+ perms.add(new LoggingPermission("control", null));
+ return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
+ }
+
+}