001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.classic.joran; 015 016import static org.junit.Assert.assertEquals; 017import static org.junit.Assert.assertFalse; 018import static org.junit.Assert.assertNotNull; 019import static org.junit.Assert.assertNull; 020import static org.junit.Assert.assertTrue; 021 022import java.io.IOException; 023import java.text.SimpleDateFormat; 024import java.util.Date; 025 026import org.junit.Ignore; 027import org.junit.Test; 028import org.slf4j.MDC; 029 030import ch.qos.logback.classic.ClassicTestConstants; 031import ch.qos.logback.classic.Level; 032import ch.qos.logback.classic.Logger; 033import ch.qos.logback.classic.LoggerContext; 034import ch.qos.logback.classic.jul.JULHelper; 035import ch.qos.logback.classic.spi.ILoggingEvent; 036import ch.qos.logback.classic.turbo.DebugUsersTurboFilter; 037import ch.qos.logback.classic.turbo.NOPTurboFilter; 038import ch.qos.logback.classic.turbo.TurboFilter; 039import ch.qos.logback.core.ConsoleAppender; 040import ch.qos.logback.core.CoreConstants; 041import ch.qos.logback.core.encoder.LayoutWrappingEncoder; 042import ch.qos.logback.core.joran.spi.JoranException; 043import ch.qos.logback.core.pattern.parser.Parser; 044import ch.qos.logback.core.read.ListAppender; 045import ch.qos.logback.core.spi.ScanException; 046import ch.qos.logback.core.status.Status; 047import ch.qos.logback.core.testUtil.RandomUtil; 048import ch.qos.logback.core.testUtil.StatusChecker; 049import ch.qos.logback.core.testUtil.StringListAppender; 050import ch.qos.logback.core.util.CachingDateFormatter; 051 052public class JoranConfiguratorTest { 053 054 LoggerContext loggerContext = new LoggerContext(); 055 Logger logger = loggerContext.getLogger(this.getClass().getName()); 056 Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); 057 StatusChecker checker = new StatusChecker(loggerContext); 058 int diff = RandomUtil.getPositiveInt(); 059 060 void configure(String file) throws JoranException { 061 JoranConfigurator jc = new JoranConfigurator(); 062 jc.setContext(loggerContext); 063 loggerContext.putProperty("diff", "" + diff); 064 jc.doConfigure(file); 065 } 066 067 @Test 068 public void simpleList() throws JoranException { 069 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleList.xml"); 070 071 Logger logger = loggerContext.getLogger(this.getClass().getName()); 072 Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); 073 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 074 assertEquals(0, listAppender.list.size()); 075 String msg = "hello world"; 076 logger.debug(msg); 077 assertEquals(1, listAppender.list.size()); 078 ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0); 079 assertEquals(msg, le.getMessage()); 080 } 081 082 @Test 083 public void level() throws JoranException { 084 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "simpleLevel.xml"); 085 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 086 assertEquals(0, listAppender.list.size()); 087 String msg = "hello world"; 088 logger.debug(msg); 089 assertEquals(0, listAppender.list.size()); 090 } 091 092 @Test 093 public void additivity() throws JoranException { 094 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "additivity.xml"); 095 Logger logger = loggerContext.getLogger("additivityTest"); 096 assertFalse(logger.isAdditive()); 097 } 098 099 @Test 100 public void rootLoggerLevelSettingBySystemProperty() throws JoranException { 101 String propertyName = "logback.level"; 102 103 System.setProperty(propertyName, "INFO"); 104 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "rootLevelByProperty.xml"); 105 // StatusPrinter.print(loggerContext); 106 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 107 assertEquals(0, listAppender.list.size()); 108 String msg = "hello world"; 109 logger.debug(msg); 110 assertEquals(0, listAppender.list.size()); 111 System.clearProperty(propertyName); 112 } 113 114 @Test 115 public void loggerLevelSettingBySystemProperty() throws JoranException { 116 String propertyName = "logback.level"; 117 System.setProperty(propertyName, "DEBUG"); 118 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "loggerLevelByProperty.xml"); 119 // StatusPrinter.print(loggerContext); 120 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 121 assertEquals(0, listAppender.list.size()); 122 String msg = "hello world"; 123 logger.debug(msg); 124 assertEquals(1, listAppender.list.size()); 125 System.clearProperty(propertyName); 126 } 127 128 @Test 129 public void appenderRefSettingBySystemProperty() throws JoranException { 130 final String propertyName = "logback.appenderRef"; 131 System.setProperty(propertyName, "A"); 132 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "appenderRefByProperty.xml"); 133 final Logger logger = loggerContext.getLogger("ch.qos.logback.classic.joran"); 134 final ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) logger.getAppender("A"); 135 assertEquals(0, listAppender.list.size()); 136 final String msg = "hello world"; 137 logger.info(msg); 138 assertEquals(1, listAppender.list.size()); 139 System.clearProperty(propertyName); 140 } 141 142 @Test 143 public void statusListener() throws JoranException { 144 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "statusListener.xml"); 145 } 146 147 @Test 148 public void contextRename() throws JoranException { 149 loggerContext.setName(CoreConstants.DEFAULT_CONTEXT_NAME); 150 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "contextRename.xml"); 151 assertEquals("wombat", loggerContext.getName()); 152 } 153 154 @Test 155 public void eval() throws JoranException { 156 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "callerData.xml"); 157 158 String msg = "hello world"; 159 logger.debug("toto"); 160 logger.debug(msg); 161 162 StringListAppender<ILoggingEvent> slAppender = (StringListAppender<ILoggingEvent>) loggerContext.getLogger("root").getAppender("STR_LIST"); 163 assertNotNull(slAppender); 164 assertEquals(2, slAppender.strList.size()); 165 assertTrue(slAppender.strList.get(0).contains(" DEBUG - toto")); 166 167 String str1 = slAppender.strList.get(1); 168 assertTrue(str1.contains("Caller+0")); 169 assertTrue(str1.contains(" DEBUG - hello world")); 170 } 171 172 @Test 173 public void turboFilter() throws JoranException { 174 // Although this test uses turbo filters, it only checks 175 // that Joran can see the xml element and create 176 // and place the relevant object correctly. 177 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turbo.xml"); 178 179 TurboFilter filter = loggerContext.getTurboFilterList().get(0); 180 assertTrue(filter instanceof NOPTurboFilter); 181 } 182 183 @Test 184 public void testTurboFilterWithStringList() throws JoranException { 185 // Although this test uses turbo filters, it only checks 186 // that Joran can see <user> elements, and behave correctly 187 // that is call the addUser method and pass the correct values 188 // to that method. 189 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turbo2.xml"); 190 191 // StatusPrinter.print(loggerContext.getStatusManager()); 192 193 TurboFilter filter = loggerContext.getTurboFilterList().get(0); 194 assertTrue(filter instanceof DebugUsersTurboFilter); 195 DebugUsersTurboFilter dutf = (DebugUsersTurboFilter) filter; 196 assertEquals(2, dutf.getUsers().size()); 197 } 198 199 @Test 200 public void testLevelFilter() throws JoranException { 201 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "levelFilter.xml"); 202 203 // StatusPrinter.print(loggerContext); 204 205 logger.warn("hello"); 206 logger.error("to be ignored"); 207 208 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 209 210 assertNotNull(listAppender); 211 assertEquals(1, listAppender.list.size()); 212 ILoggingEvent back = listAppender.list.get(0); 213 assertEquals(Level.WARN, back.getLevel()); 214 assertEquals("hello", back.getMessage()); 215 } 216 217 @Test 218 public void testEvaluatorFilter() throws JoranException { 219 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "evaluatorFilter.xml"); 220 221 // StatusPrinter.print(loggerContext); 222 223 logger.warn("hello"); 224 logger.error("to be ignored"); 225 226 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 227 228 assertNotNull(listAppender); 229 assertEquals(1, listAppender.list.size()); 230 ILoggingEvent back = listAppender.list.get(0); 231 assertEquals(Level.WARN, back.getLevel()); 232 assertEquals("hello", back.getMessage()); 233 } 234 235 @Test 236 public void testTurboDynamicThreshold() throws JoranException { 237 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold.xml"); 238 239 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 240 assertEquals(0, listAppender.list.size()); 241 242 // this one should be denied 243 MDC.put("userId", "user1"); 244 logger.debug("hello user1"); 245 // this one should log 246 MDC.put("userId", "user2"); 247 logger.debug("hello user2"); 248 249 assertEquals(1, listAppender.list.size()); 250 ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0); 251 assertEquals("hello user2", le.getMessage()); 252 } 253 254 @Test 255 public void testTurboDynamicThreshold2() throws JoranException { 256 configure(ClassicTestConstants.JORAN_INPUT_PREFIX + "turboDynamicThreshold2.xml"); 257 258 ListAppender<ILoggingEvent> listAppender = (ListAppender<ILoggingEvent>) root.getAppender("LIST"); 259 assertEquals(0, listAppender.list.size()); 260 261 // this one should log 262 MDC.put("userId", "user1"); 263 logger.debug("hello user1"); 264 // this one should log 265 MDC.put("userId", "user2"); 266 logger.debug("hello user2"); 267 // this one should fail 268 MDC.put("userId", "user3"); 269 logger.debug("hello user3"); 270 271 assertEquals(2, listAppender.list.size()); 272 ILoggingEvent le = (ILoggingEvent) listAppender.list.get(0); 273 assertEquals("hello user1", le.getMessage()); 274 le = (ILoggingEvent) listAppender.list.get(1); 275 assertEquals("hello user2", le.getMessage()); 276 } 277 278 @Test 279 public void timestamp() throws JoranException, IOException, InterruptedException { 280 281 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "timestamp-context.xml"; 282 configure(configFileAsStr); 283 284 String r = loggerContext.getProperty("testTimestamp"); 285 assertNotNull(r); 286 CachingDateFormatter sdf = new CachingDateFormatter("yyyy-MM"); 287 String expected = sdf.format(System.currentTimeMillis()); 288 assertEquals("expected \"" + expected + "\" but got " + r, expected, r); 289 } 290 291 @Test 292 public void timestampLocal() throws JoranException, IOException, InterruptedException { 293 294 String sysProp = "ch.qos.logback.classic.joran.JoranConfiguratorTest.timestampLocal"; 295 System.setProperty(sysProp, ""); 296 297 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "timestamp-local.xml"; 298 configure(configFileAsStr); 299 300 // It's hard to test the local variable has been set, as it's not 301 // visible from here. But instead we test that it's not set in the 302 // context. And check that a system property has been replaced with the 303 // contents of the local variable 304 305 String r = loggerContext.getProperty("testTimestamp"); 306 assertNull(r); 307 308 String expected = "today is " + new SimpleDateFormat("yyyy-MM").format(new Date()); 309 String sysPropValue = System.getProperty(sysProp); 310 assertEquals(expected, sysPropValue); 311 } 312 313 @Test 314 public void encoderCharset() throws JoranException, IOException, InterruptedException { 315 316 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "encoderCharset.xml"; 317 configure(configFileAsStr); 318 319 ConsoleAppender<ILoggingEvent> consoleAppender = (ConsoleAppender<ILoggingEvent>) root.getAppender("CONSOLE"); 320 assertNotNull(consoleAppender); 321 LayoutWrappingEncoder<ILoggingEvent> encoder = (LayoutWrappingEncoder<ILoggingEvent>) consoleAppender.getEncoder(); 322 323 assertEquals("UTF-8", encoder.getCharset().displayName()); 324 325 StatusChecker checker = new StatusChecker(loggerContext); 326 checker.assertIsErrorFree(); 327 } 328 329 void verifyJULLevel(String loggerName, Level expectedLevel) { 330 java.util.logging.Logger julLogger = JULHelper.asJULLogger(loggerName); 331 java.util.logging.Level julLevel = julLogger.getLevel(); 332 333 if (expectedLevel == null) { 334 assertNull(julLevel); 335 } else { 336 assertEquals(JULHelper.asJULLevel(expectedLevel), julLevel); 337 } 338 339 } 340 341 @Test 342 public void levelChangePropagator0() throws JoranException, IOException, InterruptedException { 343 String loggerName = "changePropagator0" + diff; 344 java.util.logging.Logger.getLogger(loggerName).setLevel(java.util.logging.Level.INFO); 345 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "/jul/levelChangePropagator0.xml"; 346 configure(configFileAsStr); 347 StatusChecker checker = new StatusChecker(loggerContext); 348 checker.assertIsErrorFree(); 349 verifyJULLevel(loggerName, null); 350 verifyJULLevel("a.b.c." + diff, Level.WARN); 351 verifyJULLevel(Logger.ROOT_LOGGER_NAME, Level.TRACE); 352 } 353 354 @Test 355 public void levelChangePropagator1() throws JoranException, IOException, InterruptedException { 356 String loggerName = "changePropagator1" + diff; 357 java.util.logging.Logger logger1 = java.util.logging.Logger.getLogger(loggerName); 358 logger1.setLevel(java.util.logging.Level.INFO); 359 verifyJULLevel(loggerName, Level.INFO); 360 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "/jul/levelChangePropagator1.xml"; 361 configure(configFileAsStr); 362 StatusChecker checker = new StatusChecker(loggerContext); 363 checker.assertIsErrorFree(); 364 verifyJULLevel(loggerName, Level.INFO); // 365 verifyJULLevel("a.b.c." + diff, Level.WARN); 366 verifyJULLevel(Logger.ROOT_LOGGER_NAME, Level.TRACE); 367 } 368 369 @Test 370 @Ignore 371 public void onConsoleRetro() throws JoranException, IOException, InterruptedException { 372 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "/onConsoleRetro.xml"; 373 configure(configFileAsStr); 374 System.out.println("xxxxxxxxxxxxx"); 375 Thread.sleep(400); 376 377 loggerContext.reset(); 378 configure(configFileAsStr); 379 } 380 381 @Test 382 public void lbcore193() throws JoranException { 383 String configFileAsStr = ClassicTestConstants.ISSUES_PREFIX + "lbcore193.xml"; 384 configure(configFileAsStr); 385 checker.asssertContainsException(ScanException.class); 386 checker.assertContainsMatch(Status.ERROR, "Expecting RIGHT_PARENTHESIS token but got null"); 387 checker.assertContainsMatch(Status.ERROR, "See also " + Parser.MISSING_RIGHT_PARENTHESIS); 388 } 389 390 @Test 391 public void properties() throws JoranException { 392 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "properties.xml"; 393 assertNull(System.getProperty("sys")); 394 395 configure(configFileAsStr); 396 assertNotNull(loggerContext.getProperty(CoreConstants.HOSTNAME_KEY)); 397 assertNull(loggerContext.getProperty("transientKey1")); 398 assertNull(loggerContext.getProperty("transientKey2")); 399 assertEquals("node0", loggerContext.getProperty("nodeId")); 400 assertEquals("tem", System.getProperty("sys")); 401 assertNotNull(loggerContext.getProperty("path")); 402 checker.assertIsErrorFree(); 403 } 404 405 @Test 406 public void hostnameProperty() throws JoranException { 407 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "hostnameProperty.xml"; 408 configure(configFileAsStr); 409 assertEquals("A", loggerContext.getProperty(CoreConstants.HOSTNAME_KEY)); 410 } 411 412 // see also http://jira.qos.ch/browse/LBCORE-254 413 @Test 414 public void sysProps() throws JoranException { 415 System.setProperty("k.lbcore254", ClassicTestConstants.ISSUES_PREFIX + "lbcore254"); 416 JoranConfigurator configurator = new JoranConfigurator(); 417 configurator.setContext(loggerContext); 418 configurator.doConfigure(ClassicTestConstants.ISSUES_PREFIX + "lbcore254.xml"); 419 420 checker.assertIsErrorFree(); 421 } 422 423 @Test 424 public void packageDataDisabledByConfigAttribute() throws JoranException { 425 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "packagingDataDisabled.xml"; 426 configure(configFileAsStr); 427 assertFalse(loggerContext.isPackagingDataEnabled()); 428 } 429 430 @Test 431 public void packageDataEnabledByConfigAttribute() throws JoranException { 432 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "packagingDataEnabled.xml"; 433 configure(configFileAsStr); 434 assertTrue(loggerContext.isPackagingDataEnabled()); 435 } 436 437 @Test 438 public void valueOfConvention() throws JoranException { 439 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "valueOfConvention.xml"; 440 configure(configFileAsStr); 441 checker.assertIsWarningOrErrorFree(); 442 } 443 444 @Test 445 public void shutdownHookTest() throws JoranException { 446 String configFileAsStr = ClassicTestConstants.JORAN_INPUT_PREFIX + "issues/logback_1162.xml"; 447 loggerContext.putProperty("output_dir", ClassicTestConstants.OUTPUT_DIR_PREFIX+"logback_issue_1162/"); 448 configure(configFileAsStr); 449 assertNotNull(loggerContext.getObject(CoreConstants.SHUTDOWN_HOOK_THREAD)); 450 } 451 452}