libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / java / util / logging / Logger.java
blobcddc02d1c9cd3b1bf390f94778d80d422cc1eebd
1 /* Logger.java -- a class for logging messages
2 Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.util.logging;
41 import gnu.java.lang.CPStringBuilder;
43 import java.util.List;
44 import java.util.MissingResourceException;
45 import java.util.ResourceBundle;
46 import java.security.AccessController;
47 import java.security.PrivilegedAction;
49 /**
50 * A Logger is used for logging information about events. Usually, there is a
51 * seprate logger for each subsystem or component, although there is a shared
52 * instance for components that make only occasional use of the logging
53 * framework.
54 * <p>
55 * It is common to name a logger after the name of a corresponding Java package.
56 * Loggers are organized into a hierarchical namespace; for example, the logger
57 * <code>"org.gnu.foo"</code> is the <em>parent</em> of logger
58 * <code>"org.gnu.foo.bar"</code>.
59 * <p>
60 * A logger for a named subsystem can be obtained through {@link
61 * java.util.logging.Logger#getLogger(java.lang.String)}. However, only code
62 * which has been granted the permission to control the logging infrastructure
63 * will be allowed to customize that logger. Untrusted code can obtain a
64 * private, anonymous logger through {@link #getAnonymousLogger()} if it wants
65 * to perform any modifications to the logger.
66 * <p>
67 * FIXME: Write more documentation.
69 * @author Sascha Brawer (brawer@acm.org)
71 public class Logger
73 static final Logger root = new Logger("", null);
75 /**
76 * A logger provided to applications that make only occasional use of the
77 * logging framework, typically early prototypes. Serious products are
78 * supposed to create and use their own Loggers, so they can be controlled
79 * individually.
81 public static final Logger global;
83 /**
84 * Use to lock methods on this class instead of calling synchronize on methods
85 * to avoid deadlocks. Yeah, no kidding, we got them :)
87 private static final Object[] lock = new Object[0];
89 static
91 // Our class might be initialized from an unprivileged context
92 global = (Logger) AccessController.doPrivileged(new PrivilegedAction()
94 public Object run()
96 return getLogger("global");
98 });
102 * The name of the Logger, or <code>null</code> if the logger is anonymous.
103 * <p>
104 * A previous version of the GNU Classpath implementation granted untrusted
105 * code the permission to control any logger whose name was null. However,
106 * test code revealed that the Sun J2SE 1.4 reference implementation enforces
107 * the security control for any logger that was not created through
108 * getAnonymousLogger, even if it has a null name. Therefore, a separate flag
109 * {@link Logger#anonymous} was introduced.
111 private final String name;
114 * The name of the resource bundle used for localization.
115 * <p>
116 * This variable cannot be declared as <code>final</code> because its value
117 * can change as a result of calling getLogger(String,String).
119 private String resourceBundleName;
122 * The resource bundle used for localization.
123 * <p>
124 * This variable cannot be declared as <code>final</code> because its value
125 * can change as a result of calling getLogger(String,String).
127 private ResourceBundle resourceBundle;
129 private Filter filter;
131 private final List handlerList = new java.util.ArrayList(4);
133 private Handler[] handlers = new Handler[0];
136 * Indicates whether or not this logger is anonymous. While a
137 * LoggingPermission is required for any modifications to a normal logger,
138 * untrusted code can obtain an anonymous logger and modify it according to
139 * its needs.
140 * <p>
141 * A previous version of the GNU Classpath implementation granted access to
142 * every logger whose name was null. However, test code revealed that the Sun
143 * J2SE 1.4 reference implementation enforces the security control for any
144 * logger that was not created through getAnonymousLogger, even if it has a
145 * null name.
147 private boolean anonymous;
149 private boolean useParentHandlers;
151 private Level level;
153 private Logger parent;
156 * Constructs a Logger for a subsystem. Most applications do not need to
157 * create new Loggers explicitly; instead, they should call the static factory
158 * methods {@link #getLogger(java.lang.String,java.lang.String) getLogger}
159 * (with ResourceBundle for localization) or
160 * {@link #getLogger(java.lang.String) getLogger} (without ResourceBundle),
161 * respectively.
163 * @param name the name for the logger, for example "java.awt" or
164 * "com.foo.bar". The name should be based on the name of the
165 * package issuing log records and consist of dot-separated Java
166 * identifiers.
167 * @param resourceBundleName the name of a resource bundle for localizing
168 * messages, or <code>null</code> to indicate that messages do
169 * not need to be localized.
170 * @throws java.util.MissingResourceException if
171 * <code>resourceBundleName</code> is not <code>null</code>
172 * and no such bundle could be located.
174 protected Logger(String name, String resourceBundleName)
175 throws MissingResourceException
177 this.name = name;
178 this.resourceBundleName = resourceBundleName;
180 if (resourceBundleName == null)
181 resourceBundle = null;
182 else
183 resourceBundle = ResourceBundle.getBundle(resourceBundleName);
185 level = null;
188 * This is null when the root logger is being constructed, and the root
189 * logger afterwards.
191 parent = root;
193 useParentHandlers = (parent != null);
197 * Finds a registered logger for a subsystem, or creates one in case no logger
198 * has been registered yet.
200 * @param name the name for the logger, for example "java.awt" or
201 * "com.foo.bar". The name should be based on the name of the
202 * package issuing log records and consist of dot-separated Java
203 * identifiers.
204 * @throws IllegalArgumentException if a logger for the subsystem identified
205 * by <code>name</code> has already been created, but uses a a
206 * resource bundle for localizing messages.
207 * @throws NullPointerException if <code>name</code> is <code>null</code>.
208 * @return a logger for the subsystem specified by <code>name</code> that
209 * does not localize messages.
211 public static Logger getLogger(String name)
213 return getLogger(name, null);
217 * Finds a registered logger for a subsystem, or creates one in case no logger
218 * has been registered yet.
219 * <p>
220 * If a logger with the specified name has already been registered, the
221 * behavior depends on the resource bundle that is currently associated with
222 * the existing logger.
223 * <ul>
224 * <li>If the existing logger uses the same resource bundle as specified by
225 * <code>resourceBundleName</code>, the existing logger is returned.</li>
226 * <li>If the existing logger currently does not localize messages, the
227 * existing logger is modified to use the bundle specified by
228 * <code>resourceBundleName</code>. The existing logger is then returned.
229 * Therefore, all subsystems currently using this logger will produce
230 * localized messages from now on.</li>
231 * <li>If the existing logger already has an associated resource bundle, but
232 * a different one than specified by <code>resourceBundleName</code>, an
233 * <code>IllegalArgumentException</code> is thrown.</li>
234 * </ul>
236 * @param name the name for the logger, for example "java.awt" or
237 * "org.gnu.foo". The name should be based on the name of the
238 * package issuing log records and consist of dot-separated Java
239 * identifiers.
240 * @param resourceBundleName the name of a resource bundle for localizing
241 * messages, or <code>null</code> to indicate that messages do
242 * not need to be localized.
243 * @return a logger for the subsystem specified by <code>name</code>.
244 * @throws java.util.MissingResourceException if
245 * <code>resourceBundleName</code> is not <code>null</code>
246 * and no such bundle could be located.
247 * @throws IllegalArgumentException if a logger for the subsystem identified
248 * by <code>name</code> has already been created, but uses a
249 * different resource bundle for localizing messages.
250 * @throws NullPointerException if <code>name</code> is <code>null</code>.
252 public static Logger getLogger(String name, String resourceBundleName)
254 LogManager lm = LogManager.getLogManager();
255 Logger result;
257 if (name == null)
258 throw new NullPointerException();
261 * Without synchronized(lm), it could happen that another thread would
262 * create a logger between our calls to getLogger and addLogger. While
263 * addLogger would indicate this by returning false, we could not be sure
264 * that this other logger was still existing when we called getLogger a
265 * second time in order to retrieve it -- note that LogManager is only
266 * allowed to keep weak references to registered loggers, so Loggers can be
267 * garbage collected at any time in general, and between our call to
268 * addLogger and our second call go getLogger in particular. Of course, we
269 * assume here that LogManager.addLogger etc. are synchronizing on the
270 * global LogManager object. There is a comment in the implementation of
271 * LogManager.addLogger referring to this comment here, so that any change
272 * in the synchronization of LogManager will be reflected here.
274 synchronized (lock)
276 synchronized (lm)
278 result = lm.getLogger(name);
279 if (result == null)
281 boolean couldBeAdded;
283 result = new Logger(name, resourceBundleName);
284 couldBeAdded = lm.addLogger(result);
285 if (! couldBeAdded)
286 throw new IllegalStateException("cannot register new logger");
288 else
291 * The logger already exists. Make sure it uses the same
292 * resource bundle for localizing messages.
294 String existingBundleName = result.getResourceBundleName();
297 * The Sun J2SE 1.4 reference implementation will return the
298 * registered logger object, even if it does not have a resource
299 * bundle associated with it. However, it seems to change the
300 * resourceBundle of the registered logger to the bundle whose
301 * name was passed to getLogger.
303 if ((existingBundleName == null) &&
304 (resourceBundleName != null))
307 * If ResourceBundle.getBundle throws an exception, the
308 * existing logger will be unchanged. This would be
309 * different if the assignment to resourceBundleName came
310 * first.
312 result.resourceBundle =
313 ResourceBundle.getBundle(resourceBundleName);
315 result.resourceBundleName = resourceBundleName;
316 return result;
319 if ((existingBundleName != resourceBundleName)
320 && ((existingBundleName == null)
321 || !existingBundleName.equals(resourceBundleName)))
323 throw new IllegalArgumentException();
329 return result;
333 * Creates a new, unnamed logger. Unnamed loggers are not registered in the
334 * namespace of the LogManager, and no special security permission is required
335 * for changing their state. Therefore, untrusted applets are able to modify
336 * their private logger instance obtained through this method.
337 * <p>
338 * The parent of the newly created logger will the the root logger, from which
339 * the level threshold and the handlers are inherited.
341 public static Logger getAnonymousLogger()
343 return getAnonymousLogger(null);
347 * Creates a new, unnamed logger. Unnamed loggers are not registered in the
348 * namespace of the LogManager, and no special security permission is required
349 * for changing their state. Therefore, untrusted applets are able to modify
350 * their private logger instance obtained through this method.
351 * <p>
352 * The parent of the newly created logger will the the root logger, from which
353 * the level threshold and the handlers are inherited.
355 * @param resourceBundleName the name of a resource bundle for localizing
356 * messages, or <code>null</code> to indicate that messages do
357 * not need to be localized.
358 * @throws java.util.MissingResourceException if
359 * <code>resourceBundleName</code> is not <code>null</code>
360 * and no such bundle could be located.
362 public static Logger getAnonymousLogger(String resourceBundleName)
363 throws MissingResourceException
365 Logger result;
367 result = new Logger(null, resourceBundleName);
368 result.anonymous = true;
369 return result;
373 * Returns the name of the resource bundle that is being used for localizing
374 * messages.
376 * @return the name of the resource bundle used for localizing messages, or
377 * <code>null</code> if the parent's resource bundle is used for
378 * this purpose.
380 public String getResourceBundleName()
382 synchronized (lock)
384 return resourceBundleName;
389 * Returns the resource bundle that is being used for localizing messages.
391 * @return the resource bundle used for localizing messages, or
392 * <code>null</code> if the parent's resource bundle is used for
393 * this purpose.
395 public ResourceBundle getResourceBundle()
397 synchronized (lock)
399 return resourceBundle;
404 * Returns the severity level threshold for this <code>Handler</code>. All
405 * log records with a lower severity level will be discarded; a log record of
406 * the same or a higher level will be published unless an installed
407 * <code>Filter</code> decides to discard it.
409 * @return the severity level below which all log messages will be discarded,
410 * or <code>null</code> if the logger inherits the threshold from
411 * its parent.
413 public Level getLevel()
415 synchronized (lock)
417 return level;
422 * Returns whether or not a message of the specified level would be logged by
423 * this logger.
425 * @throws NullPointerException if <code>level</code> is <code>null</code>.
427 public boolean isLoggable(Level level)
429 synchronized (lock)
431 if (this.level != null)
432 return this.level.intValue() <= level.intValue();
434 if (parent != null)
435 return parent.isLoggable(level);
436 else
437 return false;
442 * Sets the severity level threshold for this <code>Handler</code>. All log
443 * records with a lower severity level will be discarded immediately. A log
444 * record of the same or a higher level will be published unless an installed
445 * <code>Filter</code> decides to discard it.
447 * @param level the severity level below which all log messages will be
448 * discarded, or <code>null</code> to indicate that the logger
449 * should inherit the threshold from its parent.
450 * @throws SecurityException if this logger is not anonymous, a security
451 * manager exists, and the caller is not granted the permission to
452 * control the logging infrastructure by having
453 * LoggingPermission("control"). Untrusted code can obtain an
454 * anonymous logger through the static factory method
455 * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
457 public void setLevel(Level level)
459 synchronized (lock)
462 * An application is allowed to control an anonymous logger without
463 * having the permission to control the logging infrastructure.
465 if (! anonymous)
466 LogManager.getLogManager().checkAccess();
468 this.level = level;
472 public Filter getFilter()
474 synchronized (lock)
476 return filter;
481 * @throws SecurityException if this logger is not anonymous, a security
482 * manager exists, and the caller is not granted the permission to
483 * control the logging infrastructure by having
484 * LoggingPermission("control"). Untrusted code can obtain an
485 * anonymous logger through the static factory method
486 * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
488 public void setFilter(Filter filter) throws SecurityException
490 synchronized (lock)
493 * An application is allowed to control an anonymous logger without
494 * having the permission to control the logging infrastructure.
496 if (! anonymous)
497 LogManager.getLogManager().checkAccess();
499 this.filter = filter;
504 * Returns the name of this logger.
506 * @return the name of this logger, or <code>null</code> if the logger is
507 * anonymous.
509 public String getName()
512 * Note that the name of a logger cannot be changed during its lifetime, so
513 * no synchronization is needed.
515 return name;
519 * Passes a record to registered handlers, provided the record is considered
520 * as loggable both by {@link #isLoggable(Level)} and a possibly installed
521 * custom {@link #setFilter(Filter) filter}.
522 * <p>
523 * If the logger has been configured to use parent handlers, the record will
524 * be forwarded to the parent of this logger in addition to being processed by
525 * the handlers registered with this logger.
526 * <p>
527 * The other logging methods in this class are convenience methods that merely
528 * create a new LogRecord and pass it to this method. Therefore, subclasses
529 * usually just need to override this single method for customizing the
530 * logging behavior.
532 * @param record the log record to be inspected and possibly forwarded.
534 public void log(LogRecord record)
536 synchronized (lock)
538 if (!isLoggable(record.getLevel()))
539 return;
541 if ((filter != null) && ! filter.isLoggable(record))
542 return;
545 * If no logger name has been set for the log record, use the name of
546 * this logger.
548 if (record.getLoggerName() == null)
549 record.setLoggerName(name);
552 * Avoid that some other thread is changing the logger hierarchy while
553 * we are traversing it.
555 synchronized (LogManager.getLogManager())
557 Logger curLogger = this;
562 * The Sun J2SE 1.4 reference implementation seems to call the
563 * filter only for the logger whose log method is called, never
564 * for any of its parents. Also, parent loggers publish log
565 * record whatever their level might be. This is pretty weird,
566 * but GNU Classpath tries to be as compatible as possible to
567 * the reference implementation.
569 for (int i = 0; i < curLogger.handlers.length; i++)
570 curLogger.handlers[i].publish(record);
572 if (curLogger.getUseParentHandlers() == false)
573 break;
575 curLogger = curLogger.getParent();
577 while (parent != null);
582 public void log(Level level, String message)
584 if (isLoggable(level))
585 log(level, message, (Object[]) null);
588 public void log(Level level, String message, Object param)
590 synchronized (lock)
592 if (isLoggable(level))
594 StackTraceElement caller = getCallerStackFrame();
595 logp(level, caller != null ? caller.getClassName() : "<unknown>",
596 caller != null ? caller.getMethodName() : "<unknown>",
597 message, param);
602 public void log(Level level, String message, Object[] params)
604 synchronized (lock)
606 if (isLoggable(level))
608 StackTraceElement caller = getCallerStackFrame();
609 logp(level, caller != null ? caller.getClassName() : "<unknown>",
610 caller != null ? caller.getMethodName() : "<unknown>",
611 message, params);
617 public void log(Level level, String message, Throwable thrown)
619 synchronized (lock)
621 if (isLoggable(level))
623 StackTraceElement caller = getCallerStackFrame();
624 logp(level, caller != null ? caller.getClassName() : "<unknown>",
625 caller != null ? caller.getMethodName() : "<unknown>",
626 message, thrown);
631 public void logp(Level level, String sourceClass, String sourceMethod,
632 String message)
634 synchronized (lock)
636 logp(level, sourceClass, sourceMethod, message, (Object[]) null);
640 public void logp(Level level, String sourceClass, String sourceMethod,
641 String message, Object param)
643 synchronized (lock)
645 logp(level, sourceClass, sourceMethod, message, new Object[] { param });
650 private ResourceBundle findResourceBundle()
652 synchronized (lock)
654 if (resourceBundle != null)
655 return resourceBundle;
657 if (parent != null)
658 return parent.findResourceBundle();
660 return null;
664 private void logImpl(Level level, String sourceClass, String sourceMethod,
665 String message, Object[] params)
667 synchronized (lock)
669 LogRecord rec = new LogRecord(level, message);
671 rec.setResourceBundle(findResourceBundle());
672 rec.setSourceClassName(sourceClass);
673 rec.setSourceMethodName(sourceMethod);
674 rec.setParameters(params);
676 log(rec);
680 public void logp(Level level, String sourceClass, String sourceMethod,
681 String message, Object[] params)
683 synchronized (lock)
685 logImpl(level, sourceClass, sourceMethod, message, params);
689 public void logp(Level level, String sourceClass, String sourceMethod,
690 String message, Throwable thrown)
692 synchronized (lock)
694 LogRecord rec = new LogRecord(level, message);
696 rec.setResourceBundle(resourceBundle);
697 rec.setSourceClassName(sourceClass);
698 rec.setSourceMethodName(sourceMethod);
699 rec.setThrown(thrown);
701 log(rec);
705 public void logrb(Level level, String sourceClass, String sourceMethod,
706 String bundleName, String message)
708 synchronized (lock)
710 logrb(level, sourceClass, sourceMethod, bundleName, message,
711 (Object[]) null);
715 public void logrb(Level level, String sourceClass, String sourceMethod,
716 String bundleName, String message, Object param)
718 synchronized (lock)
720 logrb(level, sourceClass, sourceMethod, bundleName, message,
721 new Object[] { param });
725 public void logrb(Level level, String sourceClass, String sourceMethod,
726 String bundleName, String message, Object[] params)
728 synchronized (lock)
730 LogRecord rec = new LogRecord(level, message);
732 rec.setResourceBundleName(bundleName);
733 rec.setSourceClassName(sourceClass);
734 rec.setSourceMethodName(sourceMethod);
735 rec.setParameters(params);
737 log(rec);
741 public void logrb(Level level, String sourceClass, String sourceMethod,
742 String bundleName, String message, Throwable thrown)
744 synchronized (lock)
746 LogRecord rec = new LogRecord(level, message);
748 rec.setResourceBundleName(bundleName);
749 rec.setSourceClassName(sourceClass);
750 rec.setSourceMethodName(sourceMethod);
751 rec.setThrown(thrown);
753 log(rec);
757 public void entering(String sourceClass, String sourceMethod)
759 synchronized (lock)
761 if (isLoggable(Level.FINER))
762 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
766 public void entering(String sourceClass, String sourceMethod, Object param)
768 synchronized (lock)
770 if (isLoggable(Level.FINER))
771 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param);
775 public void entering(String sourceClass, String sourceMethod, Object[] params)
777 synchronized (lock)
779 if (isLoggable(Level.FINER))
781 CPStringBuilder buf = new CPStringBuilder(80);
782 buf.append("ENTRY");
783 for (int i = 0; i < params.length; i++)
785 buf.append(" {");
786 buf.append(i);
787 buf.append('}');
790 logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params);
795 public void exiting(String sourceClass, String sourceMethod)
797 synchronized (lock)
799 if (isLoggable(Level.FINER))
800 logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
804 public void exiting(String sourceClass, String sourceMethod, Object result)
806 synchronized (lock)
808 if (isLoggable(Level.FINER))
809 logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
813 public void throwing(String sourceClass, String sourceMethod, Throwable thrown)
815 synchronized (lock)
817 if (isLoggable(Level.FINER))
818 logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown);
823 * Logs a message with severity level SEVERE, indicating a serious failure
824 * that prevents normal program execution. Messages at this level should be
825 * understandable to an inexperienced, non-technical end user. Ideally, they
826 * explain in simple words what actions the user can take in order to resolve
827 * the problem.
829 * @see Level#SEVERE
830 * @param message the message text, also used as look-up key if the logger is
831 * localizing messages with a resource bundle. While it is possible
832 * to pass <code>null</code>, this is not recommended, since a
833 * logging message without text is unlikely to be helpful.
835 public void severe(String message)
837 synchronized (lock)
839 if (isLoggable(Level.SEVERE))
840 log(Level.SEVERE, message);
845 * Logs a message with severity level WARNING, indicating a potential problem
846 * that does not prevent normal program execution. Messages at this level
847 * should be understandable to an inexperienced, non-technical end user.
848 * Ideally, they explain in simple words what actions the user can take in
849 * order to resolve the problem.
851 * @see Level#WARNING
852 * @param message the message text, also used as look-up key if the logger is
853 * localizing messages with a resource bundle. While it is possible
854 * to pass <code>null</code>, this is not recommended, since a
855 * logging message without text is unlikely to be helpful.
857 public void warning(String message)
859 synchronized (lock)
861 if (isLoggable(Level.WARNING))
862 log(Level.WARNING, message);
867 * Logs a message with severity level INFO. {@link Level#INFO} is intended for
868 * purely informational messages that do not indicate error or warning
869 * situations. In the default logging configuration, INFO messages will be
870 * written to the system console. For this reason, the INFO level should be
871 * used only for messages that are important to end users and system
872 * administrators. Messages at this level should be understandable to an
873 * inexperienced, non-technical user.
875 * @param message the message text, also used as look-up key if the logger is
876 * localizing messages with a resource bundle. While it is possible
877 * to pass <code>null</code>, this is not recommended, since a
878 * logging message without text is unlikely to be helpful.
880 public void info(String message)
882 synchronized (lock)
884 if (isLoggable(Level.INFO))
885 log(Level.INFO, message);
890 * Logs a message with severity level CONFIG. {@link Level#CONFIG} is intended
891 * for static configuration messages, for example about the windowing
892 * environment, the operating system version, etc.
894 * @param message the message text, also used as look-up key if the logger is
895 * localizing messages with a resource bundle. While it is possible
896 * to pass <code>null</code>, this is not recommended, since a
897 * logging message without text is unlikely to be helpful.
899 public void config(String message)
901 synchronized (lock)
903 if (isLoggable(Level.CONFIG))
904 log(Level.CONFIG, message);
909 * Logs a message with severity level FINE. {@link Level#FINE} is intended for
910 * messages that are relevant for developers using the component generating
911 * log messages. Examples include minor, recoverable failures, or possible
912 * inefficiencies.
914 * @param message the message text, also used as look-up key if the logger is
915 * localizing messages with a resource bundle. While it is possible
916 * to pass <code>null</code>, this is not recommended, since a
917 * logging message without text is unlikely to be helpful.
919 public void fine(String message)
921 synchronized (lock)
923 if (isLoggable(Level.FINE))
924 log(Level.FINE, message);
929 * Logs a message with severity level FINER. {@link Level#FINER} is intended
930 * for rather detailed tracing, for example entering a method, returning from
931 * a method, or throwing an exception.
933 * @param message the message text, also used as look-up key if the logger is
934 * localizing messages with a resource bundle. While it is possible
935 * to pass <code>null</code>, this is not recommended, since a
936 * logging message without text is unlikely to be helpful.
938 public void finer(String message)
940 synchronized (lock)
942 if (isLoggable(Level.FINER))
943 log(Level.FINER, message);
948 * Logs a message with severity level FINEST. {@link Level#FINEST} is intended
949 * for highly detailed tracing, for example reaching a certain point inside
950 * the body of a method.
952 * @param message the message text, also used as look-up key if the logger is
953 * localizing messages with a resource bundle. While it is possible
954 * to pass <code>null</code>, this is not recommended, since a
955 * logging message without text is unlikely to be helpful.
957 public void finest(String message)
959 synchronized (lock)
961 if (isLoggable(Level.FINEST))
962 log(Level.FINEST, message);
967 * Adds a handler to the set of handlers that get notified when a log record
968 * is to be published.
970 * @param handler the handler to be added.
971 * @throws NullPointerException if <code>handler</code> is <code>null</code>.
972 * @throws SecurityException if this logger is not anonymous, a security
973 * manager exists, and the caller is not granted the permission to
974 * control the logging infrastructure by having
975 * LoggingPermission("control"). Untrusted code can obtain an
976 * anonymous logger through the static factory method
977 * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
979 public void addHandler(Handler handler) throws SecurityException
981 synchronized (lock)
983 if (handler == null)
984 throw new NullPointerException();
987 * An application is allowed to control an anonymous logger without
988 * having the permission to control the logging infrastructure.
990 if (! anonymous)
991 LogManager.getLogManager().checkAccess();
993 if (! handlerList.contains(handler))
995 handlerList.add(handler);
996 handlers = getHandlers();
1002 * Removes a handler from the set of handlers that get notified when a log
1003 * record is to be published.
1005 * @param handler the handler to be removed.
1006 * @throws SecurityException if this logger is not anonymous, a security
1007 * manager exists, and the caller is not granted the permission to
1008 * control the logging infrastructure by having
1009 * LoggingPermission("control"). Untrusted code can obtain an
1010 * anonymous logger through the static factory method {@link
1011 * #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1012 * @throws NullPointerException if <code>handler</code> is <code>null</code>.
1014 public void removeHandler(Handler handler) throws SecurityException
1016 synchronized (lock)
1019 * An application is allowed to control an anonymous logger without
1020 * having the permission to control the logging infrastructure.
1022 if (! anonymous)
1023 LogManager.getLogManager().checkAccess();
1025 if (handler == null)
1026 throw new NullPointerException();
1028 handlerList.remove(handler);
1029 handlers = getHandlers();
1034 * Returns the handlers currently registered for this Logger. When a log
1035 * record has been deemed as being loggable, it will be passed to all
1036 * registered handlers for publication. In addition, if the logger uses parent
1037 * handlers (see {@link #getUseParentHandlers() getUseParentHandlers} and
1038 * {@link #setUseParentHandlers(boolean) setUseParentHandlers}, the log
1039 * record will be passed to the parent's handlers.
1041 public Handler[] getHandlers()
1043 synchronized (lock)
1046 * We cannot return our internal handlers array because we do not have
1047 * any guarantee that the caller would not change the array entries.
1049 return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]);
1054 * Returns whether or not this Logger forwards log records to handlers
1055 * registered for its parent loggers.
1057 * @return <code>false</code> if this Logger sends log records merely to
1058 * Handlers registered with itself; <code>true</code> if this Logger
1059 * sends log records not only to Handlers registered with itself, but
1060 * also to those Handlers registered with parent loggers.
1062 public boolean getUseParentHandlers()
1064 synchronized (lock)
1066 return useParentHandlers;
1071 * Sets whether or not this Logger forwards log records to handlers registered
1072 * for its parent loggers.
1074 * @param useParentHandlers <code>false</code> to let this Logger send log
1075 * records merely to Handlers registered with itself;
1076 * <code>true</code> to let this Logger send log records not only
1077 * to Handlers registered with itself, but also to those Handlers
1078 * registered with parent loggers.
1079 * @throws SecurityException if this logger is not anonymous, a security
1080 * manager exists, and the caller is not granted the permission to
1081 * control the logging infrastructure by having
1082 * LoggingPermission("control"). Untrusted code can obtain an
1083 * anonymous logger through the static factory method
1084 * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1086 public void setUseParentHandlers(boolean useParentHandlers)
1088 synchronized (lock)
1091 * An application is allowed to control an anonymous logger without
1092 * having the permission to control the logging infrastructure.
1094 if (! anonymous)
1095 LogManager.getLogManager().checkAccess();
1097 this.useParentHandlers = useParentHandlers;
1102 * Returns the parent of this logger. By default, the parent is assigned by
1103 * the LogManager by inspecting the logger's name.
1105 * @return the parent of this logger (as detemined by the LogManager by
1106 * inspecting logger names), the root logger if no other logger has a
1107 * name which is a prefix of this logger's name, or <code>null</code>
1108 * for the root logger.
1110 public Logger getParent()
1112 synchronized (lock)
1114 return parent;
1119 * Sets the parent of this logger. Usually, applications do not call this
1120 * method directly. Instead, the LogManager will ensure that the tree of
1121 * loggers reflects the hierarchical logger namespace. Basically, this method
1122 * should not be public at all, but the GNU implementation follows the API
1123 * specification.
1125 * @throws NullPointerException if <code>parent</code> is <code>null</code>.
1126 * @throws SecurityException if this logger is not anonymous, a security
1127 * manager exists, and the caller is not granted the permission to
1128 * control the logging infrastructure by having
1129 * LoggingPermission("control"). Untrusted code can obtain an
1130 * anonymous logger through the static factory method
1131 * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1133 public void setParent(Logger parent)
1135 synchronized (lock)
1137 if (parent == null)
1138 throw new NullPointerException();
1140 if (this == root)
1141 throw new IllegalArgumentException(
1142 "the root logger can only have a null parent");
1145 * An application is allowed to control an anonymous logger without
1146 * having the permission to control the logging infrastructure.
1148 if (! anonymous)
1149 LogManager.getLogManager().checkAccess();
1151 this.parent = parent;
1156 * Gets the StackTraceElement of the first class that is not this class. That
1157 * should be the initial caller of a logging method.
1159 * @return caller of the initial logging method or null if unknown.
1161 private StackTraceElement getCallerStackFrame()
1163 Throwable t = new Throwable();
1164 StackTraceElement[] stackTrace = t.getStackTrace();
1165 int index = 0;
1167 // skip to stackentries until this class
1168 while (index < stackTrace.length
1169 && ! stackTrace[index].getClassName().equals(getClass().getName()))
1170 index++;
1172 // skip the stackentries of this class
1173 while (index < stackTrace.length
1174 && stackTrace[index].getClassName().equals(getClass().getName()))
1175 index++;
1177 return index < stackTrace.length ? stackTrace[index] : null;
1181 * Reset and close handlers attached to this logger. This function is package
1182 * private because it must only be available to the LogManager.
1184 void resetLogger()
1186 for (int i = 0; i < handlers.length; i++)
1188 handlers[i].close();
1189 handlerList.remove(handlers[i]);
1191 handlers = getHandlers();