• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package java.util.logging;
19 
20 import dalvik.system.DalvikLogHandler;
21 import dalvik.system.DalvikLogging;
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.MissingResourceException;
27 import java.util.ResourceBundle;
28 import java.util.concurrent.CopyOnWriteArrayList;
29 
30 /**
31  * Loggers are used to log records to a variety of destinations such as log files or
32  * the console. They use instances of {@link Handler} to actually do the destination-specific
33  * operations.
34  *
35  * <p>Client applications can get named loggers by calling the {@code getLogger}
36  * methods. They can also get anonymous loggers by calling the
37  * {@code getAnonymousLogger} methods. Named loggers are organized in a
38  * namespace hierarchy managed by a log manager. The naming convention is
39  * usually the Java package naming convention. Anonymous loggers do not belong to any namespace.
40  *
41  * <p>Developers should use named loggers to enable logging to be controlled on a
42  * per-{@code Logger} granularity. The recommended idiom is to create and assign the logger to
43  * a {@code static final} field. This ensures that there's always a strong reference to the logger,
44  * preventing it from being garbage collected. In particular, {@link LogManager#addLogger(Logger)}
45  * will <i>not</i> keep your logger live.
46  *
47  * <p>Loggers "inherit" log level setting from their parent if their own level is
48  * set to {@code null}. This is also true for the resource bundle. The logger's
49  * resource bundle is used to localize the log messages if no resource bundle
50  * name is given when a log method is called. If {@code getUseParentHandlers()}
51  * returns {@code true}, loggers also inherit their parent's handlers. In this
52  * context, "inherit" only means that "behavior" is inherited. The internal
53  * field values will not change, for example, {@code getLevel()} still returns
54  * {@code null}.
55  * <p>
56  * When loading a given resource bundle, the logger first tries to use the
57  * context {@code ClassLoader}. If that fails, it tries the system {@code ClassLoader}. And if
58  * that still fails, it searches up the class stack and uses each class's
59  * {@code ClassLoader} to try to locate the resource bundle.
60  * <p>
61  * Some log methods accept log requests that do not specify the source class and
62  * source method. In these cases, the logging framework will automatically infer
63  * the calling class and method, but this is not guaranteed to be accurate.
64  * <p>
65  * Once a {@code LogRecord} object has been passed into the logging framework,
66  * it is owned by the logging framework and the client applications should not
67  * use it any longer.
68  * <p>
69  * All methods of this class are thread-safe.
70  *
71  * @see LogManager
72  */
73 public class Logger {
74 
75     /** A handler for use when no handler optimization is possible. */
76     private static final DalvikLogHandler GENERAL_LOG_HANDLER = new DalvikLogHandler() {
77         public void publish(Logger source, String tag, Level level, String message) {
78             LogRecord record = new LogRecord(level, message);
79             record.setLoggerName(source.name);
80             source.setResourceBundle(record);
81             source.log(record);
82         }
83     };
84 
85     /**
86      * The name of the global logger. Before using this, see the discussion of how to use
87      * {@code Logger} in the class documentation.
88      * @since 1.6
89      */
90     public static final String GLOBAL_LOGGER_NAME = "global";
91 
92     /**
93      * The global logger is provided as convenience for casual use.
94      * @deprecated This is deadlock-prone. Use {@code Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)}
95      * as a direct replacement, but read the discussion of how to use {@link Logger} in the class
96      * documentation.
97      */
98     @Deprecated
99     public static final Logger global = new Logger(GLOBAL_LOGGER_NAME, null);
100 
101     /**
102      * When converting the concurrent collection of handlers to an array, we
103      * always pass a zero-length array to avoid size miscalculations. Passing
104      * properly-sized arrays is non-atomic, and risks a null element in the
105      * result.
106      */
107     private static final Handler[] EMPTY_HANDLERS_ARRAY = new Handler[0];
108 
109     /** The name of this logger. */
110     private volatile String name;
111 
112     /** The parent logger of this logger. */
113     Logger parent;
114 
115     /** The logging level of this logger, or null if none is set. */
116     volatile Level levelObjVal;
117 
118     /**
119      * The effective logging level of this logger. In order of preference this
120      * is the first applicable of:
121      * <ol>
122      * <li>the int value of this logger's {@link #levelObjVal}
123      * <li>the logging level of the parent
124      * <li>the default level ({@link Level#INFO})
125      * </ol>
126      */
127     volatile int levelIntVal = Level.INFO.intValue();
128 
129     /** The filter. */
130     private Filter filter;
131 
132     /**
133      * The resource bundle used to localize logging messages. If null, no
134      * localization will be performed.
135      */
136     private volatile String resourceBundleName;
137 
138     /** The loaded resource bundle according to the specified name. */
139     private volatile ResourceBundle resourceBundle;
140 
141     /**
142      * The handlers attached to this logger. Eagerly initialized and
143      * concurrently modified.
144      */
145     private final List<Handler> handlers = new CopyOnWriteArrayList<Handler>();
146 
147     /** True to notify the parent's handlers of each log message. */
148     private boolean notifyParentHandlers = true;
149 
150     /**
151      * Indicates whether this logger is named. Only {@link #getAnonymousLogger
152      * anonymous loggers} are unnamed.
153      */
154     private boolean isNamed = true;
155 
156     /**
157      * Child loggers. Should be accessed only while synchronized on {@code
158      * LogManager.getLogManager()}.
159      */
160     final List<Logger> children = new ArrayList<Logger>();
161 
162     /** the tag used for optimized logging. Derived from the logger name. */
163     private final String androidTag;
164 
165     /** Handler delegate for either optimized or standard logging. */
166     private volatile DalvikLogHandler dalvikLogHandler = GENERAL_LOG_HANDLER;
167 
168     /**
169      * We've optimized for the common case: logging to a single handler that
170      * implements {@link DalvikLogHandler}. This is how Android framework
171      * applications are configured by default.
172      *
173      * <p>This optimization has been measured to show a 2.75x improvement in
174      * throughput in the common case: 154ns vs. 56ns per message on a Cortex-A8.
175      * Direct use of {@code android.util.Log} takes 29ns per message.
176      *
177      * <p>Each time the handler configuration changes, either directly or
178      * indirectly, it's necessary to either turn on or off this optimization.
179      * When the optimization is off, {@link #dalvikLogHandler} is assigned to
180      * {@link #GENERAL_LOG_HANDLER} which can satisfy arbitrary configuration.
181      * When the optimization is possible, {@link #dalvikLogHandler} is assigned
182      * to the user's efficient implementation. In pratice this is usually the
183      * {@code com.android.internal.logging.AndroidHandler}.
184      */
updateDalvikLogHandler()185     void updateDalvikLogHandler() {
186         DalvikLogHandler newLogHandler = GENERAL_LOG_HANDLER;
187 
188         Logger parent = this.parent;
189 
190         if (getClass() != Logger.class) {
191             /*
192              * Do nothing. Subclasses aren't eligible for the optimization
193              * because they may override methods like getHandlers() or
194              * log(LogRecord).
195              */
196 
197         } else if (parent == null) {
198             // we use an iterator rather than size()+get() for safe concurrency
199             Iterator<Handler> h = handlers.iterator();
200             if (h.hasNext()) {
201                 Handler firstHandler = h.next();
202                 if (!h.hasNext() && firstHandler instanceof DalvikLogHandler) {
203                     /*
204                      * At this point, we're eligible for the optimization. We've
205                      * satisfied these constraints:
206                      *   1. This is not a subclass of logger
207                      *   2. This is a root logger (no parent)
208                      *   3. There is exactly one handler installed
209                      *   4. That handler is a DalvikLogHandler
210                      */
211                     newLogHandler = (DalvikLogHandler) firstHandler;
212                 }
213             }
214         } else if (handlers.isEmpty() && notifyParentHandlers) {
215             /*
216              * At this point, we're eligible for the optimization if our parent
217              * logger is eligible. We've satisfied these constraints:
218              *   1. This is not a subclass of logger
219              *   2. our parent exists
220              *   3. we have no handlers of our own
221              *   4. we notify our parent's handlers
222              */
223             newLogHandler = parent.dalvikLogHandler;
224         }
225 
226         if (newLogHandler == this.dalvikLogHandler) {
227             return;
228         }
229 
230         this.dalvikLogHandler = newLogHandler;
231 
232         for (Logger logger : children) {
233             logger.updateDalvikLogHandler();
234         }
235     }
236 
237     /**
238      * Constructs a {@code Logger} object with the supplied name and resource
239      * bundle name; {@code notifiyParentHandlers} is set to {@code true}.
240      * <p>
241      * Notice : Loggers use a naming hierarchy. Thus "z.x.y" is a child of "z.x".
242      *
243      * @param name
244      *            the name of this logger, may be {@code null} for anonymous
245      *            loggers.
246      * @param resourceBundleName
247      *            the name of the resource bundle used to localize logging
248      *            messages, may be {@code null}.
249      * @throws MissingResourceException
250      *             if the specified resource bundle can not be loaded.
251      */
Logger(String name, String resourceBundleName)252     protected Logger(String name, String resourceBundleName) {
253         this.name = name;
254         initResourceBundle(resourceBundleName);
255         this.androidTag = DalvikLogging.loggerNameToTag(name);
256         updateDalvikLogHandler();
257     }
258 
259     /**
260      * Load the specified resource bundle, use privileged code.
261      *
262      * @param resourceBundleName
263      *            the name of the resource bundle to load, cannot be {@code null}.
264      * @return the loaded resource bundle.
265      * @throws MissingResourceException
266      *             if the specified resource bundle can not be loaded.
267      */
loadResourceBundle(String resourceBundleName)268     static ResourceBundle loadResourceBundle(String resourceBundleName) {
269         // try context class loader to load the resource
270         ClassLoader cl = Thread.currentThread().getContextClassLoader();
271         if (cl != null) {
272             try {
273                 return ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), cl);
274             } catch (MissingResourceException ignored) {
275                 // Failed to load using context class loader, ignore
276             }
277         }
278         // try system class loader to load the resource
279         cl = ClassLoader.getSystemClassLoader();
280         if (cl != null) {
281             try {
282                 return ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), cl);
283             } catch (MissingResourceException ignored) {
284                 // Failed to load using system class loader, ignore
285             }
286         }
287         throw new MissingResourceException("Failed to load the specified resource bundle \"" +
288                 resourceBundleName + "\"", resourceBundleName, null);
289     }
290 
291     /**
292      * Gets an anonymous logger to use internally in a thread. Anonymous loggers
293      * are not registered in the log manager's namespace. No security checks
294      * will be performed when updating an anonymous logger's control settings.
295      * <p>
296      * The anonymous loggers' parent is set to be the root logger. This way it
297      * inherits the default logging level and handlers from the root logger.
298      *
299      * @return a new instance of anonymous logger.
300      */
getAnonymousLogger()301     public static Logger getAnonymousLogger() {
302         return getAnonymousLogger(null);
303     }
304 
305     /**
306      * Gets an anonymous logger to use internally in a thread. Anonymous loggers
307      * are not registered in the log manager's namespace. No security checks
308      * will be performed when updating an anonymous logger's control settings.
309      * <p>
310      * The anonymous loggers' parent is set to be the root logger. This way it
311      * inherits default logging level and handlers from the root logger.
312      *
313      * @param resourceBundleName
314      *            the name of the resource bundle used to localize log messages.
315      * @return a new instance of anonymous logger.
316      * @throws MissingResourceException
317      *             if the specified resource bundle can not be loaded.
318      */
getAnonymousLogger(String resourceBundleName)319     public static Logger getAnonymousLogger(String resourceBundleName) {
320         Logger result = new Logger(null, resourceBundleName);
321         result.isNamed = false;
322         LogManager logManager = LogManager.getLogManager();
323         logManager.setParent(result, logManager.getLogger(""));
324         return result;
325     }
326 
327     /**
328      * Initializes this logger's resource bundle.
329      *
330      * @throws IllegalArgumentException if this logger's resource bundle already
331      *      exists and is different from the resource bundle specified.
332      */
initResourceBundle(String resourceBundleName)333     private synchronized void initResourceBundle(String resourceBundleName) {
334         String current = this.resourceBundleName;
335 
336         if (current != null) {
337             if (current.equals(resourceBundleName)) {
338                 return;
339             } else {
340                 throw new IllegalArgumentException("Resource bundle name '" + resourceBundleName + "' is inconsistent with the existing '" + current + "'");
341             }
342         }
343 
344         if (resourceBundleName != null) {
345             this.resourceBundle = loadResourceBundle(resourceBundleName);
346             this.resourceBundleName = resourceBundleName;
347         }
348     }
349 
350     /**
351      * Gets a named logger. The returned logger may already exist or may be
352      * newly created. In the latter case, its level will be set to the
353      * configured level according to the {@code LogManager}'s properties.
354      *
355      * @param name
356      *            the name of the logger to get, cannot be {@code null}.
357      * @return a named logger.
358      * @throws MissingResourceException
359      *             If the specified resource bundle can not be loaded.
360      */
getLogger(String name)361     public static Logger getLogger(String name) {
362         return LogManager.getLogManager().getOrCreate(name, null);
363     }
364 
365     /**
366      * Gets a named logger associated with the supplied resource bundle. The
367      * resource bundle will be used to localize logging messages.
368      *
369      * @param name
370      *            the name of the logger to get, cannot be {@code null}.
371      * @param resourceBundleName
372      *            the name of the resource bundle, may be {@code null}.
373      * @throws IllegalArgumentException
374      *             if the logger identified by {@code name} is associated with a
375      *             resource bundle and its name is not equal to
376      *             {@code resourceBundleName}.
377      * @throws MissingResourceException
378      *             if the name of the resource bundle cannot be found.
379      * @return a named logger.
380      */
getLogger(String name, String resourceBundleName)381     public static Logger getLogger(String name, String resourceBundleName) {
382         Logger result = LogManager.getLogManager()
383                 .getOrCreate(name, resourceBundleName);
384         result.initResourceBundle(resourceBundleName);
385         return result;
386     }
387 
388     /**
389      * Returns the global {@code Logger}.
390      * @since 1.7
391      */
getGlobal()392     public static Logger getGlobal() {
393         return global;
394     }
395 
396     /**
397      * Adds a handler to this logger. The {@code name} will be fed with log
398      * records received by this logger.
399      *
400      * @param handler
401      *            the handler object to add, cannot be {@code null}.
402      */
addHandler(Handler handler)403     public void addHandler(Handler handler) {
404         if (handler == null) {
405             throw new NullPointerException("handler == null");
406         }
407         // Anonymous loggers can always add handlers
408         if (this.isNamed) {
409             LogManager.getLogManager().checkAccess();
410         }
411         this.handlers.add(handler);
412         updateDalvikLogHandler();
413     }
414 
415     /**
416      * Set the logger's manager and initializes its configuration from the
417      * manager's properties.
418      */
setManager(LogManager manager)419     void setManager(LogManager manager) {
420         String levelProperty = manager.getProperty(name + ".level");
421         if (levelProperty != null) {
422             try {
423                 manager.setLevelRecursively(Logger.this, Level.parse(levelProperty));
424             } catch (IllegalArgumentException invalidLevel) {
425                 invalidLevel.printStackTrace();
426             }
427         }
428 
429         String handlersPropertyName = name.isEmpty() ? "handlers" : name + ".handlers";
430         String handlersProperty = manager.getProperty(handlersPropertyName);
431         if (handlersProperty != null) {
432             for (String handlerName : handlersProperty.split(",|\\s")) {
433                 if (handlerName.isEmpty()) {
434                     continue;
435                 }
436 
437                 final Handler handler;
438                 try {
439                     handler = (Handler) LogManager.getInstanceByClass(handlerName);
440                 } catch (Exception invalidHandlerName) {
441                     invalidHandlerName.printStackTrace();
442                     continue;
443                 }
444 
445                 try {
446                     String level = manager.getProperty(handlerName + ".level");
447                     if (level != null) {
448                         handler.setLevel(Level.parse(level));
449                     }
450                 } catch (Exception invalidLevel) {
451                     invalidLevel.printStackTrace();
452                 }
453 
454                 handlers.add(handler);
455             }
456         }
457 
458         updateDalvikLogHandler();
459     }
460 
461     /**
462      * Gets all the handlers associated with this logger.
463      *
464      * @return an array of all the handlers associated with this logger.
465      */
getHandlers()466     public Handler[] getHandlers() {
467         return handlers.toArray(EMPTY_HANDLERS_ARRAY);
468     }
469 
470     /**
471      * Removes a handler from this logger. If the specified handler does not
472      * exist then this method has no effect.
473      *
474      * @param handler
475      *            the handler to be removed.
476      */
removeHandler(Handler handler)477     public void removeHandler(Handler handler) {
478         // Anonymous loggers can always remove handlers
479         if (this.isNamed) {
480             LogManager.getLogManager().checkAccess();
481         }
482         if (handler == null) {
483             return;
484         }
485         this.handlers.remove(handler);
486         updateDalvikLogHandler();
487     }
488 
489     /**
490      * Gets the filter used by this logger.
491      *
492      * @return the filter used by this logger, may be {@code null}.
493      */
getFilter()494     public Filter getFilter() {
495         return this.filter;
496     }
497 
498     /**
499      * Sets the filter used by this logger.
500      *
501      * @param newFilter
502      *            the filter to set, may be {@code null}.
503      */
setFilter(Filter newFilter)504     public void setFilter(Filter newFilter) {
505         // Anonymous loggers can always set the filter
506         if (this.isNamed) {
507             LogManager.getLogManager().checkAccess();
508         }
509         filter = newFilter;
510     }
511 
512     /**
513      * Gets the logging level of this logger. A {@code null} level indicates
514      * that this logger inherits its parent's level.
515      *
516      * @return the logging level of this logger.
517      */
getLevel()518     public Level getLevel() {
519         return levelObjVal;
520     }
521 
522     /**
523      * Sets the logging level for this logger. A {@code null} level indicates
524      * that this logger will inherit its parent's level.
525      *
526      * @param newLevel
527      *            the logging level to set.
528      */
setLevel(Level newLevel)529     public void setLevel(Level newLevel) {
530         // Anonymous loggers can always set the level
531         LogManager logManager = LogManager.getLogManager();
532         if (this.isNamed) {
533             logManager.checkAccess();
534         }
535         logManager.setLevelRecursively(this, newLevel);
536     }
537 
538     /**
539      * Gets the flag which indicates whether to use the handlers of this
540      * logger's parent to publish incoming log records, potentially recursively
541      * up the namespace.
542      *
543      * @return {@code true} if set to use parent's handlers, {@code false}
544      *         otherwise.
545      */
getUseParentHandlers()546     public boolean getUseParentHandlers() {
547         return this.notifyParentHandlers;
548     }
549 
550     /**
551      * Sets the flag which indicates whether to use the handlers of this
552      * logger's parent, potentially recursively up the namespace.
553      *
554      * @param notifyParentHandlers
555      *            the new flag indicating whether to use the parent's handlers.
556      */
setUseParentHandlers(boolean notifyParentHandlers)557     public void setUseParentHandlers(boolean notifyParentHandlers) {
558         // Anonymous loggers can always set the useParentHandlers flag
559         if (this.isNamed) {
560             LogManager.getLogManager().checkAccess();
561         }
562         this.notifyParentHandlers = notifyParentHandlers;
563         updateDalvikLogHandler();
564     }
565 
566     /**
567      * Gets the nearest parent of this logger in the namespace, a {@code null}
568      * value will be returned if called on the root logger.
569      *
570      * @return the parent of this logger in the namespace.
571      */
getParent()572     public Logger getParent() {
573         return parent;
574     }
575 
576     /**
577      * Sets the parent of this logger in the namespace. This method should be
578      * used by the {@code LogManager} object only.
579      *
580      * @param parent
581      *            the parent logger to set.
582      */
setParent(Logger parent)583     public void setParent(Logger parent) {
584         if (parent == null) {
585             throw new NullPointerException("parent == null");
586         }
587 
588         // even anonymous loggers are checked
589         LogManager logManager = LogManager.getLogManager();
590         logManager.checkAccess();
591         logManager.setParent(this, parent);
592     }
593 
594     /**
595      * Gets the name of this logger, {@code null} for anonymous loggers.
596      *
597      * @return the name of this logger.
598      */
getName()599     public String getName() {
600         return this.name;
601     }
602 
603     /**
604      * Gets the loaded resource bundle used by this logger to localize logging
605      * messages. If the value is {@code null}, the parent's resource bundle will be
606      * inherited.
607      *
608      * @return the loaded resource bundle used by this logger.
609      */
getResourceBundle()610     public ResourceBundle getResourceBundle() {
611         return this.resourceBundle;
612     }
613 
614     /**
615      * Gets the name of the loaded resource bundle used by this logger to
616      * localize logging messages. If the value is {@code null}, the parent's resource
617      * bundle name will be inherited.
618      *
619      * @return the name of the loaded resource bundle used by this logger.
620      */
getResourceBundleName()621     public String getResourceBundleName() {
622         return this.resourceBundleName;
623     }
624 
625     /**
626      * This method is for compatibility. Tests written to the reference
627      * implementation API imply that the isLoggable() method is not called
628      * directly. This behavior is important because subclass may override
629      * isLoggable() method, so that affect the result of log methods.
630      */
internalIsLoggable(Level l)631     private boolean internalIsLoggable(Level l) {
632         int effectiveLevel = levelIntVal;
633         if (effectiveLevel == Level.OFF.intValue()) {
634             // always return false if the effective level is off
635             return false;
636         }
637         return l.intValue() >= effectiveLevel;
638     }
639 
640     /**
641      * Determines whether this logger will actually log messages of the
642      * specified level. The effective level used to do the determination may be
643      * inherited from its parent. The default level is {@code Level.INFO}.
644      *
645      * @param l
646      *            the level to check.
647      * @return {@code true} if this logger will actually log this level,
648      *         otherwise {@code false}.
649      */
isLoggable(Level l)650     public boolean isLoggable(Level l) {
651         return internalIsLoggable(l);
652     }
653 
654     /**
655      * Sets the resource bundle and its name for a supplied LogRecord object.
656      * This method first tries to use this logger's resource bundle if any,
657      * otherwise try to inherit from this logger's parent, recursively up the
658      * namespace.
659      */
setResourceBundle(LogRecord record)660     private void setResourceBundle(LogRecord record) {
661         for (Logger p = this; p != null; p = p.parent) {
662             String resourceBundleName = p.resourceBundleName;
663             if (resourceBundleName != null) {
664                 record.setResourceBundle(p.resourceBundle);
665                 record.setResourceBundleName(resourceBundleName);
666                 return;
667             }
668         }
669     }
670 
671     /**
672      * Logs a message indicating that a method has been entered. A log record
673      * with log level {@code Level.FINER}, log message "ENTRY", the specified
674      * source class name and source method name is submitted for logging.
675      *
676      * @param sourceClass
677      *            the calling class name.
678      * @param sourceMethod
679      *            the method name.
680      */
entering(String sourceClass, String sourceMethod)681     public void entering(String sourceClass, String sourceMethod) {
682         if (!internalIsLoggable(Level.FINER)) {
683             return;
684         }
685 
686         LogRecord record = new LogRecord(Level.FINER, "ENTRY");
687         record.setLoggerName(this.name);
688         record.setSourceClassName(sourceClass);
689         record.setSourceMethodName(sourceMethod);
690         setResourceBundle(record);
691         log(record);
692     }
693 
694     /**
695      * Logs a message indicating that a method has been entered. A log record
696      * with log level {@code Level.FINER}, log message "ENTRY", the specified
697      * source class name, source method name and one parameter is submitted for
698      * logging.
699      *
700      * @param sourceClass
701      *            the source class name.
702      * @param sourceMethod
703      *            the source method name.
704      * @param param
705      *            the parameter for the method call.
706      */
entering(String sourceClass, String sourceMethod, Object param)707     public void entering(String sourceClass, String sourceMethod, Object param) {
708         if (!internalIsLoggable(Level.FINER)) {
709             return;
710         }
711 
712         LogRecord record = new LogRecord(Level.FINER, "ENTRY" + " {0}");
713         record.setLoggerName(this.name);
714         record.setSourceClassName(sourceClass);
715         record.setSourceMethodName(sourceMethod);
716         record.setParameters(new Object[] { param });
717         setResourceBundle(record);
718         log(record);
719     }
720 
721     /**
722      * Logs a message indicating that a method has been entered. A log record
723      * with log level {@code Level.FINER}, log message "ENTRY", the specified
724      * source class name, source method name and array of parameters is
725      * submitted for logging.
726      *
727      * @param sourceClass
728      *            the source class name.
729      * @param sourceMethod
730      *            the source method name.
731      * @param params
732      *            an array of parameters for the method call.
733      */
entering(String sourceClass, String sourceMethod, Object[] params)734     public void entering(String sourceClass, String sourceMethod,
735             Object[] params) {
736         if (!internalIsLoggable(Level.FINER)) {
737             return;
738         }
739 
740         String msg = "ENTRY";
741         if (params != null) {
742             StringBuilder msgBuffer = new StringBuilder("ENTRY");
743             for (int i = 0; i < params.length; i++) {
744                 msgBuffer.append(" {").append(i).append("}");
745             }
746             msg = msgBuffer.toString();
747         }
748         LogRecord record = new LogRecord(Level.FINER, msg);
749         record.setLoggerName(this.name);
750         record.setSourceClassName(sourceClass);
751         record.setSourceMethodName(sourceMethod);
752         record.setParameters(params);
753         setResourceBundle(record);
754         log(record);
755     }
756 
757     /**
758      * Logs a message indicating that a method is exited. A log record with log
759      * level {@code Level.FINER}, log message "RETURN", the specified source
760      * class name and source method name is submitted for logging.
761      *
762      * @param sourceClass
763      *            the calling class name.
764      * @param sourceMethod
765      *            the method name.
766      */
exiting(String sourceClass, String sourceMethod)767     public void exiting(String sourceClass, String sourceMethod) {
768         if (!internalIsLoggable(Level.FINER)) {
769             return;
770         }
771 
772         LogRecord record = new LogRecord(Level.FINER, "RETURN");
773         record.setLoggerName(this.name);
774         record.setSourceClassName(sourceClass);
775         record.setSourceMethodName(sourceMethod);
776         setResourceBundle(record);
777         log(record);
778     }
779 
780     /**
781      * Logs a message indicating that a method is exited. A log record with log
782      * level {@code Level.FINER}, log message "RETURN", the specified source
783      * class name, source method name and return value is submitted for logging.
784      *
785      * @param sourceClass
786      *            the source class name.
787      * @param sourceMethod
788      *            the source method name.
789      * @param result
790      *            the return value of the method call.
791      */
exiting(String sourceClass, String sourceMethod, Object result)792     public void exiting(String sourceClass, String sourceMethod, Object result) {
793         if (!internalIsLoggable(Level.FINER)) {
794             return;
795         }
796 
797         LogRecord record = new LogRecord(Level.FINER, "RETURN" + " {0}");
798         record.setLoggerName(this.name);
799         record.setSourceClassName(sourceClass);
800         record.setSourceMethodName(sourceMethod);
801         record.setParameters(new Object[] { result });
802         setResourceBundle(record);
803         log(record);
804     }
805 
806     /**
807      * Logs a message indicating that an exception is thrown. A log record with
808      * log level {@code Level.FINER}, log message "THROW", the specified source
809      * class name, source method name and the {@code Throwable} object is
810      * submitted for logging.
811      *
812      * @param sourceClass
813      *            the source class name.
814      * @param sourceMethod
815      *            the source method name.
816      * @param thrown
817      *            the {@code Throwable} object.
818      */
throwing(String sourceClass, String sourceMethod, Throwable thrown)819     public void throwing(String sourceClass, String sourceMethod,
820             Throwable thrown) {
821         if (!internalIsLoggable(Level.FINER)) {
822             return;
823         }
824 
825         LogRecord record = new LogRecord(Level.FINER, "THROW");
826         record.setLoggerName(this.name);
827         record.setSourceClassName(sourceClass);
828         record.setSourceMethodName(sourceMethod);
829         record.setThrown(thrown);
830         setResourceBundle(record);
831         log(record);
832     }
833 
834     /**
835      * Logs a message of level {@code Level.SEVERE}; the message is transmitted
836      * to all subscribed handlers.
837      *
838      * @param msg
839      *            the message to log.
840      */
severe(String msg)841     public void severe(String msg) {
842         log(Level.SEVERE, msg);
843     }
844 
845     /**
846      * Logs a message of level {@code Level.WARNING}; the message is
847      * transmitted to all subscribed handlers.
848      *
849      * @param msg
850      *            the message to log.
851      */
warning(String msg)852     public void warning(String msg) {
853         log(Level.WARNING, msg);
854     }
855 
856     /**
857      * Logs a message of level {@code Level.INFO}; the message is transmitted
858      * to all subscribed handlers.
859      *
860      * @param msg
861      *            the message to log.
862      */
info(String msg)863     public void info(String msg) {
864         log(Level.INFO, msg);
865     }
866 
867     /**
868      * Logs a message of level {@code Level.CONFIG}; the message is transmitted
869      * to all subscribed handlers.
870      *
871      * @param msg
872      *            the message to log.
873      */
config(String msg)874     public void config(String msg) {
875         log(Level.CONFIG, msg);
876     }
877 
878     /**
879      * Logs a message of level {@code Level.FINE}; the message is transmitted
880      * to all subscribed handlers.
881      *
882      * @param msg
883      *            the message to log.
884      */
fine(String msg)885     public void fine(String msg) {
886         log(Level.FINE, msg);
887     }
888 
889     /**
890      * Logs a message of level {@code Level.FINER}; the message is transmitted
891      * to all subscribed handlers.
892      *
893      * @param msg
894      *            the message to log.
895      */
finer(String msg)896     public void finer(String msg) {
897         log(Level.FINER, msg);
898     }
899 
900     /**
901      * Logs a message of level {@code Level.FINEST}; the message is transmitted
902      * to all subscribed handlers.
903      *
904      * @param msg
905      *            the message to log.
906      */
finest(String msg)907     public void finest(String msg) {
908         log(Level.FINEST, msg);
909     }
910 
911     /**
912      * Logs a message of the specified level. The message is transmitted to all
913      * subscribed handlers.
914      *
915      * @param logLevel
916      *            the level of the specified message.
917      * @param msg
918      *            the message to log.
919      */
log(Level logLevel, String msg)920     public void log(Level logLevel, String msg) {
921         if (!internalIsLoggable(logLevel)) {
922             return;
923         }
924         dalvikLogHandler.publish(this, androidTag, logLevel, msg);
925     }
926 
927     /**
928      * Logs a message of the specified level with the supplied parameter. The
929      * message is then transmitted to all subscribed handlers.
930      *
931      * @param logLevel
932      *            the level of the given message.
933      * @param msg
934      *            the message to log.
935      * @param param
936      *            the parameter associated with the event that is logged.
937      */
log(Level logLevel, String msg, Object param)938     public void log(Level logLevel, String msg, Object param) {
939         if (!internalIsLoggable(logLevel)) {
940             return;
941         }
942 
943         LogRecord record = new LogRecord(logLevel, msg);
944         record.setLoggerName(this.name);
945         record.setParameters(new Object[] { param });
946         setResourceBundle(record);
947         log(record);
948     }
949 
950     /**
951      * Logs a message of the specified level with the supplied parameter array.
952      * The message is then transmitted to all subscribed handlers.
953      *
954      * @param logLevel
955      *            the level of the given message
956      * @param msg
957      *            the message to log.
958      * @param params
959      *            the parameter array associated with the event that is logged.
960      */
log(Level logLevel, String msg, Object[] params)961     public void log(Level logLevel, String msg, Object[] params) {
962         if (!internalIsLoggable(logLevel)) {
963             return;
964         }
965 
966         LogRecord record = new LogRecord(logLevel, msg);
967         record.setLoggerName(this.name);
968         record.setParameters(params);
969         setResourceBundle(record);
970         log(record);
971     }
972 
973     /**
974      * Logs a message of the specified level with the supplied {@code Throwable}
975      * object. The message is then transmitted to all subscribed handlers.
976      *
977      * @param logLevel
978      *            the level of the given message.
979      * @param msg
980      *            the message to log.
981      * @param thrown
982      *            the {@code Throwable} object associated with the event that is
983      *            logged.
984      */
log(Level logLevel, String msg, Throwable thrown)985     public void log(Level logLevel, String msg, Throwable thrown) {
986         if (!internalIsLoggable(logLevel)) {
987             return;
988         }
989 
990         LogRecord record = new LogRecord(logLevel, msg);
991         record.setLoggerName(this.name);
992         record.setThrown(thrown);
993         setResourceBundle(record);
994         log(record);
995     }
996 
997     /**
998      * Logs a given log record. Only records with a logging level that is equal
999      * or greater than this logger's level will be submitted to this logger's
1000      * handlers for logging. If {@code getUseParentHandlers()} returns {@code
1001      * true}, the log record will also be submitted to the handlers of this
1002      * logger's parent, potentially recursively up the namespace.
1003      * <p>
1004      * Since all other log methods call this method to actually perform the
1005      * logging action, subclasses of this class can override this method to
1006      * catch all logging activities.
1007      * </p>
1008      *
1009      * @param record
1010      *            the log record to be logged.
1011      */
log(LogRecord record)1012     public void log(LogRecord record) {
1013         if (!internalIsLoggable(record.getLevel())) {
1014             return;
1015         }
1016 
1017         // apply the filter if any
1018         Filter f = filter;
1019         if (f != null && !f.isLoggable(record)) {
1020             return;
1021         }
1022 
1023         /*
1024          * call the handlers of this logger, throw any exception that occurs
1025          */
1026         Handler[] allHandlers = getHandlers();
1027         for (Handler element : allHandlers) {
1028             element.publish(record);
1029         }
1030         // call the parent's handlers if set useParentHandlers
1031         Logger temp = this;
1032         Logger theParent = temp.parent;
1033         while (theParent != null && temp.getUseParentHandlers()) {
1034             Handler[] ha = theParent.getHandlers();
1035             for (Handler element : ha) {
1036                 element.publish(record);
1037             }
1038             temp = theParent;
1039             theParent = temp.parent;
1040         }
1041     }
1042 
1043     /**
1044      * Logs a message of the given level with the specified source class name
1045      * and source method name.
1046      *
1047      * @param logLevel
1048      *            the level of the given message.
1049      * @param sourceClass
1050      *            the source class name.
1051      * @param sourceMethod
1052      *            the source method name.
1053      * @param msg
1054      *            the message to be logged.
1055      */
logp(Level logLevel, String sourceClass, String sourceMethod, String msg)1056     public void logp(Level logLevel, String sourceClass, String sourceMethod,
1057             String msg) {
1058         if (!internalIsLoggable(logLevel)) {
1059             return;
1060         }
1061 
1062         LogRecord record = new LogRecord(logLevel, msg);
1063         record.setLoggerName(this.name);
1064         record.setSourceClassName(sourceClass);
1065         record.setSourceMethodName(sourceMethod);
1066         setResourceBundle(record);
1067         log(record);
1068     }
1069 
1070     /**
1071      * Logs a message of the given level with the specified source class name,
1072      * source method name and parameter.
1073      *
1074      * @param logLevel
1075      *            the level of the given message
1076      * @param sourceClass
1077      *            the source class name
1078      * @param sourceMethod
1079      *            the source method name
1080      * @param msg
1081      *            the message to be logged
1082      * @param param
1083      *            the parameter associated with the event that is logged.
1084      */
logp(Level logLevel, String sourceClass, String sourceMethod, String msg, Object param)1085     public void logp(Level logLevel, String sourceClass, String sourceMethod,
1086             String msg, Object param) {
1087         if (!internalIsLoggable(logLevel)) {
1088             return;
1089         }
1090 
1091         LogRecord record = new LogRecord(logLevel, msg);
1092         record.setLoggerName(this.name);
1093         record.setSourceClassName(sourceClass);
1094         record.setSourceMethodName(sourceMethod);
1095         record.setParameters(new Object[] { param });
1096         setResourceBundle(record);
1097         log(record);
1098     }
1099 
1100     /**
1101      * Logs a message of the given level with the specified source class name,
1102      * source method name and parameter array.
1103      *
1104      * @param logLevel
1105      *            the level of the given message.
1106      * @param sourceClass
1107      *            the source class name.
1108      * @param sourceMethod
1109      *            the source method name.
1110      * @param msg
1111      *            the message to be logged.
1112      * @param params
1113      *            the parameter array associated with the event that is logged.
1114      */
logp(Level logLevel, String sourceClass, String sourceMethod, String msg, Object[] params)1115     public void logp(Level logLevel, String sourceClass, String sourceMethod,
1116             String msg, Object[] params) {
1117         if (!internalIsLoggable(logLevel)) {
1118             return;
1119         }
1120 
1121         LogRecord record = new LogRecord(logLevel, msg);
1122         record.setLoggerName(this.name);
1123         record.setSourceClassName(sourceClass);
1124         record.setSourceMethodName(sourceMethod);
1125         record.setParameters(params);
1126         setResourceBundle(record);
1127         log(record);
1128     }
1129 
1130     /**
1131      * Logs a message of the given level with the specified source class name,
1132      * source method name and {@code Throwable} object.
1133      *
1134      * @param logLevel
1135      *            the level of the given message.
1136      * @param sourceClass
1137      *            the source class name.
1138      * @param sourceMethod
1139      *            the source method name.
1140      * @param msg
1141      *            the message to be logged.
1142      * @param thrown
1143      *            the {@code Throwable} object.
1144      */
logp(Level logLevel, String sourceClass, String sourceMethod, String msg, Throwable thrown)1145     public void logp(Level logLevel, String sourceClass, String sourceMethod,
1146             String msg, Throwable thrown) {
1147         if (!internalIsLoggable(logLevel)) {
1148             return;
1149         }
1150 
1151         LogRecord record = new LogRecord(logLevel, msg);
1152         record.setLoggerName(this.name);
1153         record.setSourceClassName(sourceClass);
1154         record.setSourceMethodName(sourceMethod);
1155         record.setThrown(thrown);
1156         setResourceBundle(record);
1157         log(record);
1158     }
1159 
1160     /**
1161      * Logs a message of the given level with the specified source class name
1162      * and source method name, using the given resource bundle to localize the
1163      * message. If {@code bundleName} is null, the empty string or not valid then
1164      * the message is not localized.
1165      *
1166      * @param logLevel
1167      *            the level of the given message.
1168      * @param sourceClass
1169      *            the source class name.
1170      * @param sourceMethod
1171      *            the source method name.
1172      * @param bundleName
1173      *            the name of the resource bundle used to localize the message.
1174      * @param msg
1175      *            the message to be logged.
1176      */
logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg)1177     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
1178             String bundleName, String msg) {
1179         if (!internalIsLoggable(logLevel)) {
1180             return;
1181         }
1182 
1183         LogRecord record = new LogRecord(logLevel, msg);
1184         if (bundleName != null) {
1185             try {
1186                 record.setResourceBundle(loadResourceBundle(bundleName));
1187             } catch (MissingResourceException e) {
1188                 // ignore
1189             }
1190             record.setResourceBundleName(bundleName);
1191         }
1192         record.setLoggerName(this.name);
1193         record.setSourceClassName(sourceClass);
1194         record.setSourceMethodName(sourceMethod);
1195         log(record);
1196     }
1197 
1198     /**
1199      * Logs a message of the given level with the specified source class name,
1200      * source method name and parameter, using the given resource bundle to
1201      * localize the message. If {@code bundleName} is null, the empty string
1202      * or not valid then the message is not localized.
1203      *
1204      * @param logLevel
1205      *            the level of the given message.
1206      * @param sourceClass
1207      *            the source class name.
1208      * @param sourceMethod
1209      *            the source method name.
1210      * @param bundleName
1211      *            the name of the resource bundle used to localize the message.
1212      * @param msg
1213      *            the message to be logged.
1214      * @param param
1215      *            the parameter associated with the event that is logged.
1216      */
logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg, Object param)1217     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
1218             String bundleName, String msg, Object param) {
1219         if (!internalIsLoggable(logLevel)) {
1220             return;
1221         }
1222 
1223         LogRecord record = new LogRecord(logLevel, msg);
1224         if (bundleName != null) {
1225             try {
1226                 record.setResourceBundle(loadResourceBundle(bundleName));
1227             } catch (MissingResourceException e) {
1228                 // ignore
1229             }
1230             record.setResourceBundleName(bundleName);
1231         }
1232         record.setLoggerName(this.name);
1233         record.setSourceClassName(sourceClass);
1234         record.setSourceMethodName(sourceMethod);
1235         record.setParameters(new Object[] { param });
1236         log(record);
1237     }
1238 
1239     /**
1240      * Logs a message of the given level with the specified source class name,
1241      * source method name and parameter array, using the given resource bundle
1242      * to localize the message. If {@code bundleName} is null, the empty string
1243      * or not valid then the message is not localized.
1244      *
1245      * @param logLevel
1246      *            the level of the given message.
1247      * @param sourceClass
1248      *            the source class name.
1249      * @param sourceMethod
1250      *            the source method name.
1251      * @param bundleName
1252      *            the name of the resource bundle used to localize the message.
1253      * @param msg
1254      *            the message to be logged.
1255      * @param params
1256      *            the parameter array associated with the event that is logged.
1257      */
logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg, Object[] params)1258     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
1259             String bundleName, String msg, Object[] params) {
1260         if (!internalIsLoggable(logLevel)) {
1261             return;
1262         }
1263 
1264         LogRecord record = new LogRecord(logLevel, msg);
1265         if (bundleName != null) {
1266             try {
1267                 record.setResourceBundle(loadResourceBundle(bundleName));
1268             } catch (MissingResourceException e) {
1269                 // ignore
1270             }
1271             record.setResourceBundleName(bundleName);
1272         }
1273         record.setLoggerName(this.name);
1274         record.setSourceClassName(sourceClass);
1275         record.setSourceMethodName(sourceMethod);
1276         record.setParameters(params);
1277         log(record);
1278     }
1279 
1280     /**
1281      * Logs a message of the given level with the specified source class name,
1282      * source method name and {@code Throwable} object, using the given resource
1283      * bundle to localize the message. If {@code bundleName} is null, the empty
1284      * string or not valid then the message is not localized.
1285      *
1286      * @param logLevel
1287      *            the level of the given message
1288      * @param sourceClass
1289      *            the source class name
1290      * @param sourceMethod
1291      *            the source method name
1292      * @param bundleName
1293      *            the name of the resource bundle used to localize the message.
1294      * @param msg
1295      *            the message to be logged.
1296      * @param thrown
1297      *            the {@code Throwable} object.
1298      */
logrb(Level logLevel, String sourceClass, String sourceMethod, String bundleName, String msg, Throwable thrown)1299     public void logrb(Level logLevel, String sourceClass, String sourceMethod,
1300             String bundleName, String msg, Throwable thrown) {
1301         if (!internalIsLoggable(logLevel)) {
1302             return;
1303         }
1304 
1305         LogRecord record = new LogRecord(logLevel, msg);
1306         if (bundleName != null) {
1307             try {
1308                 record.setResourceBundle(loadResourceBundle(bundleName));
1309             } catch (MissingResourceException e) {
1310                 // ignore
1311             }
1312             record.setResourceBundleName(bundleName);
1313         }
1314         record.setLoggerName(this.name);
1315         record.setSourceClassName(sourceClass);
1316         record.setSourceMethodName(sourceMethod);
1317         record.setThrown(thrown);
1318         log(record);
1319     }
1320 
reset()1321     void reset() {
1322         levelObjVal = null;
1323         levelIntVal = Level.INFO.intValue();
1324 
1325         for (Handler handler : handlers) {
1326             try {
1327                 if (handlers.remove(handler)) {
1328                     handler.close();
1329                 }
1330             } catch (Exception ignored) {
1331             }
1332         }
1333 
1334         updateDalvikLogHandler();
1335     }
1336 }
1337