1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002, 2014 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 8 package com.sleepycat.je.utilint; 9 10 import static org.junit.Assert.assertEquals; 11 import static org.junit.Assert.assertFalse; 12 import static org.junit.Assert.assertNull; 13 import static org.junit.Assert.assertTrue; 14 15 import java.io.BufferedReader; 16 import java.io.BufferedWriter; 17 import java.io.File; 18 import java.io.FileReader; 19 import java.io.FileWriter; 20 import java.io.PrintWriter; 21 import java.util.ArrayList; 22 import java.util.Enumeration; 23 import java.util.List; 24 import java.util.logging.Handler; 25 import java.util.logging.Level; 26 import java.util.logging.LogManager; 27 import java.util.logging.LogRecord; 28 import java.util.logging.Logger; 29 30 import org.junit.Test; 31 32 import com.sleepycat.je.DatabaseException; 33 import com.sleepycat.je.DbInternal; 34 import com.sleepycat.je.Environment; 35 import com.sleepycat.je.EnvironmentConfig; 36 import com.sleepycat.je.EnvironmentMutableConfig; 37 import com.sleepycat.je.dbi.EnvironmentImpl; 38 import com.sleepycat.je.junit.JUnitProcessThread; 39 import com.sleepycat.je.util.TestUtils; 40 import com.sleepycat.util.test.SharedTestUtils; 41 import com.sleepycat.util.test.TestBase; 42 43 /** 44 * A unit test for testing JE logging programatically. 45 */ 46 public class LoggerUtilsTest extends TestBase { 47 48 /** 49 * If a logging config file is specified, this test cannot expect the 50 * logging properties to have default settings. 51 */ 52 private static final boolean DEFAULT_LOGGING_PROPERTIES = 53 System.getProperty("java.util.logging.config.file", "").equals(""); 54 55 private final File envHome; 56 private static final String loggerPrefix = "com.sleepycat.je."; 57 /* Logging configure properties file name. */ 58 private static final String fileName = "logging.properties"; 59 /* Logging settings in the properties file. */ 60 private static final String consoleLevel = 61 "com.sleepycat.je.util.ConsoleHandler.level=INFO"; 62 private static final String fileLevel = 63 "com.sleepycat.je.util.FileHandler.level=WARNING"; 64 LoggerUtilsTest()65 public LoggerUtilsTest() { 66 envHome = SharedTestUtils.getTestDir(); 67 } 68 69 /* 70 * Remove the named files from the environment directory. 71 */ removeFiles(File envDir, String name)72 private void removeFiles(File envDir, String name) { 73 File[] files = envDir.listFiles(); 74 for (File file : files) { 75 if (file.getName().contains(name)) { 76 assertTrue("couldn't delete " + name + "for " + envDir, 77 file.delete()); 78 } 79 } 80 } 81 82 /* 83 * Test whether a JE logger's level can be set programmatically. 84 */ 85 @Test testLoggerLevelsRWEnv()86 public void testLoggerLevelsRWEnv() 87 throws Exception { 88 89 changeLoggerLevels(false /* readOnly */); 90 } 91 92 /* 93 * Test whether a JE logger's level can be set programmatically, and that 94 * logging works in a read only environment. 95 */ 96 @Test testLoggerLevelsROEnv()97 public void testLoggerLevelsROEnv() 98 throws Exception { 99 100 changeLoggerLevels(true /* readOnly */); 101 } 102 changeLoggerLevels(boolean readOnlyEnv)103 private void changeLoggerLevels(boolean readOnlyEnv) 104 throws Exception { 105 106 /* 107 * Set the parent's level to OFF, so all logging messages shouldn't be 108 * written to je.info files. 109 */ 110 Logger parent = Logger.getLogger("com.sleepycat.je"); 111 parent.setLevel(Level.OFF); 112 113 EnvironmentConfig envConfig = new EnvironmentConfig(); 114 envConfig.setAllowCreate(true); 115 envConfig.setConfigParam(EnvironmentConfig.FILE_LOGGING_LEVEL, "ALL"); 116 envConfig.setReadOnly(readOnlyEnv); 117 Environment env = new Environment(envHome, envConfig); 118 119 /* Init a test messages list. */ 120 ArrayList<String> messages = new ArrayList<String>(); 121 messages.add("Hello, Linda!"); 122 messages.add("Hello, Sam!"); 123 messages.add("Hello, Charlie!"); 124 messages.add("Hello, Mark!"); 125 messages.add("Hello, Tao!"); 126 messages.add("Hello, Eric!"); 127 128 /* Check the logger level before reset. */ 129 checkLoggerLevel(); 130 131 /* Log the test messages. */ 132 logMsg(DbInternal.getEnvironmentImpl(env), messages); 133 134 /* 135 * The loggers were turned off with a level setting of OFF, so there is 136 * should be nothing in the je.info files. 137 */ 138 ArrayList<String> readMsgs = readFromInfoFile(readOnlyEnv); 139 assertTrue(readMsgs.size() == 0); 140 141 /* 142 * Reset the parent level to ALL, so that all logging messages should 143 * be logged. 144 */ 145 parent.setLevel(Level.ALL); 146 147 /* Log the test messages. */ 148 logMsg(DbInternal.getEnvironmentImpl(env), messages); 149 150 /* Check that each test message is in the je.info.0 file. */ 151 readMsgs = readFromInfoFile(readOnlyEnv); 152 153 /* 154 * Since JE logger's level has been set to ALL, additional JE logging 155 * messages from normal operations may also be written to je.info 156 * files. We should check that the actual messages in je.info should be 157 * equal to or larger than the size we directly log. 158 */ 159 if (readOnlyEnv) { 160 /* Read only Environment won't log anything to JE FileHandler. */ 161 assertTrue(readMsgs.size() == 0); 162 } else { 163 164 /* 165 * Since JE logger's level has been set to ALL, additional JE 166 * logging messages from normal operations may also be written to 167 * je.info files. We should check that the actual messages in 168 * je.info files should be equal to or larger than the size we 169 * directly log. 170 */ 171 assertTrue(readMsgs.size() >= messages.size()); 172 for (int i = 0; i < messages.size(); i++) { 173 boolean contained = false; 174 for (int j = 0; j < readMsgs.size(); j++) { 175 if (readMsgs.get(j).contains(messages.get(i))) { 176 contained = true; 177 break; 178 } 179 } 180 assertTrue(contained); 181 } 182 } 183 184 /* Check to see that all JE loggers' level are not changed. */ 185 checkLoggerLevel(); 186 187 env.close(); 188 } 189 190 /* Check the level for all JE loggers. */ checkLoggerLevel()191 private void checkLoggerLevel() { 192 Enumeration<String> loggerNames = 193 LogManager.getLogManager().getLoggerNames(); 194 while (loggerNames.hasMoreElements()) { 195 String loggerName = loggerNames.nextElement(); 196 if (loggerName.startsWith(loggerPrefix)) { 197 Logger logger = Logger.getLogger(loggerName); 198 assertNull(logger.getLevel()); 199 } 200 } 201 } 202 203 /* Log some messages. */ logMsg(EnvironmentImpl envImpl, ArrayList<String> messages)204 private void logMsg(EnvironmentImpl envImpl, ArrayList<String> messages) { 205 Logger envLogger = envImpl.getLogger(); 206 for (String message : messages) { 207 LoggerUtils.info(envLogger, envImpl, message); 208 } 209 } 210 211 /* Read the contents in the je.info files. */ readFromInfoFile(boolean readOnlyEnv)212 private ArrayList<String> readFromInfoFile(boolean readOnlyEnv) 213 throws Exception { 214 215 /* Get the file for je.info.0. */ 216 File[] files = envHome.listFiles(); 217 File infoFile = null; 218 for (File file : files) { 219 if (("je.info.0").equals(file.getName())) { 220 infoFile = file; 221 break; 222 } 223 } 224 225 /* Make sure the file exists. */ 226 ArrayList<String> messages = new ArrayList<String>(); 227 if (readOnlyEnv) { 228 return messages; 229 } 230 231 assertTrue(infoFile != null); 232 233 /* Read the messages from the file. */ 234 BufferedReader in = new BufferedReader(new FileReader(infoFile)); 235 String message = new String(); 236 while ((message = in.readLine()) != null) { 237 messages.add(message); 238 } 239 in.close(); 240 241 return messages; 242 } 243 244 /* 245 * Test FileHandler and ConsoleHandler level setting. 246 */ 247 @Test testHandlerLevels()248 public void testHandlerLevels() 249 throws Exception { 250 251 EnvironmentConfig envConfig = new EnvironmentConfig(); 252 envConfig.setAllowCreate(true); 253 Environment env = new Environment(envHome, envConfig); 254 255 /* Check the initial handler level settings. */ 256 EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 257 Level consoleHandlerLevel = envImpl.getConsoleHandler().getLevel(); 258 Level fileHandlerLevel = envImpl.getFileHandler().getLevel(); 259 if (DEFAULT_LOGGING_PROPERTIES) { 260 assertEquals(Level.OFF, consoleHandlerLevel); 261 assertEquals(Level.INFO, fileHandlerLevel); 262 } 263 264 env.close(); 265 266 /* Reopen the Environment with params setting. */ 267 envConfig.setConfigParam(EnvironmentConfig.CONSOLE_LOGGING_LEVEL, 268 "WARNING"); 269 envConfig.setConfigParam(EnvironmentConfig.FILE_LOGGING_LEVEL, 270 "SEVERE"); 271 env = new Environment(envHome, envConfig); 272 envImpl = DbInternal.getEnvironmentImpl(env); 273 Level newConsoleHandlerLevel = envImpl.getConsoleHandler().getLevel(); 274 Level newFileHandlerLevel = envImpl.getFileHandler().getLevel(); 275 /* Check that the new level are the same as param setting. */ 276 assertEquals(Level.WARNING, newConsoleHandlerLevel); 277 assertEquals(Level.SEVERE, newFileHandlerLevel); 278 279 /* Make sure the levels are different before and after param setting. */ 280 if (DEFAULT_LOGGING_PROPERTIES) { 281 assertFalse(consoleHandlerLevel.equals(newConsoleHandlerLevel)); 282 assertFalse(fileHandlerLevel.equals(newFileHandlerLevel)); 283 } 284 285 env.close(); 286 } 287 288 /* 289 * Test whether the configurations inside the properties file are set 290 * correctly in JE Environment. 291 */ 292 @Test testPropertiesSetting()293 public void testPropertiesSetting() 294 throws Exception { 295 296 invokeProcess(false); 297 } 298 299 /** 300 * Start the process and check the exit value. 301 * 302 * @param bothSetting presents whether the logging configuration and JE 303 * params are both set on a same Environment. 304 */ invokeProcess(boolean bothSetting)305 private void invokeProcess(boolean bothSetting) 306 throws Exception { 307 308 /* Create a property file and write configurations into the file. */ 309 String propertiesFile = createPropertiesFile(); 310 311 /* 312 * If bothSetting is true, which means we need to set JE params, so 313 * obviously we need to add another two arguments. 314 */ 315 String[] envCommand = bothSetting ? new String[8] : new String[6]; 316 envCommand[0] = "-Djava.util.logging.config.file=" + propertiesFile; 317 envCommand[1] = "com.sleepycat.je.utilint.LoggerUtilsTest$" + 318 "PropertiesSettingProcess"; 319 envCommand[2] = envHome.getAbsolutePath(); 320 envCommand[3] = "INFO"; 321 envCommand[4] = "WARNING"; 322 envCommand[5] = bothSetting ? "true" : "false"; 323 /* JE Param setting. */ 324 if (bothSetting) { 325 envCommand[6] = "WARNING"; 326 envCommand[7] = "SEVERE"; 327 } 328 329 /* Start a process. */ 330 JUnitProcessThread thread = 331 new JUnitProcessThread("PropertiesSettingProcess", envCommand); 332 thread.start(); 333 334 try { 335 thread.finishTest(); 336 } catch (Throwable t) { 337 System.err.println(t.toString()); 338 } 339 340 /* We expect that the process exited normally. */ 341 assertEquals(0, thread.getExitVal()); 342 343 /* Remove the created property file. */ 344 removeFiles(envHome, fileName); 345 } 346 347 /* Create a properties file for use. */ createPropertiesFile()348 private String createPropertiesFile() 349 throws Exception { 350 351 String name = envHome.getAbsolutePath() + 352 System.getProperty("file.separator") + fileName; 353 File file = new File(name); 354 PrintWriter out = 355 new PrintWriter(new BufferedWriter(new FileWriter(file))); 356 out.println(consoleLevel); 357 out.println(fileLevel); 358 out.close(); 359 360 return name; 361 } 362 363 /* 364 * Test that JE ConsoleHandler and FileHandler get the correct level when 365 * their levels are set both by the java.util.logging properties file and 366 * JE params. 367 * 368 * We want JE params to override the levels set by the standard 369 * properties file. 370 */ 371 @Test testPropertiesAndParamSetting()372 public void testPropertiesAndParamSetting() 373 throws Exception { 374 375 invokeProcess(true); 376 } 377 378 /* 379 * Test that handler levels are mutable. 380 */ 381 @Test testMutableConfig()382 public void testMutableConfig() 383 throws Exception { 384 385 EnvironmentConfig envConfig = new EnvironmentConfig(); 386 envConfig.setAllowCreate(true); 387 envConfig.setConfigParam(EnvironmentConfig.CONSOLE_LOGGING_LEVEL, 388 "WARNING"); 389 envConfig.setConfigParam(EnvironmentConfig.FILE_LOGGING_LEVEL, 390 "SEVERE"); 391 Environment env = new Environment(envHome, envConfig); 392 393 /* Check the init handlers' level setting. */ 394 EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 395 Level consoleHandlerLevel = envImpl.getConsoleHandler().getLevel(); 396 Level fileHandlerLevel = envImpl.getFileHandler().getLevel(); 397 assertEquals(Level.WARNING, consoleHandlerLevel); 398 assertEquals(Level.SEVERE, fileHandlerLevel); 399 400 /* Change the handler param setting for an open Environment. */ 401 EnvironmentMutableConfig mutableConfig = env.getMutableConfig(); 402 mutableConfig.setConfigParam(EnvironmentConfig.CONSOLE_LOGGING_LEVEL, 403 "SEVERE"); 404 mutableConfig.setConfigParam(EnvironmentConfig.FILE_LOGGING_LEVEL, 405 "WARNING"); 406 env.setMutableConfig(mutableConfig); 407 408 /* Check the handler's level has changed. */ 409 Level newConsoleHandlerLevel = envImpl.getConsoleHandler().getLevel(); 410 Level newFileHandlerLevel = envImpl.getFileHandler().getLevel(); 411 assertEquals(Level.SEVERE, newConsoleHandlerLevel); 412 assertEquals(Level.WARNING, newFileHandlerLevel); 413 assertTrue(newConsoleHandlerLevel != consoleHandlerLevel); 414 assertTrue(newFileHandlerLevel != fileHandlerLevel); 415 416 /* Check levels again. */ 417 mutableConfig = env.getMutableConfig(); 418 env.setMutableConfig(mutableConfig); 419 consoleHandlerLevel = envImpl.getConsoleHandler().getLevel(); 420 fileHandlerLevel = envImpl.getFileHandler().getLevel(); 421 assertEquals(Level.SEVERE, consoleHandlerLevel); 422 assertEquals(Level.WARNING, fileHandlerLevel); 423 assertTrue(newConsoleHandlerLevel == consoleHandlerLevel); 424 assertTrue(newFileHandlerLevel == fileHandlerLevel); 425 426 env.close(); 427 } 428 429 /* 430 * A process for starting a JE Environment with properties file or 431 * configured JE params. 432 */ 433 static class PropertiesSettingProcess { 434 private final File envHome; 435 /* Handler levels set through properties configuration file. */ 436 private final Level propertyConsole; 437 private final Level propertyFile; 438 /* Handler levels set through JE params. */ 439 private final Level paramConsole; 440 private final Level paramFile; 441 /* Indicates whether property file and params are both set. */ 442 private final boolean bothSetting; 443 private Environment env; 444 PropertiesSettingProcess(File envHome, Level propertyConsole, Level propertyFile, boolean bothSetting, Level paramConsole, Level paramFile)445 public PropertiesSettingProcess(File envHome, 446 Level propertyConsole, 447 Level propertyFile, 448 boolean bothSetting, 449 Level paramConsole, 450 Level paramFile) { 451 this.envHome = envHome; 452 this.propertyConsole = propertyConsole; 453 this.propertyFile = propertyFile; 454 this.bothSetting = bothSetting; 455 this.paramConsole = paramConsole; 456 this.paramFile = paramFile; 457 } 458 459 /* Open a JE Environment. */ openEnv()460 public void openEnv() { 461 try { 462 EnvironmentConfig envConfig = new EnvironmentConfig(); 463 envConfig.setAllowCreate(true); 464 465 /* If bothSetting is true, set the JE params. */ 466 if (bothSetting) { 467 envConfig.setConfigParam 468 (EnvironmentConfig.CONSOLE_LOGGING_LEVEL, 469 paramConsole.toString()); 470 envConfig.setConfigParam 471 (EnvironmentConfig.FILE_LOGGING_LEVEL, 472 paramFile.toString()); 473 } 474 475 env = new Environment(envHome, envConfig); 476 } catch (DatabaseException e) { 477 e.printStackTrace(); 478 System.exit(1); 479 } 480 } 481 482 /* Check the configured levels. */ check()483 public void check() { 484 if (bothSetting) { 485 doCheck(paramConsole, paramFile); 486 } else { 487 doCheck(propertyConsole, propertyFile); 488 } 489 } 490 doCheck(Level cLevel, Level fLevel)491 private void doCheck(Level cLevel, Level fLevel) { 492 try { 493 EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 494 assertTrue 495 (envImpl.getConsoleHandler().getLevel() == cLevel); 496 assertTrue(envImpl.getFileHandler().getLevel() == fLevel); 497 } catch (Exception e) { 498 e.printStackTrace(); 499 System.exit(2); 500 } finally { 501 env.close(); 502 } 503 } 504 main(String args[])505 public static void main(String args[]) { 506 PropertiesSettingProcess process = null; 507 try { 508 Level paramConsole = null; 509 Level paramFile = null; 510 if (args.length == 6) { 511 paramConsole = Level.parse(args[4]); 512 paramFile = Level.parse(args[5]); 513 } 514 515 process = new PropertiesSettingProcess(new File(args[0]), 516 Level.parse(args[1]), 517 Level.parse(args[2]), 518 new Boolean(args[3]), 519 paramConsole, 520 paramFile); 521 } catch (Exception e) { 522 e.printStackTrace(); 523 System.exit(3); 524 } 525 526 if (process == null) { 527 throw new RuntimeException("Process should have been created"); 528 } 529 process.openEnv(); 530 process.check(); 531 } 532 } 533 534 /** 535 * Set up two environments with configured handlers, and make sure 536 * that they only log records from the appropriate environment. 537 */ 538 @Test testConfiguredHandler()539 public void testConfiguredHandler() { 540 TestInfo infoA = setupMultipleEnvs("A"); 541 TestInfo infoB = setupMultipleEnvs("B"); 542 int numTestMsgs = 10; 543 try { 544 Logger loggerA = LoggerUtils.getLogger 545 (com.sleepycat.je.utilint.LoggerUtils.class); 546 Logger loggerB = LoggerUtils.getLogger 547 (com.sleepycat.je.utilint.LoggerUtils.class); 548 549 for (int i = 0; i < numTestMsgs; i++) { 550 LoggerUtils.logMsg(loggerA, 551 infoA.envImpl, 552 Level.SEVERE, infoA.prefix + i); 553 LoggerUtils.logMsg(loggerB, 554 infoB.envImpl, 555 Level.SEVERE, infoB.prefix + i); 556 } 557 558 infoA.handler.verify(numTestMsgs); 559 infoB.handler.verify(numTestMsgs); 560 } finally { 561 cleanup(infoA.env, infoA.dir); 562 cleanup(infoB.env, infoB.dir); 563 } 564 } 565 cleanup(Environment env, File envDir)566 private void cleanup(Environment env, File envDir) { 567 env.close(); 568 TestUtils.removeLogFiles("2 envs", envDir, false); 569 removeFiles(envDir, "je.info"); 570 } 571 setupMultipleEnvs(String name)572 private TestInfo setupMultipleEnvs(String name) { 573 String testPrefix = "TEXT" + name; 574 File dir = new File(envHome, name); 575 dir.mkdirs(); 576 577 EnvironmentConfig config = new EnvironmentConfig(); 578 config.setAllowCreate(true); 579 TestHandler handler = new TestHandler(testPrefix); 580 handler.setLevel(Level.SEVERE); 581 config.setLoggingHandler(handler); 582 Environment env = new Environment(dir, config); 583 584 return new TestInfo(env, handler, testPrefix, dir); 585 } 586 587 private class TestInfo { 588 EnvironmentImpl envImpl; 589 Environment env; 590 String prefix; 591 TestHandler handler; 592 File dir; 593 TestInfo(Environment env, TestHandler handler, String testPrefix, File dir)594 TestInfo(Environment env, TestHandler handler, 595 String testPrefix, File dir) { 596 this.env = env; 597 this.envImpl = DbInternal.getEnvironmentImpl(env); 598 this.handler = handler; 599 this.prefix = testPrefix; 600 this.dir = dir; 601 } 602 } 603 604 private class TestHandler extends Handler { 605 606 private final String prefix; 607 private final List<String> logged; 608 TestHandler(String prefix)609 TestHandler(String prefix) { 610 this.prefix = prefix; 611 logged = new ArrayList<String>(); 612 } 613 verify(int numExpected)614 void verify(int numExpected) { 615 assertEquals(numExpected, logged.size()); 616 for (int i = 0; i < numExpected; i++) { 617 assertEquals(logged.get(i), (prefix + i)); 618 } 619 } 620 621 @Override publish(LogRecord record)622 public void publish(LogRecord record) { 623 logged.add(record.getMessage()); 624 } 625 626 @Override flush()627 public void flush() { 628 } 629 630 @Override close()631 public void close() throws SecurityException { 632 } 633 } 634 } 635