1 package org.testng.log4testng; 2 3 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.PrintStream; 8 import java.util.Iterator; 9 import java.util.Map; 10 import java.util.Map.Entry; 11 import java.util.Properties; 12 13 import org.testng.Assert; 14 import org.testng.collections.Maps; 15 16 /** 17 * TestNG support logging via a custom logging framework similar to 18 * <a href="http://logging.apache.org/log4j"> Log4j</a>. To control logging, add a 19 * resource named "log4testng.properties" to your classpath. The logging levels are 20 * TRACE, DEBUG, INFO, WARN, ERROR and FATAL. 21 * The Logging framework has the following characteristics: 22 * 23 * <ul> 24 * <li>All logging is done using System.out (for levels < ERROR) or System.err. There 25 * is no way to specify Appenders.</li> 26 * <li>There is no way to control logging programmatically.</li> 27 * <li>The log4testng.properties resource is searched in the classpath on the first 28 * call to the logging API. If it is not present, logging defaults to the WARN 29 * level.</li> 30 * </ul> 31 * 32 * The property file contains lines in the following format: 33 * 34 * <pre><code> 35 * # log4testng will log its own behavior (generally used for debugging this package only). 36 * log4testng.debug=true 37 * 38 * # Specifies the root Loggers logging level. Will log DEBUG level and above 39 * log4testng.rootLogger=DEBUG 40 * 41 * # The org.testng.reporters.EmailableReporter Logger will log TRACE level and above 42 * log4testng.logger.org.testng.reporters.EmailableReporter=TRACE 43 * 44 * # All Logger in packages below org.testng will log WARN level and above 45 * log4testng.logger.org.testng=WARN 46 * </code></pre> 47 * 48 * In your source files you will typically instantiate and use loggers this ways: 49 * <pre><code> 50 * import org.testng.log4testng.Logger; 51 * 52 * class ThisClass { 53 * private static final Logger LOGGER = Logger.getLogger(ThisClass.class); 54 * 55 * ... 56 * LOGGER.debug("entering myMethod()"); 57 * ... 58 * LOGGER.warn("unknown file: " + filename); 59 * ... 60 * LOGGER.error("Unexpected error", exception); 61 * </code></pre> 62 */ 63 public class Logger { 64 65 // Attribute an hierarchical integer value to all levels. 66 private static int i= 0; 67 private static final int TRACE= i++; 68 private static final int DEBUG= i++; 69 private static final int INFO= i++; 70 private static final int WARN= i++; 71 private static final int ERROR= i++; 72 private static final int FATAL= i++; 73 private static final int LEVEL_COUNT= i; 74 75 /** Standard prefix of all property names in log4testng.properties. */ 76 private static final String PREFIX= "log4testng."; 77 78 /** Standard prefix of all logger names in log4testng.properties. */ 79 private static final String LOGGER_PREFIX= PREFIX + "logger."; 80 81 /** Root logger name in log4testng.properties. */ 82 private static final String ROOT_LOGGER= PREFIX + "rootLogger"; 83 84 /** Debug property name in log4testng.properties. */ 85 private static final String DEBUG_PROPERTY= PREFIX + "debug"; 86 87 /** The standard error stream (this is allways System.err except for unit tests) */ 88 private static PrintStream err= System.err; 89 90 /** The standard output stream (this is allways System.out except for unit tests) */ 91 private static PrintStream out= System.out; 92 93 /** An ordered list of level names. */ 94 private static final String[] levelNames= new String[LEVEL_COUNT]; 95 96 static { 97 levelNames[TRACE]= "TRACE"; 98 levelNames[DEBUG]= "DEBUG"; 99 levelNames[INFO] = "INFO"; 100 levelNames[WARN] = "WARN"; 101 levelNames[ERROR] = "ERROR"; 102 levelNames[FATAL] = "FATAL"; 103 } 104 105 /** A map from level name to level integer index (TRACE->0, DEBUG->1 ...) */ 106 private static final Map<String, Integer> levelMap= Maps.newHashMap(); 107 108 static { 109 for(i= 0; i < LEVEL_COUNT; ++i) { 110 levelMap.put(levelNames[i], i); 111 } 112 } 113 114 /** true if the Logging system has been initialized. */ 115 private static boolean initialized; 116 117 /** Map from Logger names to level index (as specified in log4testng.properties) */ 118 private static final Map<String, Integer> loggerLevels = Maps.newHashMap(); 119 120 /** Map of all known loggers. */ 121 private static final Map<Class, Logger> loggers = Maps.newHashMap(); 122 123 /** The logging level of the root logger (defaults to warn). */ 124 private static int rootLoggerLevel= WARN; 125 126 /** Should log4testng log what it is doing (defaults to false). */ 127 private static boolean debug= false; 128 129 /** The logger's level */ 130 private final int level; 131 132 /** The logger's name. */ 133 private final Class klass; 134 private final String m_className; 135 136 /** 137 * Retrieve a logger named according to the value of the pClass.getName() 138 * parameter. If the named logger already exists, then the existing instance 139 * will be returned. Otherwise, a new instance is created. By default, loggers 140 * do not have a set level but inherit it from their nearest ancestor with 141 * a set level. 142 * 143 * @param pClass The class' logger to retrieve. 144 * @return a logger named according to the value of the pClass.getName(). 145 */ 146 public static synchronized Logger getLogger(Class pClass) { 147 initialize(); 148 Logger logger= loggers.get(pClass); 149 if(logger != null) { 150 return logger; 151 } 152 int level= getLevel(pClass); 153 logger= new Logger(pClass, level); 154 loggers.put(pClass, logger); 155 156 return logger; 157 } 158 159 /** 160 * Check whether this logger is enabled for the TRACE Level. 161 * @return true if this logger is enabled for level TRACE, false otherwise. 162 */ 163 public boolean isTraceEnabled() { 164 return isLevelEnabled(TRACE); 165 } 166 167 /** 168 * Log a message object with the TRACE level. This method first checks if this 169 * logger is TRACE enabled. If this logger is TRACE enabled, then it converts 170 * the message object (passed as parameter) to a string by invoking toString(). 171 * WARNING Note that passing a Throwable to this method will print the name of 172 * the Throwable but no stack trace. To print a stack trace use the 173 * trace(Object, Throwable) form instead. 174 * @param message the message object to log. 175 */ 176 public void trace(Object message) { 177 log(TRACE, message, null); 178 } 179 180 /** 181 * Log a message object with the TRACE level including the stack trace of the 182 * Throwable t passed as parameter. 183 * See Logger.trace(Object) form for more detailed information. 184 * @param message the message object to log. 185 * @param t the exception to log, including its stack trace. 186 */ 187 public void trace(Object message, Throwable t) { 188 log(TRACE, message, t); 189 } 190 191 /** 192 * Check whether this logger is enabled for the DEBUG Level. 193 * @return true if this logger is enabled for level DEBUG, false otherwise. 194 */ 195 public boolean isDebugEnabled() { 196 return isLevelEnabled(DEBUG); 197 } 198 199 /** 200 * Log a message object with the DEBUG level. 201 * See Logger.trace(Object) form for more detailed information. 202 * @param message the message object to log. 203 */ 204 public void debug(Object message) { 205 log(DEBUG, message, null); 206 } 207 208 /** 209 * Log a message object with the DEBUG level including the stack trace of the 210 * Throwable t passed as parameter. 211 * See Logger.trace(Object, Throwable) form for more detailed information. 212 * @param message the message object to log. 213 * @param t the exception to log, including its stack trace. 214 */ 215 public void debug(Object message, Throwable t) { 216 log(DEBUG, message, t); 217 } 218 219 /** 220 * Check whether this logger is enabled for the INFO Level. 221 * @return true if this logger is enabled for level INFO, false otherwise. 222 */ 223 public boolean isInfoEnabled() { 224 return isLevelEnabled(INFO); 225 } 226 227 /** 228 * Log a message object with the INFO level. 229 * See Logger.trace(Object) form for more detailed information. 230 * @param message the message object to log. 231 */ 232 public void info(Object message) { 233 log(INFO, message, null); 234 } 235 236 /** 237 * Log a message object with the WARN level including the stack trace of the 238 * Throwable t passed as parameter. 239 * See Logger.trace(Object, Throwable) form for more detailed information. 240 * @param message the message object to log. 241 * @param t the exception to log, including its stack trace. 242 */ 243 public void info(Object message, Throwable t) { 244 log(INFO, message, t); 245 } 246 247 /** 248 * Log a message object with the WARN level. 249 * See Logger.trace(Object) form for more detailed information. 250 * @param message the message object to log. 251 */ 252 public void warn(Object message) { 253 log(WARN, message, null); 254 } 255 256 /** 257 * Log a message object with the ERROR level including the stack trace of the 258 * Throwable t passed as parameter. 259 * See Logger.trace(Object, Throwable) form for more detailed information. 260 * @param message the message object to log. 261 * @param t the exception to log, including its stack trace. 262 */ 263 public void warn(Object message, Throwable t) { 264 log(WARN, message, t); 265 } 266 267 /** 268 * Log a message object with the ERROR level. 269 * See Logger.trace(Object) form for more detailed information. 270 * @param message the message object to log. 271 */ 272 public void error(Object message) { 273 log(ERROR, message, null); 274 } 275 276 /** 277 * Log a message object with the DEBUG level including the stack trace of the 278 * Throwable t passed as parameter. 279 * See Logger.trace(Object, Throwable) form for more detailed information. 280 * @param message the message object to log. 281 * @param t the exception to log, including its stack trace. 282 */ 283 public void error(Object message, Throwable t) { 284 log(ERROR, message, t); 285 } 286 287 /** 288 * Log a message object with the FATAL level. 289 * See Logger.trace(Object) form for more detailed information. 290 * @param message the message object to log. 291 */ 292 public void fatal(Object message) { 293 log(FATAL, message, null); 294 } 295 296 /** 297 * Log a message object with the FATAL level including the stack trace of the 298 * Throwable t passed as parameter. 299 * See Logger.trace(Object, Throwable) form for more detailed information. 300 * @param message the message object to log. 301 * @param t the exception to log, including its stack trace. 302 */ 303 public void fatal(Object message, Throwable t) { 304 log(FATAL, message, t); 305 } 306 307 private Logger(Class pClass, int pLevel) { 308 level= pLevel; 309 klass= pClass; 310 m_className= pClass.getName().substring(pClass.getName().lastIndexOf('.') + 1); 311 } 312 313 private static synchronized void initialize() { 314 if(initialized) { 315 return; 316 } 317 318 // We flag as initialized right away because if anything goes wrong 319 // We still consider it initialized. TODO Is this OK? 320 initialized= true; 321 322 InputStream is= Thread.currentThread().getContextClassLoader().getResourceAsStream("log4testng.properties"); 323 if(is == null) { 324 return; 325 } 326 Properties properties= new Properties(); 327 try { 328 properties.load(is); 329 } 330 catch(IOException e) { 331 throw new RuntimeException(e); 332 } 333 334 checkProperties(properties); 335 } 336 337 private static void checkProperties(Properties pProperties) { 338 { 339 // See if we want to debug log4testng 340 String debugStr= pProperties.getProperty(DEBUG_PROPERTY); 341 if(debugStr != null) { 342 if(debugStr.equalsIgnoreCase("true")) { 343 debug= true; 344 } 345 else if(debugStr.equalsIgnoreCase("false")) { 346 debug= false; 347 } 348 else { 349 throw new IllegalArgumentException("Unknown " + DEBUG_PROPERTY 350 + " value " + debugStr); 351 } 352 } 353 loglog4testng("log4testng.debug set to " + debug); 354 } 355 356 { 357 // Set the value of the root logger (if any). 358 String rootLevelStr= pProperties.getProperty(ROOT_LOGGER); 359 if(rootLevelStr != null) { 360 Integer ilevel= levelMap.get(rootLevelStr.toUpperCase()); 361 if(ilevel == null) { 362 throw new IllegalArgumentException("Unknown level for log4testng.rootLogger " 363 + rootLevelStr + " in log4testng.properties"); 364 } 365 rootLoggerLevel= ilevel; 366 loglog4testng("Root level logger set to " + rootLevelStr + " level."); 367 } 368 } 369 370 Iterator it= pProperties.entrySet().iterator(); 371 while(it.hasNext()) { 372 Map.Entry entry= (Entry) it.next(); 373 String logger= (String) entry.getKey(); 374 String level= (String) entry.getValue(); 375 376 if(!logger.startsWith(PREFIX)) { 377 throw new IllegalArgumentException("Illegal property value: " + logger); 378 } 379 if(logger.equals(DEBUG_PROPERTY)) { 380 // Already handled 381 } 382 else if(logger.equals(ROOT_LOGGER)) { 383 // Already handled 384 } 385 else { 386 if(!logger.startsWith(LOGGER_PREFIX)) { 387 throw new IllegalArgumentException("Illegal property value: " + logger); 388 } 389 390 Integer ilevel= levelMap.get(level.toUpperCase()); 391 if(ilevel == null) { 392 throw new IllegalArgumentException("Unknown level " + level + " for logger " + logger 393 + " in log4testng.properties"); 394 } 395 396 loggerLevels.put(logger.substring(LOGGER_PREFIX.length()), ilevel); 397 loglog4testng("logger " + logger + " set to " + ilevel + " level."); 398 } 399 } 400 } 401 402 /** 403 * Returns the level associated to the current class. The level is obtain by searching 404 * for a logger in the "testng-logging.properties" resource. For example, if class is 405 * "org.testng.TestNG" the the following loggers are searched in this order: 406 * <ol> 407 * <li>"org.testng.TestNG"</li> 408 * <li>"org.testng"</li> 409 * <li>"org"</li> 410 * <li>The root level</li> 411 * </ol> 412 * 413 * @param pClass the class name used for logger name. 414 * @return the level associated to the current class. 415 */ 416 private static int getLevel(Class pClass) { 417 String name= pClass.getName(); 418 loglog4testng("Getting level for logger " + name); 419 while(true) { 420 Integer level= loggerLevels.get(name); 421 if(level != null) { 422 loglog4testng("Found level " + level + " for logger " + name); 423 424 return level; 425 } 426 int dot= name.lastIndexOf('.'); 427 if(dot == -1) { 428 loglog4testng("Found level " + rootLoggerLevel + " for root logger"); 429 430 // Logger name not found. Defaults to root logger level. 431 return rootLoggerLevel; 432 } 433 name= name.substring(0, dot); 434 } 435 } 436 437 private boolean isLevelEnabled(int pLevel) { 438 return level <= pLevel; 439 } 440 441 private void log(int pLevel, Object pMessage, Throwable pT) { 442 if(isLevelEnabled(pLevel)) { 443 PrintStream ps= (pLevel >= ERROR) ? err : out; 444 if(null != pT) { 445 synchronized(ps) { 446 ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage); 447 pT.printStackTrace(ps); 448 } 449 } 450 else { 451 ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage); 452 } 453 } 454 } 455 456 /** 457 * Logs the message to System.out of debug is on. 458 * @param pmessage the message to log to the console 459 */ 460 private static void loglog4testng(String pmessage) { 461 if(debug) { 462 out.println("[log4testng] [debug] " + pmessage); 463 } 464 } 465 466 /** 467 * This method is for debugging purpose only. 468 * 469 * @param pProperties a properties bundle initialised as log4testng 470 * property file would be. 471 * @param pOut the standard output stream to be used for logging. 472 * @param pErr the standard error stream to be used for logging. 473 */ 474 private static synchronized void testInitialize(Properties pProperties, 475 PrintStream pOut, 476 PrintStream pErr) { 477 initialized= true; 478 loggers.clear(); 479 rootLoggerLevel= WARN; 480 debug= false; 481 out= pOut; 482 err= pErr; 483 checkProperties(pProperties); 484 } 485 486 /** 487 * Makes sure the default debug value is false. 488 */ 489 private static void testDebugDefault() { 490 Properties props= new Properties(); 491 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 492 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 493 PrintStream out2= new PrintStream(out1); 494 PrintStream err2= new PrintStream(err1); 495 props.put("log4testng.rootLogger", "WARN"); 496 testInitialize(props, out2, err2); 497 Assert.assertEquals(out1.toString(), ""); 498 Assert.assertEquals(err1.toString(), ""); 499 } 500 501 /** 502 * Makes sure the debug value can be turned on and actualls logs something. 503 */ 504 private static void testDebugOn() { 505 Properties props= new Properties(); 506 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 507 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 508 PrintStream out2= new PrintStream(out1); 509 PrintStream err2= new PrintStream(err1); 510 props.put("log4testng.debug", "true"); 511 props.put("log4testng.rootLogger", "WARN"); 512 testInitialize(props, out2, err2); 513 Assert.assertTrue(out1.toString().startsWith("[log4testng][debug]")); 514 Assert.assertEquals(err1.toString(), ""); 515 } 516 517 /** 518 * Makes sure the debug value can be turned off and logs nothing. 519 */ 520 private static void testDebugOff() { 521 Properties props= new Properties(); 522 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 523 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 524 PrintStream out2= new PrintStream(out1); 525 PrintStream err2= new PrintStream(err1); 526 props.put("log4testng.debug", "false"); 527 props.put("log4testng.rootLogger", "WARN"); 528 testInitialize(props, out2, err2); 529 Assert.assertEquals(out1.toString(), ""); 530 Assert.assertEquals(err1.toString(), ""); 531 } 532 533 /** 534 * Makes sure an illegal debug value throws an exception. 535 */ 536 private static void testDebugError() { 537 Properties props= new Properties(); 538 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 539 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 540 PrintStream out2= new PrintStream(out1); 541 PrintStream err2= new PrintStream(err1); 542 props.put("log4testng.debug", "unknown"); 543 props.put("log4testng.rootLogger", "WARN"); 544 try { 545 testInitialize(props, out2, err2); 546 throw new RuntimeException("failure"); 547 } 548 catch(IllegalArgumentException pEx) { 549 550 // Normal case 551 Assert.assertEquals(out1.toString(), ""); 552 Assert.assertEquals(err1.toString(), ""); 553 } 554 } 555 556 /** 557 * Tests that the root logger's default level is WARN and that loggers do not 558 * log bellow this level and do log in the correct stream for levels equal to 559 * and above WARN. 560 */ 561 private static void testRootLoggerDefault() { 562 Properties props= new Properties(); 563 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 564 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 565 PrintStream out2= new PrintStream(out1); 566 PrintStream err2= new PrintStream(err1); 567 testInitialize(props, out2, err2); 568 569 Logger strLogger= Logger.getLogger(String.class); 570 strLogger.trace("trace should not appear"); 571 Assert.assertEquals(out1.toString(), ""); 572 Assert.assertEquals(err1.toString(), ""); 573 strLogger.debug("debug should not appear"); 574 Assert.assertEquals(out1.toString(), ""); 575 Assert.assertEquals(err1.toString(), ""); 576 strLogger.info("info should not appear"); 577 Assert.assertEquals(out1.toString(), ""); 578 Assert.assertEquals(err1.toString(), ""); 579 strLogger.warn("warn should appear"); 580 int outlength= out1.toString().length(); 581 Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [WARN] warn should appear")); 582 Assert.assertEquals(err1.toString(), ""); 583 strLogger.error("error should appear"); 584 Assert.assertEquals(out1.toString().length(), outlength); 585 Assert.assertTrue(err1.toString().startsWith("[java.lang.String] [ERROR] error should appear")); 586 strLogger.fatal("fatal should appear"); 587 Assert.assertEquals(out1.toString().length(), outlength); 588 Assert.assertTrue(err1.toString().contains("[java.lang.String] [FATAL] fatal should appear")); 589 } 590 591 /** 592 * Test setting the root logger level 593 */ 594 private static void testRootLoggerSet() { 595 Properties props= new Properties(); 596 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 597 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 598 PrintStream out2= new PrintStream(out1); 599 PrintStream err2= new PrintStream(err1); 600 props.put("log4testng.rootLogger", "DEBUG"); 601 testInitialize(props, out2, err2); 602 603 Logger strLogger= Logger.getLogger(String.class); 604 strLogger.trace("trace should appear"); 605 Assert.assertEquals(out1.toString(), ""); 606 Assert.assertEquals(err1.toString(), ""); 607 strLogger.debug("debug should appear"); 608 Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear")); 609 Assert.assertEquals(err1.toString(), ""); 610 } 611 612 /** 613 * Test setting the root logger to an illegal level value throws an exception. 614 */ 615 private static void testRootLoggerSetError() { 616 Properties props= new Properties(); 617 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 618 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 619 PrintStream out2= new PrintStream(out1); 620 PrintStream err2= new PrintStream(err1); 621 props.put("log4testng.rootLogger", "unknown"); 622 try { 623 testInitialize(props, out2, err2); 624 throw new RuntimeException("failure"); 625 } 626 catch(IllegalArgumentException pEx) { 627 628 // Normal case 629 Assert.assertEquals(out1.toString(), ""); 630 Assert.assertEquals(err1.toString(), ""); 631 } 632 } 633 634 /** 635 * Test setting a user logger level 636 */ 637 private static void testUserLoggerSet() { 638 Properties props= new Properties(); 639 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 640 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 641 PrintStream out2= new PrintStream(out1); 642 PrintStream err2= new PrintStream(err1); 643 props.put("log4testng.logger.java.lang.String", "DEBUG"); 644 testInitialize(props, out2, err2); 645 646 Logger strLogger= Logger.getLogger(String.class); 647 strLogger.trace("trace should not appear"); 648 Assert.assertEquals(out1.toString(), ""); 649 Assert.assertEquals(err1.toString(), ""); 650 strLogger.debug("debug should appear"); 651 int outLength= out1.toString().length(); 652 Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear")); 653 Assert.assertEquals(err1.toString(), ""); 654 655 Logger classLogger= Logger.getLogger(Class.class); 656 classLogger.debug("debug should not appear"); 657 Assert.assertEquals(out1.toString().length(), outLength); 658 Assert.assertEquals(err1.toString(), ""); 659 classLogger.warn("warn should appear"); 660 Assert.assertTrue(out1.toString().contains("[java.lang.Class] [WARN] warn should appear")); 661 Assert.assertEquals(err1.toString(), ""); 662 } 663 664 /** 665 * Test setting a user logger to an illegal level value throws an exception 666 */ 667 private static void testUserLoggerSetError() { 668 Properties props= new Properties(); 669 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 670 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 671 PrintStream out2= new PrintStream(out1); 672 PrintStream err2= new PrintStream(err1); 673 props.put("log4testng.logger.java.lang.String", "unknown"); 674 try { 675 testInitialize(props, out2, err2); 676 throw new RuntimeException("failure"); 677 } 678 catch(IllegalArgumentException pEx) { 679 680 // Normal case 681 Assert.assertEquals(out1.toString(), ""); 682 Assert.assertEquals(err1.toString(), ""); 683 } 684 } 685 686 /** 687 * Tests setting a partial logger name (a hierarchy scope) 688 */ 689 private static void testUserLoggerSetHierarchy() { 690 Properties props= new Properties(); 691 ByteArrayOutputStream out1= new ByteArrayOutputStream(); 692 ByteArrayOutputStream err1= new ByteArrayOutputStream(); 693 PrintStream out2= new PrintStream(out1); 694 PrintStream err2= new PrintStream(err1); 695 props.put("log4testng.logger.java.lang", "DEBUG"); 696 testInitialize(props, out2, err2); 697 698 Logger strLogger= Logger.getLogger(String.class); 699 strLogger.trace("trace should not appear"); 700 Assert.assertEquals(out1.toString(), ""); 701 Assert.assertEquals(err1.toString(), ""); 702 strLogger.debug("debug should appear"); 703 Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear")); 704 Assert.assertEquals(err1.toString(), ""); 705 } 706 707 /** 708 * Run all tests. (very crusty ...) 709 * @param pArgs not used 710 */ 711 public static void main(String[] pArgs) { 712 testDebugDefault(); 713 testDebugOn(); 714 testDebugOff(); 715 testDebugError(); 716 testRootLoggerDefault(); 717 testRootLoggerSet(); 718 testRootLoggerSetError(); 719 testUserLoggerSet(); 720 testUserLoggerSetError(); 721 testUserLoggerSetHierarchy(); 722 } 723 } 724