Home » openjdk-7 » sun.util.logging » [javadoc | source]

    1   /*
    2    * Copyright (c) 2009, 2011, 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   
   27   package sun.util.logging;
   28   
   29   import java.lang.ref.WeakReference;
   30   import java.lang.reflect.InvocationTargetException;
   31   import java.lang.reflect.Method;
   32   import java.io.PrintStream;
   33   import java.io.PrintWriter;
   34   import java.io.StringWriter;
   35   import java.security.AccessController;
   36   import java.security.PrivilegedAction;
   37   import java.text.MessageFormat;
   38   import java.util.Date;
   39   import java.util.HashMap;
   40   import java.util.Map;
   41   import sun.misc.JavaLangAccess;
   42   import sun.misc.SharedSecrets;
   43   
   44   /**
   45    * Platform logger provides an API for the JRE components to log
   46    * messages.  This enables the runtime components to eliminate the
   47    * static dependency of the logging facility and also defers the
   48    * java.util.logging initialization until it is enabled.
   49    * In addition, the PlatformLogger API can be used if the logging
   50    * module does not exist.
   51    *
   52    * If the logging facility is not enabled, the platform loggers
   53    * will output log messages per the default logging configuration
   54    * (see below). In this implementation, it does not log the
   55    * the stack frame information issuing the log message.
   56    *
   57    * When the logging facility is enabled (at startup or runtime),
   58    * the java.util.logging.Logger will be created for each platform
   59    * logger and all log messages will be forwarded to the Logger
   60    * to handle.
   61    *
   62    * Logging facility is "enabled" when one of the following
   63    * conditions is met:
   64    * 1) a system property "java.util.logging.config.class" or
   65    *    "java.util.logging.config.file" is set
   66    * 2) java.util.logging.LogManager or java.util.logging.Logger
   67    *    is referenced that will trigger the logging initialization.
   68    *
   69    * Default logging configuration:
   70    *   global logging level = INFO
   71    *   handlers = java.util.logging.ConsoleHandler
   72    *   java.util.logging.ConsoleHandler.level = INFO
   73    *   java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
   74    *
   75    * Limitation:
   76    * <JAVA_HOME>/lib/logging.properties is the system-wide logging
   77    * configuration defined in the specification and read in the
   78    * default case to configure any java.util.logging.Logger instances.
   79    * Platform loggers will not detect if <JAVA_HOME>/lib/logging.properties
   80    * is modified. In other words, unless the java.util.logging API
   81    * is used at runtime or the logging system properties is set,
   82    * the platform loggers will use the default setting described above.
   83    * The platform loggers are designed for JDK developers use and
   84    * this limitation can be workaround with setting
   85    * -Djava.util.logging.config.file system property.
   86    *
   87    * @since 1.7
   88    */
   89   public class PlatformLogger {
   90       // Same values as java.util.logging.Level for easy mapping
   91       public static final int OFF     = Integer.MAX_VALUE;
   92       public static final int SEVERE  = 1000;
   93       public static final int WARNING = 900;
   94       public static final int INFO    = 800;
   95       public static final int CONFIG  = 700;
   96       public static final int FINE    = 500;
   97       public static final int FINER   = 400;
   98       public static final int FINEST  = 300;
   99       public static final int ALL     = Integer.MIN_VALUE;
  100   
  101       private static final int defaultLevel = INFO;
  102       private static boolean loggingEnabled;
  103       static {
  104           loggingEnabled = AccessController.doPrivileged(
  105               new PrivilegedAction<Boolean>() {
  106                   public Boolean run() {
  107                       String cname = System.getProperty("java.util.logging.config.class");
  108                       String fname = System.getProperty("java.util.logging.config.file");
  109                       return (cname != null || fname != null);
  110                   }
  111               });
  112       }
  113   
  114       // Table of known loggers.  Maps names to PlatformLoggers.
  115       private static Map<String,WeakReference<PlatformLogger>> loggers =
  116           new HashMap<>();
  117   
  118       /**
  119        * Returns a PlatformLogger of a given name.
  120        */
  121       public static synchronized PlatformLogger getLogger(String name) {
  122           PlatformLogger log = null;
  123           WeakReference<PlatformLogger> ref = loggers.get(name);
  124           if (ref != null) {
  125               log = ref.get();
  126           }
  127           if (log == null) {
  128               log = new PlatformLogger(name);
  129               loggers.put(name, new WeakReference<>(log));
  130           }
  131           return log;
  132       }
  133   
  134       /**
  135        * Initialize java.util.logging.Logger objects for all platform loggers.
  136        * This method is called from LogManager.readPrimordialConfiguration().
  137        */
  138       public static synchronized void redirectPlatformLoggers() {
  139           if (loggingEnabled || !LoggingSupport.isAvailable()) return;
  140   
  141           loggingEnabled = true;
  142           for (Map.Entry<String, WeakReference<PlatformLogger>> entry : loggers.entrySet()) {
  143               WeakReference<PlatformLogger> ref = entry.getValue();
  144               PlatformLogger plog = ref.get();
  145               if (plog != null) {
  146                   plog.newJavaLogger();
  147               }
  148           }
  149       }
  150   
  151       /**
  152        * Creates a new JavaLogger that the platform logger uses
  153        */
  154       private void newJavaLogger() {
  155           logger = new JavaLogger(logger.name, logger.effectiveLevel);
  156       }
  157   
  158       // logger may be replaced with a JavaLogger object
  159       // when the logging facility is enabled
  160       private volatile LoggerProxy logger;
  161   
  162       private PlatformLogger(String name) {
  163           if (loggingEnabled) {
  164               this.logger = new JavaLogger(name);
  165           } else {
  166               this.logger = new LoggerProxy(name);
  167           }
  168       }
  169   
  170       /**
  171        * A convenience method to test if the logger is turned off.
  172        * (i.e. its level is OFF).
  173        */
  174       public boolean isEnabled() {
  175           return logger.isEnabled();
  176       }
  177   
  178       /**
  179        * Gets the name for this platform logger.
  180        */
  181       public String getName() {
  182           return logger.name;
  183       }
  184   
  185       /**
  186        * Returns true if a message of the given level would actually
  187        * be logged by this logger.
  188        */
  189       public boolean isLoggable(int level) {
  190           return logger.isLoggable(level);
  191       }
  192   
  193       /**
  194        * Gets the current log level.  Returns 0 if the current effective level
  195        * is not set (equivalent to Logger.getLevel() returns null).
  196        */
  197       public int getLevel() {
  198           return logger.getLevel();
  199       }
  200   
  201       /**
  202        * Sets the log level.
  203        */
  204       public void setLevel(int newLevel) {
  205           logger.setLevel(newLevel);
  206       }
  207   
  208       /**
  209        * Logs a SEVERE message.
  210        */
  211       public void severe(String msg) {
  212           logger.doLog(SEVERE, msg);
  213       }
  214   
  215       public void severe(String msg, Throwable t) {
  216           logger.doLog(SEVERE, msg, t);
  217       }
  218   
  219       public void severe(String msg, Object... params) {
  220           logger.doLog(SEVERE, msg, params);
  221       }
  222   
  223       /**
  224        * Logs a WARNING message.
  225        */
  226       public void warning(String msg) {
  227           logger.doLog(WARNING, msg);
  228       }
  229   
  230       public void warning(String msg, Throwable t) {
  231           logger.doLog(WARNING, msg, t);
  232       }
  233   
  234       public void warning(String msg, Object... params) {
  235           logger.doLog(WARNING, msg, params);
  236       }
  237   
  238       /**
  239        * Logs an INFO message.
  240        */
  241       public void info(String msg) {
  242           logger.doLog(INFO, msg);
  243       }
  244   
  245       public void info(String msg, Throwable t) {
  246           logger.doLog(INFO, msg, t);
  247       }
  248   
  249       public void info(String msg, Object... params) {
  250           logger.doLog(INFO, msg, params);
  251       }
  252   
  253       /**
  254        * Logs a CONFIG message.
  255        */
  256       public void config(String msg) {
  257           logger.doLog(CONFIG, msg);
  258       }
  259   
  260       public void config(String msg, Throwable t) {
  261           logger.doLog(CONFIG, msg, t);
  262       }
  263   
  264       public void config(String msg, Object... params) {
  265           logger.doLog(CONFIG, msg, params);
  266       }
  267   
  268       /**
  269        * Logs a FINE message.
  270        */
  271       public void fine(String msg) {
  272           logger.doLog(FINE, msg);
  273       }
  274   
  275       public void fine(String msg, Throwable t) {
  276           logger.doLog(FINE, msg, t);
  277       }
  278   
  279       public void fine(String msg, Object... params) {
  280           logger.doLog(FINE, msg, params);
  281       }
  282   
  283       /**
  284        * Logs a FINER message.
  285        */
  286       public void finer(String msg) {
  287           logger.doLog(FINER, msg);
  288       }
  289   
  290       public void finer(String msg, Throwable t) {
  291           logger.doLog(FINER, msg, t);
  292       }
  293   
  294       public void finer(String msg, Object... params) {
  295           logger.doLog(FINER, msg, params);
  296       }
  297   
  298       /**
  299        * Logs a FINEST message.
  300        */
  301       public void finest(String msg) {
  302           logger.doLog(FINEST, msg);
  303       }
  304   
  305       public void finest(String msg, Throwable t) {
  306           logger.doLog(FINEST, msg, t);
  307       }
  308   
  309       public void finest(String msg, Object... params) {
  310           logger.doLog(FINEST, msg, params);
  311       }
  312   
  313       /**
  314        * Default platform logging support - output messages to
  315        * System.err - equivalent to ConsoleHandler with SimpleFormatter.
  316        */
  317       static class LoggerProxy {
  318           private static final PrintStream defaultStream = System.err;
  319   
  320           final String name;
  321           volatile int levelValue;
  322           volatile int effectiveLevel = 0; // current effective level value
  323   
  324           LoggerProxy(String name) {
  325               this(name, defaultLevel);
  326           }
  327   
  328           LoggerProxy(String name, int level) {
  329               this.name = name;
  330               this.levelValue = level == 0 ? defaultLevel : level;
  331           }
  332   
  333           boolean isEnabled() {
  334               return levelValue != OFF;
  335           }
  336   
  337           int getLevel() {
  338               return effectiveLevel;
  339           }
  340   
  341           void setLevel(int newLevel) {
  342               levelValue = newLevel;
  343               effectiveLevel = newLevel;
  344           }
  345   
  346           void doLog(int level, String msg) {
  347               if (level < levelValue || levelValue == OFF) {
  348                   return;
  349               }
  350               defaultStream.print(format(level, msg, null));
  351           }
  352   
  353           void doLog(int level, String msg, Throwable thrown) {
  354               if (level < levelValue || levelValue == OFF) {
  355                   return;
  356               }
  357               defaultStream.print(format(level, msg, thrown));
  358           }
  359   
  360           void doLog(int level, String msg, Object... params) {
  361               if (level < levelValue || levelValue == OFF) {
  362                   return;
  363               }
  364               String newMsg = formatMessage(msg, params);
  365               defaultStream.print(format(level, newMsg, null));
  366           }
  367   
  368           public boolean isLoggable(int level) {
  369               if (level < levelValue || levelValue == OFF) {
  370                   return false;
  371               }
  372               return true;
  373           }
  374   
  375           // Copied from java.util.logging.Formatter.formatMessage
  376           private String formatMessage(String format, Object... parameters) {
  377               // Do the formatting.
  378               try {
  379                   if (parameters == null || parameters.length == 0) {
  380                       // No parameters.  Just return format string.
  381                       return format;
  382                   }
  383                   // Is it a java.text style format?
  384                   // Ideally we could match with
  385                   // Pattern.compile("\\{\\d").matcher(format).find())
  386                   // However the cost is 14% higher, so we cheaply check for
  387                   // 1 of the first 4 parameters
  388                   if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
  389                               format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
  390                       return java.text.MessageFormat.format(format, parameters);
  391                   }
  392                   return format;
  393               } catch (Exception ex) {
  394                   // Formatting failed: use format string.
  395                   return format;
  396               }
  397           }
  398   
  399           private static final String formatString =
  400               LoggingSupport.getSimpleFormat(false); // don't check logging.properties
  401   
  402           // minimize memory allocation
  403           private Date date = new Date();
  404           private synchronized String format(int level, String msg, Throwable thrown) {
  405               date.setTime(System.currentTimeMillis());
  406               String throwable = "";
  407               if (thrown != null) {
  408                   StringWriter sw = new StringWriter();
  409                   PrintWriter pw = new PrintWriter(sw);
  410                   pw.println();
  411                   thrown.printStackTrace(pw);
  412                   pw.close();
  413                   throwable = sw.toString();
  414               }
  415   
  416               return String.format(formatString,
  417                                    date,
  418                                    getCallerInfo(),
  419                                    name,
  420                                    PlatformLogger.getLevelName(level),
  421                                    msg,
  422                                    throwable);
  423           }
  424   
  425           // Returns the caller's class and method's name; best effort
  426           // if cannot infer, return the logger's name.
  427           private String getCallerInfo() {
  428               String sourceClassName = null;
  429               String sourceMethodName = null;
  430   
  431               JavaLangAccess access = SharedSecrets.getJavaLangAccess();
  432               Throwable throwable = new Throwable();
  433               int depth = access.getStackTraceDepth(throwable);
  434   
  435               String logClassName = "sun.util.logging.PlatformLogger";
  436               boolean lookingForLogger = true;
  437               for (int ix = 0; ix < depth; ix++) {
  438                   // Calling getStackTraceElement directly prevents the VM
  439                   // from paying the cost of building the entire stack frame.
  440                   StackTraceElement frame =
  441                       access.getStackTraceElement(throwable, ix);
  442                   String cname = frame.getClassName();
  443                   if (lookingForLogger) {
  444                       // Skip all frames until we have found the first logger frame.
  445                       if (cname.equals(logClassName)) {
  446                           lookingForLogger = false;
  447                       }
  448                   } else {
  449                       if (!cname.equals(logClassName)) {
  450                           // We've found the relevant frame.
  451                           sourceClassName = cname;
  452                           sourceMethodName = frame.getMethodName();
  453                           break;
  454                       }
  455                   }
  456               }
  457   
  458               if (sourceClassName != null) {
  459                   return sourceClassName + " " + sourceMethodName;
  460               } else {
  461                   return name;
  462               }
  463           }
  464       }
  465   
  466       /**
  467        * JavaLogger forwards all the calls to its corresponding
  468        * java.util.logging.Logger object.
  469        */
  470       static class JavaLogger extends LoggerProxy {
  471           private static final Map<Integer, Object> levelObjects =
  472               new HashMap<>();
  473   
  474           static {
  475               if (LoggingSupport.isAvailable()) {
  476                   // initialize the map to Level objects
  477                   getLevelObjects();
  478               }
  479           }
  480   
  481           private static void getLevelObjects() {
  482               // get all java.util.logging.Level objects
  483               int[] levelArray = new int[] {OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL};
  484               for (int l : levelArray) {
  485                   Object level = LoggingSupport.parseLevel(getLevelName(l));
  486                   levelObjects.put(l, level);
  487               }
  488           }
  489   
  490           private final Object javaLogger;
  491           JavaLogger(String name) {
  492               this(name, 0);
  493           }
  494   
  495           JavaLogger(String name, int level) {
  496               super(name, level);
  497               this.javaLogger = LoggingSupport.getLogger(name);
  498               if (level != 0) {
  499                   // level has been updated and so set the Logger's level
  500                   LoggingSupport.setLevel(javaLogger, levelObjects.get(level));
  501               }
  502           }
  503   
  504          /**
  505           * Let Logger.log() do the filtering since if the level of a
  506           * platform logger is altered directly from
  507           * java.util.logging.Logger.setLevel(), the levelValue will
  508           * not be updated.
  509           */
  510           void doLog(int level, String msg) {
  511               LoggingSupport.log(javaLogger, levelObjects.get(level), msg);
  512           }
  513   
  514           void doLog(int level, String msg, Throwable t) {
  515               LoggingSupport.log(javaLogger, levelObjects.get(level), msg, t);
  516           }
  517   
  518           void doLog(int level, String msg, Object... params) {
  519               // only pass String objects to the j.u.l.Logger which may
  520               // be created by untrusted code
  521               int len = (params != null) ? params.length : 0;
  522               Object[] sparams = new String[len];
  523               for (int i = 0; i < len; i++) {
  524                   sparams [i] = String.valueOf(params[i]);
  525               }
  526               LoggingSupport.log(javaLogger, levelObjects.get(level), msg, sparams);
  527           }
  528   
  529           boolean isEnabled() {
  530               Object level = LoggingSupport.getLevel(javaLogger);
  531               return level == null || level.equals(levelObjects.get(OFF)) == false;
  532           }
  533   
  534           int getLevel() {
  535               Object level = LoggingSupport.getLevel(javaLogger);
  536               if (level != null) {
  537                   for (Map.Entry<Integer, Object> l : levelObjects.entrySet()) {
  538                       if (level == l.getValue()) {
  539                           return l.getKey();
  540                       }
  541                   }
  542               }
  543               return 0;
  544           }
  545   
  546           void setLevel(int newLevel) {
  547               levelValue = newLevel;
  548               LoggingSupport.setLevel(javaLogger, levelObjects.get(newLevel));
  549           }
  550   
  551           public boolean isLoggable(int level) {
  552               return LoggingSupport.isLoggable(javaLogger, levelObjects.get(level));
  553           }
  554       }
  555   
  556       private static String getLevelName(int level) {
  557           switch (level) {
  558               case OFF     : return "OFF";
  559               case SEVERE  : return "SEVERE";
  560               case WARNING : return "WARNING";
  561               case INFO    : return "INFO";
  562               case CONFIG  : return "CONFIG";
  563               case FINE    : return "FINE";
  564               case FINER   : return "FINER";
  565               case FINEST  : return "FINEST";
  566               case ALL     : return "ALL";
  567               default      : return "UNKNOWN";
  568           }
  569       }
  570   
  571   }

Home » openjdk-7 » sun.util.logging » [javadoc | source]