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