From 4be9e7aa4cd90ca5ac4410d04aadfc3a4efcbba0 Mon Sep 17 00:00:00 2001 From: Kirk Lund Date: Fri, 2 Nov 2018 17:03:24 -0700 Subject: [PATCH] GEODE-2644: Make LogWriterAppender optional and support log4j2.xml LogWriterAppender is now configured in log4j2.xml and it supports sessions that correspond with Cache lifecycle. This allows Geode to pause and resume LogWriterAppender and GeodeConsoleAppender without resorting to dynamically adding and removing appenders. When the Cache exists, log events stop going to the Console and instead go to the Geode log file. Whenever the Cache does not exist, log events go only to the Console. These changes remove as much of the Log4j2 Core manipulation as possible. Also fixed: * GEODE-5789: Geode now updates log level of all Geode loggers. List of changes: * Change LogWriterAppender to be pausable and session-oriented * Add GeodeConsoleAppender which is pausable * Log4j2 Core dependency is now optional * Internal Logging interfaces allow Logging service to be pluggable * Log4j2 xml integration testing now uses JUnit Rule from Log4j2 * Reduce coupling between Logging and the rest of Geode * Greatly increase test coverage for Logging --- .../GfshStartLocatorLogAcceptanceTest.java | 36 +- .../LoggingWithReconnectDistributedTest.java | 210 +++ .../LocatorLauncherIntegrationTestCase.java | 2 +- .../InternalLocatorIntegrationTest.java | 76 - .../logging/BannerLoggingIntegrationTest.java | 129 ++ .../ConfigurationInfoIntegrationTest.java | 42 + .../logging/ConfigurationIntegrationTest.java | 133 ++ ...stributedSystemLogFileIntegrationTest.java | 1152 ------------ .../LocatorLogFileIntegrationTest.java | 123 -- ...gLevelChangesWithCacheIntegrationTest.java | 150 ++ ...sWithDistributedSystemIntegrationTest.java | 167 ++ .../logging/LogServiceIntegrationTest.java | 236 --- ...gWithDistributedSystemIntegrationTest.java | 1597 +++++++++++++++++ .../LoggingWithLocatorIntegrationTest.java | 207 +++ ...ingWithLocatorLauncherIntegrationTest.java | 65 + ...gingWithServerLauncherIntegrationTest.java | 65 + ...anagerLogWriterFactoryIntegrationTest.java | 152 ++ .../internal/logging/NonBlankStrings.java | 27 + ...upConfigurationLoggingIntegrationTest.java | 159 ++ ...utRuleAndSystemErrRuleIntegrationTest.java | 98 + ...BothLogWriterAppendersIntegrationTest.java | 180 ++ ...heWithCustomLogConfigIntegrationTest.java} | 100 +- ...heWithDefaultAppendersIntegrationTest.java | 96 + ...ionWithLogLevelChangesIntegrationTest.java | 226 +++ ...rWithLoggerContextRuleIntegrationTest.java | 70 +- ...enderWithSystemOutRuleIntegrationTest.java | 182 -- ...BothLogWriterAppendersIntegrationTest.java | 203 +++ ...temWithLogLevelChangesIntegrationTest.java | 207 +++ .../log4j/FastLoggerIntegrationTest.java | 411 ++--- ...oggerWithDefaultConfigIntegrationTest.java | 53 +- ...boseMarkerFilterAcceptIntegrationTest.java | 26 +- ...erboseMarkerFilterDenyIntegrationTest.java | 26 +- .../GeodeConsoleAppenderIntegrationTest.java | 210 +++ ...nsoleAppenderWithCacheIntegrationTest.java | 168 ++ ...enderWithSystemOutRuleIntegrationTest.java | 98 + ...boseMarkerFilterAcceptIntegrationTest.java | 26 +- ...erboseMarkerFilterDenyIntegrationTest.java | 26 +- ...ceWithCustomLogConfigIntegrationTest.java} | 32 +- .../LogWriterAppenderIntegrationTest.java | 341 ++-- ...iterAppenderWithLimitsIntegrationTest.java | 147 ++ ...derWithMemberNameInXmlIntegrationTest.java | 148 ++ ...urityLogWriterAppenderIntegrationTest.java | 136 ++ .../MemberMXBeanShowLogIntegrationTest.java | 186 ++ ...ChangeLogLevelFunctionIntegrationTest.java | 164 ++ .../geode/codeAnalysis/excludedClasses.txt | 9 +- ...gWriterAppendersIntegrationTest_log4j2.xml | 44 + ...CustomLogConfigIntegrationTest_log4j2.xml} | 10 +- ...hLogLevelChangesIntegrationTest_log4j2.xml | 38 + ...oggerContextRuleIntegrationTest_log4j2.xml | 26 +- ...gWriterAppendersIntegrationTest_log4j2.xml | 44 + ...hLogLevelChangesIntegrationTest_log4j2.xml | 38 + ...rkerFilterAcceptIntegrationTest_log4j2.xml | 2 +- ...MarkerFilterDenyIntegrationTest_log4j2.xml | 2 +- ...eConsoleAppenderIntegrationTest_log4j2.xml | 38 + ...penderWithCacheIntegrationTest_log4j2.xml} | 19 +- ...ithSystemOutRuleIntegrationTest_log4j2.xml | 38 + ...rkerFilterAcceptIntegrationTest_log4j2.xml | 2 +- ...MarkerFilterDenyIntegrationTest_log4j2.xml | 2 +- ...CustomLogConfigIntegrationTest_log4j2.xml} | 2 +- ...ogWriterAppenderIntegrationTest_log4j2.xml | 38 + ...penderWithLimitsIntegrationTest_log4j2.xml | 38 + ...hMemberNameInXmlIntegrationTest_log4j2.xml | 38 + ...ogWriterAppenderIntegrationTest_log4j2.xml | 39 + .../logging/log4j/CacheLoggingBenchmark.java | 116 ++ .../log4j/LogWriterAppenderBenchmark.java | 124 ++ .../internal/AdminDistributedSystemImpl.java | 27 +- .../geode/admin/jmx/internal/AgentImpl.java | 111 +- .../internal/InternalDistributedSystem.java | 151 +- .../distributed/internal/InternalLocator.java | 107 +- .../RuntimeDistributionConfigImpl.java | 12 +- .../org/apache/geode/internal/Banner.java | 94 +- .../geode/internal/VersionDescription.java | 37 +- .../admin/remote/TailLogResponse.java | 38 +- .../geode/internal/logging/Configuration.java | 237 +++ .../internal/logging/ConfigurationInfo.java | 56 + .../internal/logging/InternalLogWriter.java | 2 - .../internal/logging/LogConfigListener.java | 23 + .../internal/logging/LogConfigSupplier.java | 35 +- .../geode/internal/logging/LogFile.java | 49 + .../internal/logging/LogFileDetails.java | 21 +- .../internal/logging/LogMessageRegex.java | 106 ++ .../geode/internal/logging/LogService.java | 249 +-- .../internal/logging/LogWriterFactory.java | 81 +- .../internal/logging/LogWriterLevel.java | 40 +- .../internal/logging/LoggingSession.java | 119 ++ .../logging/LoggingSessionListener.java | 58 + .../logging/LoggingSessionListeners.java | 100 ++ .../internal/logging/ManagerLogWriter.java | 55 +- .../logging/ManagerLogWriterFactory.java | 176 ++ .../geode/internal/logging/NullLogFile.java | 53 + .../geode/internal/logging/NullLogWriter.java | 58 + .../internal/logging/NullLoggingSession.java | 47 + .../internal/logging/NullProviderAgent.java | 45 + .../geode/internal/logging/ProviderAgent.java | 39 + .../geode/internal/logging/PureLogWriter.java | 9 +- .../internal/logging/SecurityLogWriter.java | 12 +- .../internal/logging/SessionContext.java | 48 + .../internal/logging/log4j/Configurator.java | 186 -- .../logging/log4j/GeodeConsoleAppender.java | 305 ++++ .../internal/logging/log4j/Log4jAgent.java | 300 ++++ .../internal/logging/log4j/LogLevel.java | 162 +- .../logging/log4j/LogWriterAppender.java | 441 +++-- .../logging/log4j/LogWriterAppenders.java | 293 --- .../log4j/LogWriterLevelConverter.java | 97 + .../logging/log4j/LogWriterLogger.java | 23 +- .../log4j/MemberNamePatternConverter.java | 64 + .../logging/log4j/MemberNameSupplier.java | 32 + .../security/IntegratedSecurityService.java | 4 +- .../shiro/SecurityManagerProvider.java | 4 +- .../statistics/GemFireStatSampler.java | 7 +- .../internal/statistics/HostStatSampler.java | 20 + .../statistics/StatArchiveHandler.java | 21 +- .../statistics/StatArchiveHandlerConfig.java | 16 +- .../internal/beans/MemberMBeanBridge.java | 9 +- .../cli/commands/DiskStoreCommandsUtils.java | 3 +- .../cli/functions/ChangeLogLevelFunction.java | 28 +- geode-core/src/main/resources/log4j2-cli.xml | 2 +- geode-core/src/main/resources/log4j2.xml | 18 +- .../internal/logging/log4j/log4j2-legacy.xml | 2 +- .../sanctioned-geode-core-serializables.txt | 1 - .../org/apache/geode/internal/BannerTest.java | 59 + .../internal/logging/ConfigurationTest.java | 382 ++++ ...eRegexMatchesStartupConfigurationTest.java | 227 +++ .../internal/logging/LogMessageRegexTest.java | 242 +++ .../internal/logging/LogServiceTest.java | 129 +- .../internal/logging/LogWriterLevelTest.java | 73 +- .../internal/logging/LoggingSessionTest.java | 219 +++ .../logging/ManagerLogWriterTest.java | 41 + .../internal/logging/log4j/LogLevelTest.java | 183 +- .../log4j/LogWriterLevelConverterTest.java | 132 ++ .../log4j/MemberNamePatternConverterTest.java | 57 + .../apache/geode/test/golden/log4j2-test.xml | 2 +- .../geode/test/dunit/LogWriterUtils.java | 4 +- .../test/dunit/standalone/DUnitLauncher.java | 9 +- .../logging/TestLogWriterFactory.java | 5 +- .../geode/management/MXBeanAwaitility.java | 0 .../accessible/AccessibleTemporaryFolder.java | 35 + 137 files changed, 11198 insertions(+), 3929 deletions(-) create mode 100644 geode-core/src/distributedTest/java/org/apache/geode/internal/logging/LoggingWithReconnectDistributedTest.java delete mode 100644 geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/BannerLoggingIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationInfoIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationIntegrationTest.java delete mode 100755 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/DistributedSystemLogFileIntegrationTest.java delete mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LocatorLogFileIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithCacheIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithDistributedSystemIntegrationTest.java delete mode 100755 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogServiceIntegrationTest.java create mode 100755 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithDistributedSystemIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorLauncherIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithServerLauncherIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ManagerLogWriterFactoryIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/NonBlankStrings.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/StartupConfigurationLoggingIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/SystemOutRuleAndSystemErrRuleIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest.java rename geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/{CustomConfigWithCacheIntegrationTest.java => CacheWithCustomLogConfigIntegrationTest.java} (62%) create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CacheWithDefaultAppendersIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest.java delete mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithSystemOutRuleIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithCacheIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest.java rename geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/{CustomConfigWithLogServiceIntegrationTest.java => LogServiceWithCustomLogConfigIntegrationTest.java} (83%) create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/management/MemberMXBeanShowLogIntegrationTest.java create mode 100644 geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunctionIntegrationTest.java create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest_log4j2.xml rename geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/{CustomConfigWithLogServiceIntegrationTest_log4j2.xml => CacheWithCustomLogConfigIntegrationTest_log4j2.xml} (86%) create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest_log4j2.xml create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest_log4j2.xml create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest_log4j2.xml create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest_log4j2.xml rename geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/{ConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml => GeodeConsoleAppenderWithCacheIntegrationTest_log4j2.xml} (69%) create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml rename geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/{CustomConfigWithCacheIntegrationTest_log4j2.xml => LogServiceWithCustomLogConfigIntegrationTest_log4j2.xml} (96%) create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest_log4j2.xml create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest_log4j2.xml create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest_log4j2.xml create mode 100644 geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest_log4j2.xml create mode 100644 geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/CacheLoggingBenchmark.java create mode 100644 geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderBenchmark.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/Configuration.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/ConfigurationInfo.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigListener.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/LogFile.java rename geode-junit/src/main/java/org/apache/geode/internal/logging/LogServiceIntegrationTestSupport.java => geode-core/src/main/java/org/apache/geode/internal/logging/LogFileDetails.java (60%) mode change 100755 => 100644 create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/LogMessageRegex.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSession.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListener.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListeners.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriterFactory.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/NullLogFile.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/NullLogWriter.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/NullLoggingSession.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/NullProviderAgent.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/ProviderAgent.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/SessionContext.java delete mode 100755 geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Configurator.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppender.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Log4jAgent.java delete mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppenders.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverter.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverter.java create mode 100644 geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNameSupplier.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/BannerTest.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/logging/ConfigurationTest.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexMatchesStartupConfigurationTest.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexTest.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/logging/LoggingSessionTest.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/logging/ManagerLogWriterTest.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverterTest.java create mode 100644 geode-core/src/test/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverterTest.java rename {geode-dunit => geode-junit}/src/main/java/org/apache/geode/management/MXBeanAwaitility.java (100%) create mode 100644 geode-junit/src/main/java/org/apache/geode/test/junit/rules/accessible/AccessibleTemporaryFolder.java diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/GfshStartLocatorLogAcceptanceTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/GfshStartLocatorLogAcceptanceTest.java index 01a47c9bf755..4d85ab9159f6 100644 --- a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/GfshStartLocatorLogAcceptanceTest.java +++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/GfshStartLocatorLogAcceptanceTest.java @@ -14,46 +14,46 @@ */ package org.apache.geode.management.internal.cli.commands; -import static org.assertj.core.api.Assertions.assertThat; +import static org.apache.geode.internal.logging.Configuration.STARTUP_CONFIGURATION; import java.io.File; -import java.nio.charset.StandardCharsets; -import com.google.common.io.Files; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.apache.geode.internal.Banner; +import org.apache.geode.test.assertj.LogFileAssert; import org.apache.geode.test.junit.categories.GfshTest; import org.apache.geode.test.junit.categories.LoggingTest; import org.apache.geode.test.junit.rules.gfsh.GfshExecution; import org.apache.geode.test.junit.rules.gfsh.GfshRule; import org.apache.geode.test.junit.rules.gfsh.GfshScript; -@Category({GfshTest.class, LoggingTest.class}) +@Category({LoggingTest.class, GfshTest.class}) public class GfshStartLocatorLogAcceptanceTest { + private File logFile; + @Rule public GfshRule gfshRule = new GfshRule(); - @Test - public void bannerOnlyLogsOnce() throws Exception { - final String banner = "Licensed to the Apache Software Foundation (ASF)"; - String lines = getExecutionLogs(); - assertThat(lines.indexOf(banner)).isEqualTo(lines.lastIndexOf(banner)); + @Before + public void setUp() { + GfshExecution gfshExecution = GfshScript.of("start locator").execute(gfshRule); + File[] files = gfshExecution.getWorkingDir().listFiles(); + String logName = files[0].getAbsolutePath() + "/" + files[0].getName() + ".log"; + logFile = new File(logName); } @Test - public void startupConfigsOnlyLogsOnce() throws Exception { - final String startupConfigs = "### GemFire Properties using default values ###"; - String lines = getExecutionLogs(); - assertThat(lines.indexOf(startupConfigs)).isEqualTo(lines.lastIndexOf(startupConfigs)); + public void bannerIsLoggedOnlyOnce() { + LogFileAssert.assertThat(logFile).containsOnlyOnce(Banner.BannerHeader.displayValues()); } - private String getExecutionLogs() throws Exception { - GfshExecution gfshExecution = GfshScript.of("start locator").execute(gfshRule); - File[] files = gfshExecution.getWorkingDir().listFiles(); - String logName = files[0].getAbsolutePath() + "/" + files[0].getName() + ".log"; - return Files.readLines(new File(logName), StandardCharsets.UTF_8).toString(); + @Test + public void startupConfigIsLoggedOnlyOnce() { + LogFileAssert.assertThat(logFile).containsOnlyOnce(STARTUP_CONFIGURATION); } } diff --git a/geode-core/src/distributedTest/java/org/apache/geode/internal/logging/LoggingWithReconnectDistributedTest.java b/geode-core/src/distributedTest/java/org/apache/geode/internal/logging/LoggingWithReconnectDistributedTest.java new file mode 100644 index 000000000000..4734bba5e7bd --- /dev/null +++ b/geode-core/src/distributedTest/java/org/apache/geode/internal/logging/LoggingWithReconnectDistributedTest.java @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static java.lang.System.lineSeparator; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.apache.geode.distributed.ConfigurationProperties.DISABLE_AUTO_RECONNECT; +import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.MAX_WAIT_TIME_RECONNECT; +import static org.apache.geode.distributed.ConfigurationProperties.MEMBER_TIMEOUT; +import static org.apache.geode.distributed.internal.membership.gms.MembershipManagerHelper.getMembershipManager; +import static org.apache.geode.internal.Banner.BannerHeader.displayValues; +import static org.apache.geode.internal.logging.Configuration.STARTUP_CONFIGURATION; +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.apache.geode.test.awaitility.GeodeAwaitility.getTimeout; +import static org.apache.geode.test.dunit.IgnoredException.addIgnoredException; +import static org.apache.geode.test.dunit.VM.getController; +import static org.apache.geode.test.dunit.VM.getVM; +import static org.apache.geode.test.dunit.VM.toArray; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.Serializable; +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.ForcedDisconnectException; +import org.apache.geode.distributed.LocatorLauncher; +import org.apache.geode.distributed.ServerLauncher; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.distributed.internal.membership.gms.mgr.GMSMembershipManager; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.dunit.rules.DistributedRule; +import org.apache.geode.test.junit.categories.LoggingTest; +import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder; +import org.apache.geode.test.junit.rules.serializable.SerializableTestName; + +/** + * Distributed tests for logging during reconnect. + */ +@Category(LoggingTest.class) +public class LoggingWithReconnectDistributedTest implements Serializable { + + private static final long TIMEOUT = getTimeout().getValueInMS(); + + private static LocatorLauncher locatorLauncher; + private static ServerLauncher serverLauncher; + + private static InternalDistributedSystem system; + + private VM locatorVM; + private VM server1VM; + private VM server2VM; + + private String locatorName; + private String server1Name; + private String server2Name; + + private File locatorDir; + private File server1Dir; + private File server2Dir; + + @Rule + public DistributedRule distributedRule = new DistributedRule(); + + @Rule + public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder(); + + @Rule + public SerializableTestName testName = new SerializableTestName(); + + @Before + public void setUp() throws Exception { + locatorName = "locator-" + testName.getMethodName(); + server1Name = "server-" + testName.getMethodName() + "-1"; + server2Name = "server-" + testName.getMethodName() + "-2"; + + locatorVM = getVM(0); + server1VM = getVM(1); + server2VM = getController(); + + locatorDir = temporaryFolder.newFolder(locatorName); + server1Dir = temporaryFolder.newFolder(server1Name); + server2Dir = temporaryFolder.newFolder(server2Name); + + int locatorPort = locatorVM.invoke(() -> createLocator()); + + server1VM.invoke(() -> createServer(server1Name, server1Dir, locatorPort)); + server2VM.invoke(() -> createServer(server2Name, server2Dir, locatorPort)); + + addIgnoredException(ForcedDisconnectException.class); + addIgnoredException("Possible loss of quorum"); + } + + @After + public void tearDown() { + locatorVM.invoke(() -> { + locatorLauncher.stop(); + locatorLauncher = null; + system = null; + }); + + for (VM vm : toArray(server1VM, server2VM)) { + vm.invoke(() -> { + serverLauncher.stop(); + serverLauncher = null; + system = null; + }); + } + } + + @Test + public void logFileContainsBannerOnlyOnce() { + locatorVM.invoke(() -> { + assertThat(system.getDistributionManager().getDistributionManagerIds()).hasSize(3); + }); + + server2VM.invoke(() -> { + GMSMembershipManager membershipManager = (GMSMembershipManager) getMembershipManager(system); + membershipManager.forceDisconnect("Forcing disconnect in " + testName.getMethodName()); + + await().until(() -> system.isReconnecting()); + system.waitUntilReconnected(TIMEOUT, MILLISECONDS); + assertThat(system.getReconnectedSystem()).isNotSameAs(system); + }); + + locatorVM.invoke(() -> { + assertThat(system.getDistributionManager().getDistributionManagerIds()).hasSize(3); + }); + + server2VM.invoke(() -> { + File[] files = server2Dir.listFiles((dir, name) -> name.endsWith(".log")); + assertThat(files).as(expectedOneLogFile(files)).hasSize(1); + + File logFile = files[0]; + assertThat(logFile).exists(); + + // Banner must be logged only once + LogFileAssert.assertThat(logFile).containsOnlyOnce(displayValues()); + + // Startup Config must be logged only once + String[] startupConfiguration = StringUtils + .split(STARTUP_CONFIGURATION + system.getConfig().toLoggerString(), lineSeparator()); + + LogFileAssert.assertThat(logFile).containsOnlyOnce(startupConfiguration); + }); + } + + private String expectedOneLogFile(File[] files) { + return "Expecting directory:" + lineSeparator() + " " + server2Dir.getAbsolutePath() + + lineSeparator() + "to contain only one log file:" + lineSeparator() + " " + server2Name + + ".log" + lineSeparator() + "but found multiple log files:" + lineSeparator() + " " + + Arrays.asList(files); + } + + private int createLocator() { + LocatorLauncher.Builder builder = new LocatorLauncher.Builder(); + builder.setMemberName(locatorName); + builder.setWorkingDirectory(locatorDir.getAbsolutePath()); + builder.setPort(0); + builder.set(DISABLE_AUTO_RECONNECT, "false"); + builder.set(ENABLE_CLUSTER_CONFIGURATION, "false"); + builder.set(MAX_WAIT_TIME_RECONNECT, "1000"); + builder.set(MEMBER_TIMEOUT, "2000"); + + locatorLauncher = builder.build(); + locatorLauncher.start(); + + system = (InternalDistributedSystem) locatorLauncher.getCache().getDistributedSystem(); + + return locatorLauncher.getPort(); + } + + private void createServer(String serverName, File serverDir, int locatorPort) { + ServerLauncher.Builder builder = new ServerLauncher.Builder(); + builder.setMemberName(serverName); + builder.setWorkingDirectory(serverDir.getAbsolutePath()); + builder.setServerPort(0); + builder.set(LOCATORS, "localHost[" + locatorPort + "]"); + builder.set(DISABLE_AUTO_RECONNECT, "false"); + builder.set(ENABLE_CLUSTER_CONFIGURATION, "false"); + builder.set(MAX_WAIT_TIME_RECONNECT, "1000"); + builder.set(MEMBER_TIMEOUT, "2000"); + + serverLauncher = builder.build(); + serverLauncher.start(); + + system = (InternalDistributedSystem) serverLauncher.getCache().getDistributedSystem(); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java index 61c73138de93..1e484dc2a37f 100755 --- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java @@ -93,7 +93,7 @@ protected LocatorLauncher givenLocatorLauncher() { return givenLocatorLauncher(newBuilder()); } - private LocatorLauncher givenLocatorLauncher(final Builder builder) { + protected LocatorLauncher givenLocatorLauncher(final Builder builder) { return builder.build(); } diff --git a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java deleted file mode 100644 index 9d0917bb8dbc..000000000000 --- a/geode-core/src/integrationTest/java/org/apache/geode/distributed/internal/InternalLocatorIntegrationTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package org.apache.geode.distributed.internal; - -import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; -import static org.apache.geode.distributed.ConfigurationProperties.NAME; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Properties; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import org.apache.geode.distributed.Locator; -import org.apache.geode.internal.AvailablePortHelper; -import org.apache.geode.internal.logging.log4j.LogWriterAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; - -public class InternalLocatorIntegrationTest { - - private Locator locator; - private LogWriterAppender appender; - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Test - public void testLogWriterAppenderShouldBeRemovedForALocatorWithNoDS() throws Exception { - Properties properties = new Properties(); - properties.setProperty(NAME, "testVM"); - properties.setProperty(LOG_FILE, temporaryFolder.newFile("testVM.log").getAbsolutePath()); - - int port = AvailablePortHelper.getRandomAvailableTCPPort(); - locator = InternalLocator.startLocator(port, null, null, null, null, false, properties, null); - - appender = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); - assertThat(appender).isNotNull(); - - locator.stop(); - - appender = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); - assertThat(appender).isNull(); - } - - @Test - public void testLogWriterAppenderShouldBeRemovedForALocatorWithDS() throws Exception { - Properties properties = new Properties(); - properties.setProperty(NAME, "testVM"); - properties.setProperty(LOG_FILE, temporaryFolder.newFile("testVM.log").getAbsolutePath()); - - int port = AvailablePortHelper.getRandomAvailableTCPPort(); - locator = InternalLocator.startLocatorAndDS(port, null, properties); - - appender = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); - assertThat(appender).isNotNull(); - - locator.stop(); - - appender = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); - assertThat(appender).isNull(); - } -} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/BannerLoggingIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/BannerLoggingIntegrationTest.java new file mode 100644 index 000000000000..04a8c72a83a4 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/BannerLoggingIntegrationTest.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static java.nio.charset.Charset.defaultCharset; +import static org.apache.commons.io.FileUtils.readLines; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.internal.Banner.BannerHeader.displayValues; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.util.List; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.Banner; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for logging of the {@link Banner}. + */ +@Category(LoggingTest.class) +public class BannerLoggingIntegrationTest { + + private File mainLogFile; + private InternalDistributedSystem system; + private Logger geodeLogger; + private String logMessage; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() { + String name = testName.getMethodName(); + mainLogFile = new File(temporaryFolder.getRoot(), name + "-main.log"); + + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFile.getAbsolutePath()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + geodeLogger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + } + + @After + public void tearDown() throws Exception { + if (system != null) { + system.disconnect(); + } + } + + @Test + public void bannerIsLoggedToFile() { + LogFileAssert.assertThat(mainLogFile).contains(displayValues()); + } + + @Test + public void bannerIsLoggedToFileOnlyOnce() { + LogFileAssert.assertThat(mainLogFile).containsOnlyOnce(displayValues()); + } + + /** + * Verifies that the banner is logged before any log messages. + */ + @Test + public void bannerIsLoggedToFileBeforeLogMessage() throws Exception { + geodeLogger.info(logMessage); + + List lines = readLines(mainLogFile, defaultCharset()); + + boolean foundBanner = false; + boolean foundLogMessage = false; + + for (String line : lines) { + if (containsAny(line, displayValues())) { + assertThat(foundLogMessage).as("Banner should be logged before log message: " + lines) + .isFalse(); + foundBanner = true; + } + if (line.contains(logMessage)) { + assertThat(foundBanner).as("Log message should be logged after banner: " + lines) + .isTrue(); + foundLogMessage = true; + } + } + + assertThat(foundBanner).as("Banner not found in: " + lines).isTrue(); + assertThat(foundLogMessage).as("Log message not found in: " + lines).isTrue(); + } + + private boolean containsAny(String string, String... values) { + for (String value : values) { + if (string.contains(value)) { + return true; + } + } + return false; + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationInfoIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationInfoIntegrationTest.java new file mode 100644 index 000000000000..3b69302cbc17 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationInfoIntegrationTest.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.ConfigurationInfo.getConfigurationInfo; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.internal.logging.log4j.Log4jAgent; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link ConfigurationInfo}. + */ +@Category(LoggingTest.class) +public class ConfigurationInfoIntegrationTest { + + @Test + public void getConfigurationInfoContainsLog4j2Xml() { + assertThat(getConfigurationInfo()).contains("log4j2.xml"); + } + + @Test + public void getConfigurationInfoMatchesLog4jAgent() { + + assertThat(getConfigurationInfo()).contains(Log4jAgent.getConfigurationInfo()); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationIntegrationTest.java new file mode 100644 index 000000000000..d8bc23698ee3 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ConfigurationIntegrationTest.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs.ALWAYS; +import static org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope.ALL_LOGGERS; +import static org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope.GEODE_AND_APPLICATION_LOGGERS; +import static org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope.GEODE_AND_SECURITY_LOGGERS; +import static org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope.GEODE_LOGGERS; +import static org.apache.geode.internal.logging.Configuration.MAIN_LOGGER_NAME; +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.getLoggerConfig; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.internal.logging.log4j.Log4jAgent; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link Configuration}. + */ +@Category(LoggingTest.class) +public class ConfigurationIntegrationTest { + + private static final String APPLICATION_LOGGER_NAME = "com.application"; + + private LogConfigSupplier logConfigSupplier; + private LogConfig logConfig; + + private Logger geodeLogger; + private Logger geodeSecurityLogger; + private Logger applicationLogger; + + @Before + public void setUp() { + logConfigSupplier = mock(LogConfigSupplier.class); + logConfig = mock(LogConfig.class); + + when(logConfigSupplier.getLogConfig()).thenReturn(logConfig); + when(logConfig.getLogLevel()).thenReturn(INFO.intLevel()); + when(logConfig.getSecurityLogLevel()).thenReturn(INFO.intLevel()); + + geodeLogger = LogManager.getLogger(MAIN_LOGGER_NAME); + geodeSecurityLogger = LogManager.getLogger(SECURITY_LOGGER_NAME); + applicationLogger = LogManager.getLogger(APPLICATION_LOGGER_NAME); + + List loggerConfigs = Arrays.asList(getLoggerConfig(geodeLogger), + getLoggerConfig(geodeSecurityLogger), getLoggerConfig(applicationLogger)); + + Log4jAgent.updateLogLevel(Level.INFO, loggerConfigs.toArray(new LoggerConfig[0])); + } + + @Test + public void loggerLogLevelIsInfo() { + assertThat(geodeLogger.getLevel()).isEqualTo(Level.INFO); + assertThat(geodeSecurityLogger.getLevel()).isEqualTo(Level.INFO); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + } + + @Test + public void updatesLogLevelForScopeGeodeLoggers() { + when(logConfig.getLogLevel()).thenReturn(WARNING.intLevel()); + + Configuration configuration = Configuration.create(ALWAYS, GEODE_LOGGERS); + configuration.initialize(logConfigSupplier); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.WARN); + assertThat(geodeSecurityLogger.getLevel()).isEqualTo(Level.INFO); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + } + + @Test + public void updatesLogLevelForScopeGeodeAndSecurityLoggers() { + when(logConfig.getLogLevel()).thenReturn(WARNING.intLevel()); + + Configuration configuration = Configuration.create(ALWAYS, GEODE_AND_SECURITY_LOGGERS); + configuration.initialize(logConfigSupplier); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.WARN); + assertThat(geodeSecurityLogger.getLevel()).isEqualTo(Level.WARN); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + } + + @Test + public void updatesLogLevelForScopeAllLoggers() { + when(logConfig.getLogLevel()).thenReturn(WARNING.intLevel()); + + Configuration configuration = Configuration.create(ALWAYS, ALL_LOGGERS); + configuration.initialize(logConfigSupplier); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.WARN); + assertThat(geodeSecurityLogger.getLevel()).isEqualTo(Level.WARN); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.WARN); + } + + @Test + public void updatesLogLevelForScopeGeodeAndApplicationLoggers() { + when(logConfig.getLogLevel()).thenReturn(WARNING.intLevel()); + + Configuration configuration = Configuration.create(ALWAYS, GEODE_AND_APPLICATION_LOGGERS); + configuration.initialize(logConfigSupplier); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.WARN); + assertThat(geodeSecurityLogger.getLevel()).isEqualTo(Level.INFO); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.WARN); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/DistributedSystemLogFileIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/DistributedSystemLogFileIntegrationTest.java deleted file mode 100755 index dba2b0b4f3de..000000000000 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/DistributedSystemLogFileIntegrationTest.java +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.logging; - -import static org.apache.commons.lang3.SystemUtils.LINE_SEPARATOR; -import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; -import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; -import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; -import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; -import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_FILE; -import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_LEVEL; -import static org.apache.geode.test.awaitility.GeodeAwaitility.await; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.util.List; -import java.util.Properties; -import java.util.Scanner; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; - -import org.apache.geode.LogWriter; -import org.apache.geode.distributed.DistributedSystem; -import org.apache.geode.distributed.internal.DistributionConfig; -import org.apache.geode.distributed.internal.InternalDistributedSystem; -import org.apache.geode.internal.logging.log4j.FastLogger; -import org.apache.geode.internal.logging.log4j.LogWriterLogger; -import org.apache.geode.test.junit.categories.LoggingTest; - -/** - * Connects DistributedSystem and tests logging behavior at a high level. - */ -@Category(LoggingTest.class) -public class DistributedSystemLogFileIntegrationTest { - - private static final AtomicInteger COUNTER = new AtomicInteger(); - - private File logFile; - private String logFileName; - private File securityLogFile; - private String securityLogFileName; - - private InternalDistributedSystem system; - - private String prefix; - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Rule - public TestName testName = new TestName(); - - @Before - public void setUp() { - logFile = new File(temporaryFolder.getRoot(), - testName.getMethodName() + "-system-" + System.currentTimeMillis() + ".log"); - logFileName = logFile.getAbsolutePath(); - - securityLogFile = new File(temporaryFolder.getRoot(), - "security-" + testName.getMethodName() + "-system-" + System.currentTimeMillis() + ".log"); - securityLogFileName = securityLogFile.getAbsolutePath(); - - prefix = "ExpectedStrings: " + testName.getMethodName() + " message logged at "; - } - - @After - public void tearDown() throws Exception { - if (system != null) { - system.disconnect(); - } - // We will want to remove this at some point but right now the log context - // does not clear out the security logconfig between tests - LoggerContext context = (LoggerContext) LogManager.getContext(false); - context.stop(); - } - - @Test - public void testDistributedSystemLogWritersWithFilesDetails() throws Exception { - Properties config = new Properties(); - config.put(LOG_FILE, logFileName); - config.put(SECURITY_LOG_FILE, securityLogFileName); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(config); - - await().untilAsserted(() -> { - assertThat(logFile).exists(); - assertThat(securityLogFile).exists(); - }); - - // assertThat logFile is not empty - try (FileInputStream fis = new FileInputStream(logFile)) { - assertThat(fis.available()).isGreaterThan(0); - } - - DistributionConfig distributionConfig = system.getConfig(); - - assertThat(distributionConfig.getLogLevel()) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); - assertThat(distributionConfig.getSecurityLogLevel()) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); - - assertThat(distributionConfig.getLogFile().getAbsolutePath()).isEqualTo(logFileName); - assertThat(distributionConfig.getSecurityLogFile().getAbsolutePath()) - .isEqualTo(securityLogFileName); - - assertThat(system.getLogWriter()).isInstanceOf(LogWriterLogger.class); - assertThat(system.getSecurityLogWriter()).isInstanceOf(LogWriterLogger.class); - - LogWriterLogger logWriterLogger = (LogWriterLogger) system.getLogWriter(); - LogWriterLogger securityLogWriterLogger = (LogWriterLogger) system.getSecurityLogWriter(); - - assertThat(logWriterLogger.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(securityLogWriterLogger.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - - securityLogWriterLogger.info("test: security log file created at info"); - - // assertThat securityLogFile is not empty - try (FileInputStream fis = new FileInputStream(securityLogFile)) { - assertThat(fis.available()).isGreaterThan(0); - } - - LogWriter logWriter = logWriterLogger; - assertThat(logWriter.finestEnabled()).isFalse(); - assertThat(logWriter.finerEnabled()).isFalse(); - assertThat(logWriter.fineEnabled()).isFalse(); - assertThat(logWriter.configEnabled()).isTrue(); - assertThat(logWriter.infoEnabled()).isTrue(); - assertThat(logWriter.warningEnabled()).isTrue(); - assertThat(logWriter.errorEnabled()).isTrue(); - assertThat(logWriter.severeEnabled()).isTrue(); - - FastLogger logWriterFastLogger = logWriterLogger; - // assertThat(logWriterFastLogger.isDelegating()).isTrue(); - assertThat(logWriterFastLogger.isTraceEnabled()).isFalse(); - assertThat(logWriterFastLogger.isDebugEnabled()).isFalse(); - assertThat(logWriterFastLogger.isInfoEnabled()).isTrue(); - assertThat(logWriterFastLogger.isWarnEnabled()).isTrue(); - assertThat(logWriterFastLogger.isErrorEnabled()).isTrue(); - assertThat(logWriterFastLogger.isFatalEnabled()).isTrue(); - - LogWriter securityLogWriter = securityLogWriterLogger; - assertThat(securityLogWriter.finestEnabled()).isFalse(); - assertThat(securityLogWriter.finerEnabled()).isFalse(); - assertThat(securityLogWriter.fineEnabled()).isFalse(); - assertThat(securityLogWriter.configEnabled()).isTrue(); - assertThat(securityLogWriter.infoEnabled()).isTrue(); - assertThat(securityLogWriter.warningEnabled()).isTrue(); - assertThat(securityLogWriter.errorEnabled()).isTrue(); - assertThat(securityLogWriter.severeEnabled()).isTrue(); - - FastLogger securityLogWriterFastLogger = logWriterLogger; - // assertThat(securityLogWriterFastLogger.isDelegating()).isFalse(); - assertThat(securityLogWriterFastLogger.isTraceEnabled()).isFalse(); - assertThat(securityLogWriterFastLogger.isDebugEnabled()).isFalse(); - assertThat(securityLogWriterFastLogger.isInfoEnabled()).isTrue(); - assertThat(securityLogWriterFastLogger.isWarnEnabled()).isTrue(); - assertThat(securityLogWriterFastLogger.isErrorEnabled()).isTrue(); - assertThat(securityLogWriterFastLogger.isFatalEnabled()).isTrue(); - } - - @Test - public void testDistributedSystemCreatesLogFile() throws Exception { - Properties config = new Properties(); - config.put(LOG_FILE, logFileName); - config.put(LOG_LEVEL, "config"); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(config); - - await().untilAsserted(() -> assertThat(logFile).exists()); - - LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); - Logger geodeLogger = LogService.getLogger(); - Logger applicationLogger = LogManager.getLogger("net.customer"); - - // ------------------------------------------------------------------------------------------- - // CONFIG level - - DistributionConfig distributionConfig = system.getConfig(); - - assertThat(distributionConfig.getLogLevel()) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.INFO); - assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); - - String message = createMessage(LogWriterLevel.FINEST); - logWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - logWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - logWriter.fine(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - logWriter.config(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - logWriter.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - logWriter.warning(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - logWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - logWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - applicationLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - applicationLogger.debug(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.INFO); - applicationLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - applicationLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - applicationLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - applicationLogger.fatal(message); - assertThatFileContains(logFile, message); - - // ------------------------------------------------------------------------------------------- - // FINE level - - distributionConfig.setLogLevel(LogWriterLevel.FINE.getLogWriterLevel()); - - assertThat(distributionConfig.getLogLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); - assertThat(applicationLogger.getLevel()).isEqualTo(Level.DEBUG); - - message = createMessage(LogWriterLevel.FINEST); - logWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - logWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - logWriter.fine(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - logWriter.config(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - logWriter.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - logWriter.warning(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - logWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - logWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - applicationLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - applicationLogger.debug(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.INFO); - applicationLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - applicationLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - applicationLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - applicationLogger.fatal(message); - assertThatFileContains(logFile, message); - - // ------------------------------------------------------------------------------------------- - // ERROR level - - distributionConfig.setLogLevel(LogWriterLevel.ERROR.getLogWriterLevel()); - - assertThat(distributionConfig.getLogLevel()) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.ERROR); - assertThat(applicationLogger.getLevel()).isEqualTo(Level.ERROR); - - message = createMessage(LogWriterLevel.FINEST); - logWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - logWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - logWriter.fine(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - logWriter.config(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - logWriter.info(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - logWriter.warning(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - logWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - logWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - applicationLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - applicationLogger.debug(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.INFO); - applicationLogger.info(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.WARN); - applicationLogger.warn(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.ERROR); - applicationLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - applicationLogger.fatal(message); - assertThatFileContains(logFile, message); - } - - @Test - public void testDistributedSystemWithFineLogLevel() throws Exception { - Properties config = new Properties(); - config.put(LOG_FILE, logFileName); - config.put(LOG_LEVEL, "fine"); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(config); - - await().untilAsserted(() -> assertThat(logFile).exists()); - - LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); - Logger geodeLogger = LogService.getLogger(); - - DistributionConfig distributionConfig = system.getConfig(); - - // ------------------------------------------------------------------------------------------- - // FINE level - - assertThat(distributionConfig.getLogLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); - - String message = createMessage(LogWriterLevel.FINEST); - logWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - logWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - logWriter.fine(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - logWriter.config(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - logWriter.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - logWriter.warning(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - logWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - logWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - - // ------------------------------------------------------------------------------------------- - // ERROR level - - distributionConfig.setLogLevel(LogWriterLevel.ERROR.getLogWriterLevel()); - - assertThat(distributionConfig.getLogLevel()) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.ERROR); - - message = createMessage(LogWriterLevel.FINEST); - logWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - logWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - logWriter.fine(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - logWriter.config(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - logWriter.info(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - logWriter.warning(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - logWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - logWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - } - - @Test - public void testDistributedSystemWithDebugLogLevel() throws Exception { - Properties config = new Properties(); - config.put(LOG_FILE, logFileName); - config.put(LOG_LEVEL, "debug"); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(config); - - await().untilAsserted(() -> assertThat(logFile).exists()); - - LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); - Logger geodeLogger = LogService.getLogger(); - - DistributionConfig distributionConfig = system.getConfig(); - - // ------------------------------------------------------------------------------------------- - // DEBUG LEVEL - - assertThat(distributionConfig.getLogLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); - - String message = createMessage(LogWriterLevel.FINEST); - logWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - logWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - logWriter.fine(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - logWriter.config(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - logWriter.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - logWriter.warning(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - logWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - logWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - - // ------------------------------------------------------------------------------------------- - // ERROR LEVEL - - distributionConfig.setLogLevel(LogWriterLevel.ERROR.getLogWriterLevel()); - - assertThat(distributionConfig.getLogLevel()) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.ERROR); - - message = createMessage(LogWriterLevel.FINEST); - logWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - logWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - logWriter.fine(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - logWriter.config(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - logWriter.info(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - logWriter.warning(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - logWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - logWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - } - - @Test - public void testDistributedSystemWithSecurityLogDefaultLevel() throws Exception { - Properties config = new Properties(); - config.put(LOG_FILE, logFileName); - config.put(LOG_LEVEL, "fine"); - config.put(SECURITY_LOG_FILE, securityLogFileName); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(config); - - await().untilAsserted(() -> { - assertThat(logFile).exists(); - assertThat(securityLogFile).exists(); - }); - - LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); - LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); - Logger geodeLogger = LogService.getLogger(); - - DistributionConfig distributionConfig = system.getConfig(); - - assertThat(distributionConfig.getLogLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(distributionConfig.getSecurityLogLevel()) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); - - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(securityLogWriter.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); - - String message = createMessage(LogWriterLevel.FINEST); - securityLogWriter.finest(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - securityLogWriter.fine(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - securityLogWriter.info(message); - assertThatFileContains(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - geodeLogger.debug(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileContains(logFile, message); - } - - @Test - public void testDistributedSystemWithSecurityLogFineLevel() throws Exception { - Properties config = new Properties(); - config.put(LOG_FILE, logFileName); - config.put(LOG_LEVEL, "fine"); - config.put(SECURITY_LOG_FILE, securityLogFileName); - config.put(SECURITY_LOG_LEVEL, "fine"); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(config); - - await().untilAsserted(() -> { - assertThat(logFile).exists(); - assertThat(securityLogFile).exists(); - }); - - LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); - LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); - Logger geodeLogger = LogService.getLogger(); - - DistributionConfig distributionConfig = system.getConfig(); - - assertThat(distributionConfig.getLogLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(distributionConfig.getSecurityLogLevel()) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(securityLogWriter.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); - - String message = createMessage(LogWriterLevel.FINEST); - securityLogWriter.finest(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - securityLogWriter.finer(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - securityLogWriter.fine(message); - assertThatFileContains(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - securityLogWriter.config(message); - assertThatFileContains(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - securityLogWriter.info(message); - assertThatFileContains(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - securityLogWriter.warning(message); - assertThatFileContains(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - securityLogWriter.error(message); - assertThatFileContains(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - securityLogWriter.severe(message); - assertThatFileContains(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileDoesNotContain(securityLogFile, message); - assertThatFileContains(logFile, message); - } - - /** - * tests scenario where security log has not been set but a level has been set to a less granular - * level than that of the regular log. Verifies that the correct logs for security show up in the - * regular log as expected - */ - @Test - public void testDistributedSystemWithSecurityInfoLevelAndLogAtFineLevelButNoSecurityLog() - throws Exception { - Properties CONFIG = new Properties(); - CONFIG.put(LOG_FILE, logFileName); - CONFIG.put(LOG_LEVEL, "fine"); - CONFIG.put(SECURITY_LOG_LEVEL, "info"); - CONFIG.put(MCAST_PORT, "0"); - CONFIG.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(CONFIG); - - await().untilAsserted(() -> assertThat(logFile).exists()); - - LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); - LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); - Logger geodeLogger = LogService.getLogger(); - - DistributionConfig distributionConfig = system.getConfig(); - - assertThat(distributionConfig.getLogLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(distributionConfig.getSecurityLogLevel()) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(securityLogWriter.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); - - String message = createMessage(LogWriterLevel.FINEST); - securityLogWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - securityLogWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - securityLogWriter.fine(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - securityLogWriter.config(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - securityLogWriter.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - securityLogWriter.warning(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - securityLogWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - securityLogWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - } - - /** - * tests scenario where security log has not been set but a level has been set to a more granular - * level than that of the regular log. Verifies that the correct logs for security show up in the - * regular log as expected - */ - @Test - public void testDistributedSystemWithSecurityFineLevelAndLogAtInfoLevelButNoSecurityLog() - throws Exception { - Properties config = new Properties(); - config.put(LOG_FILE, logFileName); - config.put(LOG_LEVEL, "info"); - config.put(SECURITY_LOG_LEVEL, "fine"); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, ""); - - system = (InternalDistributedSystem) DistributedSystem.connect(config); - - await().untilAsserted(() -> assertThat(logFile).exists()); - - LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); - LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); - Logger geodeLogger = LogService.getLogger(); - - DistributionConfig distributionConfig = system.getConfig(); - - assertThat(distributionConfig.getLogLevel()).isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(distributionConfig.getSecurityLogLevel()) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - - assertThat(logWriter.getLogWriterLevel()).isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(securityLogWriter.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(geodeLogger.getLevel()).isEqualTo(Level.INFO); - - String message = createMessage(LogWriterLevel.FINEST); - securityLogWriter.finest(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINER); - securityLogWriter.finer(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(LogWriterLevel.FINE); - securityLogWriter.fine(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.CONFIG); - securityLogWriter.config(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.INFO); - securityLogWriter.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.WARNING); - securityLogWriter.warning(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.ERROR); - securityLogWriter.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(LogWriterLevel.SEVERE); - securityLogWriter.severe(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.TRACE); - geodeLogger.trace(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.DEBUG); - geodeLogger.debug(message); - assertThatFileDoesNotContain(logFile, message); - - message = createMessage(Level.INFO); - geodeLogger.info(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.WARN); - geodeLogger.warn(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.ERROR); - geodeLogger.error(message); - assertThatFileContains(logFile, message); - - message = createMessage(Level.FATAL); - geodeLogger.fatal(message); - assertThatFileContains(logFile, message); - } - - private String createMessage(LogWriterLevel logLevel) { - return prefix + logLevel.name() + " [" + COUNTER.incrementAndGet() + "]"; - } - - private String createMessage(Level level) { - return prefix + level.name() + " [" + COUNTER.incrementAndGet() + "]"; - } - - private void assertThatFileContains(final File file, final String string) - throws IOException { - try (Scanner scanner = new Scanner(file)) { - while (scanner.hasNextLine()) { - if (scanner.nextLine().trim().contains(string)) { - return; - } - } - } - - List lines = Files.readAllLines(file.toPath()); - fail("Expected file " + file.getAbsolutePath() + " to contain " + string + LINE_SEPARATOR - + "Actual: " + lines); - } - - private void assertThatFileDoesNotContain(final File file, final String string) - throws IOException { - boolean fail = false; - try (Scanner scanner = new Scanner(file)) { - while (scanner.hasNextLine()) { - if (scanner.nextLine().trim().contains(string)) { - fail = true; - break; - } - } - } - if (fail) { - List lines = Files.readAllLines(file.toPath()); - fail("Expected file " + file.getAbsolutePath() + " to not contain " + string + LINE_SEPARATOR - + "Actual: " + lines); - } - } -} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LocatorLogFileIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LocatorLogFileIntegrationTest.java deleted file mode 100644 index 89ac2a02854b..000000000000 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LocatorLogFileIntegrationTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.logging; - -import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION; -import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; -import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; -import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; -import static org.apache.geode.test.awaitility.GeodeAwaitility.await; -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.File; -import java.io.FileInputStream; -import java.util.Properties; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestName; - -import org.apache.geode.distributed.Locator; -import org.apache.geode.distributed.internal.DistributionConfig; -import org.apache.geode.distributed.internal.InternalDistributedSystem; -import org.apache.geode.internal.AvailablePort; -import org.apache.geode.internal.logging.log4j.LogWriterLogger; -import org.apache.geode.test.junit.categories.LoggingTest; - -/** - * Creates Locator and tests logging behavior at a high level. - */ -@Category(LoggingTest.class) -public class LocatorLogFileIntegrationTest { - - private File logFile; - private String logFileName; - private File securityLogFile; - - private int port; - private Locator locator; - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Rule - public TestName testName = new TestName(); - - @Before - public void setUp() { - logFile = new File(temporaryFolder.getRoot(), - testName.getMethodName() + "-system-" + System.currentTimeMillis() + ".log"); - logFileName = logFile.getAbsolutePath(); - - securityLogFile = new File(""); - - port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET); - } - - @After - public void tearDown() throws Exception { - if (locator != null) { - locator.stop(); - } - } - - @Test - public void testLocatorCreatesLogFile() throws Exception { - Properties config = new Properties(); - config.put(LOG_LEVEL, "config"); - config.put(MCAST_PORT, "0"); - config.put(LOCATORS, "localhost[" + port + "]"); - config.put(ENABLE_CLUSTER_CONFIGURATION, "false"); - - locator = Locator.startLocatorAndDS(port, logFile, config); - - InternalDistributedSystem system = (InternalDistributedSystem) locator.getDistributedSystem(); - - await().untilAsserted(() -> assertThat(logFile).exists()); - - // assertThat logFile is not empty - try (FileInputStream fis = new FileInputStream(logFile)) { - assertThat(fis.available()).isGreaterThan(0); - } - - DistributionConfig distributionConfig = system.getConfig(); - - assertThat(distributionConfig.getLogLevel()) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); - assertThat(distributionConfig.getSecurityLogLevel()) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); - - assertThat(distributionConfig.getLogFile().getAbsolutePath()).isEqualTo(logFileName); - assertThat(distributionConfig.getSecurityLogFile().getAbsolutePath()) - .isEqualTo(securityLogFile.getAbsolutePath()); - - assertThat(system.getLogWriter()).isInstanceOf(LogWriterLogger.class); - assertThat(system.getSecurityLogWriter()).isInstanceOf(LogWriterLogger.class); - - LogWriterLogger logWriterLogger = (LogWriterLogger) system.getLogWriter(); - LogWriterLogger securityLogWriterLogger = (LogWriterLogger) system.getSecurityLogWriter(); - - assertThat(logWriterLogger.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(securityLogWriterLogger.getLogWriterLevel()) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - - assertThat(securityLogFile).doesNotExist(); - } -} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithCacheIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithCacheIntegrationTest.java new file mode 100644 index 000000000000..81d1b34284e8 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithCacheIntegrationTest.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_LEVEL; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Properties; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for log level control using {@link DistributionConfig} with lifecycle of + * {@link Cache}. + */ +@Category(LoggingTest.class) +public class LogLevelChangesWithCacheIntegrationTest { + + private static final String APPLICATION_LOGGER_NAME = "com.application"; + + private InternalCache cache; + private Logger geodeLogger; + private Logger applicationLogger; + private InternalLogWriter mainLogWriter; + private InternalLogWriter securityLogWriter; + private DistributionConfig distributionConfig; + private LogConfig logConfig; + + @Before + public void setUp() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_LEVEL, "INFO"); + config.setProperty(SECURITY_LOG_LEVEL, "INFO"); + + cache = (InternalCache) new CacheFactory(config).create(); + InternalDistributedSystem system = cache.getInternalDistributedSystem(); + + distributionConfig = system.getConfig(); + logConfig = system.getLogConfig(); + + mainLogWriter = (InternalLogWriter) cache.getLogger(); + securityLogWriter = (InternalLogWriter) cache.getSecurityLogger(); + + geodeLogger = LogService.getLogger(); + applicationLogger = LogManager.getLogger(APPLICATION_LOGGER_NAME); + } + + @After + public void tearDown() throws Exception { + if (cache != null) { + cache.close(); + } + } + + @Test + public void mainLogWriterLogLevelIsInfo() { + assertThat(mainLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void securityLogWriterLogLevelIsInfo() { + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void changesMainLogWriterLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(mainLogWriter.getLogWriterLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void changesDistributionConfigLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void changesLogConfigLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(logConfig.getLogLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void doesNotChangeSecurityLogWriterLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void doesNotChangeDistributionConfigSecurityLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void doesNotChangeLogConfigSecurityLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void changesGeodeLoggerLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.WARN); + } + + @Test + public void doesNotChangeApplicationLoggerLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithDistributedSystemIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithDistributedSystemIntegrationTest.java new file mode 100644 index 000000000000..260c2cf6cc4c --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogLevelChangesWithDistributedSystemIntegrationTest.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_LEVEL; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Properties; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for log level control using {@link DistributionConfig} with lifecycle of + * {@link DistributedSystem}. + */ +@Category(LoggingTest.class) +public class LogLevelChangesWithDistributedSystemIntegrationTest { + + private static final String APPLICATION_LOGGER_NAME = "com.application"; + + private InternalDistributedSystem system; + private Logger geodeLogger; + private Logger applicationLogger; + private InternalLogWriter mainLogWriter; + private InternalLogWriter securityLogWriter; + private DistributionConfig distributionConfig; + private LogConfig logConfig; + + @Before + public void setUp() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_LEVEL, "INFO"); + config.setProperty(SECURITY_LOG_LEVEL, "INFO"); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + distributionConfig = system.getConfig(); + logConfig = system.getLogConfig(); + + mainLogWriter = (InternalLogWriter) system.getLogWriter(); + securityLogWriter = (InternalLogWriter) system.getSecurityLogWriter(); + + geodeLogger = LogService.getLogger(); + applicationLogger = LogManager.getLogger(APPLICATION_LOGGER_NAME); + } + + @After + public void tearDown() throws Exception { + if (system != null) { + system.disconnect(); + } + } + + @Test + public void distributionConfigLogLevelIsInfo() { + assertThat(distributionConfig.getLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void distributionConfigSecurityLogLevelIsInfo() { + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void logConfigLogLevelIsInfo() { + assertThat(logConfig.getLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void logConfigSecurityLogLevelIsInfo() { + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void mainLogWriterLevelIsInfo() { + assertThat(mainLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void securityLogWriterLevelIsInfo() { + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void changesMainLogWriterLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(mainLogWriter.getLogWriterLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void changesDistributionConfigLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void changesLogConfigLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(logConfig.getLogLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void doesNotChangeSecurityLogWriterLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void doesNotChangeDistributionConfigSecurityLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void doesNotChangeLogConfigSecurityLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void changesGeodeLoggerLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.WARN); + } + + @Test + public void doesNotChangeApplicationLoggerLogLevel() { + distributionConfig.setLogLevel(WARNING.intLevel()); + + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogServiceIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogServiceIntegrationTest.java deleted file mode 100755 index 33fbce538370..000000000000 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LogServiceIntegrationTest.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.logging; - -import static org.apache.geode.internal.logging.LogServiceIntegrationTestSupport.writeConfigFile; -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.File; -import java.net.URL; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.status.StatusLogger; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemErrRule; -import org.junit.contrib.java.lang.system.SystemOutRule; -import org.junit.experimental.categories.Category; -import org.junit.rules.ExternalResource; -import org.junit.rules.TemporaryFolder; - -import org.apache.geode.internal.logging.log4j.Configurator; -import org.apache.geode.test.junit.categories.LoggingTest; - -/** - * Integration tests for LogService and how it configures and uses log4j2 - */ -@Category(LoggingTest.class) -public class LogServiceIntegrationTest { - - private static final String DEFAULT_CONFIG_FILE_NAME = "log4j2.xml"; - private static final String CLI_CONFIG_FILE_NAME = "log4j2-cli.xml"; - - @Rule - public SystemErrRule systemErrRule = new SystemErrRule().enableLog(); - - @Rule - public SystemOutRule systemOutRule = new SystemOutRule().enableLog(); - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Rule - public ExternalResource externalResource = new ExternalResource() { - @Override - protected void before() { - beforeConfigFileProp = System.getProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY); - beforeLevel = StatusLogger.getLogger().getLevel(); - - System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY); - StatusLogger.getLogger().setLevel(Level.OFF); - - Configurator.shutdown(); - } - - @Override - protected void after() { - Configurator.shutdown(); - - System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY); - if (beforeConfigFileProp != null) { - System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, beforeConfigFileProp); - } - StatusLogger.getLogger().setLevel(beforeLevel); - - LogService.reconfigure(); - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isTrue(); - } - }; - - private String beforeConfigFileProp; - private Level beforeLevel; - - private URL defaultConfigUrl; - private URL cliConfigUrl; - - @Before - public void setUp() { - defaultConfigUrl = LogService.class.getResource(LogService.DEFAULT_CONFIG); - cliConfigUrl = LogService.class.getResource(LogService.CLI_CONFIG); - } - - @After - public void after() { - // if either of these fail then log4j2 probably logged a failure to stdout - assertThat(systemErrRule.getLog()).isEmpty(); - assertThat(systemOutRule.getLog()).isEmpty(); - } - - @Test - public void shouldPreferConfigurationFilePropertyIfSet() throws Exception { - File configFile = temporaryFolder.newFile(DEFAULT_CONFIG_FILE_NAME); - String configFileName = configFile.toURI().toString(); - System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, configFileName); - writeConfigFile(configFile, Level.DEBUG); - - LogService.reconfigure(); - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - assertThat(System.getProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY)) - .isEqualTo(configFileName); - assertThat(LogService.getLogger().getName()).isEqualTo(getClass().getName()); - } - - @Test - public void shouldUseDefaultConfigIfNotConfigured() { - LogService.reconfigure(); - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isTrue(); - assertThat(System.getProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY)) - .isNullOrEmpty(); - } - - @Test - public void defaultConfigShouldIncludeStdout() { - LogService.reconfigure(); - Logger rootLogger = (Logger) LogService.getRootLogger(); - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isTrue(); - assertThat(rootLogger.getAppenders().get(LogService.STDOUT)).isNotNull(); - } - - @Test - public void removeConsoleAppenderShouldRemoveStdout() { - LogService.reconfigure(); - Logger rootLogger = (Logger) LogService.getRootLogger(); - - LogService.removeConsoleAppender(); - - assertThat(rootLogger.getAppenders().get(LogService.STDOUT)).isNull(); - } - - @Test - public void restoreConsoleAppenderShouldRestoreStdout() { - LogService.reconfigure(); - Logger rootLogger = (Logger) LogService.getRootLogger(); - - LogService.removeConsoleAppender(); - - assertThat(rootLogger.getAppenders().get(LogService.STDOUT)).isNull(); - - LogService.restoreConsoleAppender(); - - assertThat(rootLogger.getAppenders().get(LogService.STDOUT)).isNotNull(); - } - - @Test - public void removeAndRestoreConsoleAppenderShouldAffectRootLogger() { - LogService.reconfigure(); - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isTrue(); - - Logger rootLogger = (Logger) LogService.getRootLogger(); - - // assert "Console" is present for ROOT - Appender appender = rootLogger.getAppenders().get(LogService.STDOUT); - assertThat(appender).isNotNull(); - - LogService.removeConsoleAppender(); - - // assert "Console" is not present for ROOT - appender = rootLogger.getAppenders().get(LogService.STDOUT); - assertThat(appender).isNull(); - - LogService.restoreConsoleAppender(); - - // assert "Console" is present for ROOT - appender = rootLogger.getAppenders().get(LogService.STDOUT); - assertThat(appender).isNotNull(); - } - - @Test - public void shouldNotUseDefaultConfigIfCliConfigSpecified() { - System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, - cliConfigUrl.toString()); - - LogService.reconfigure(); - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - assertThat(System.getProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY)) - .isEqualTo(cliConfigUrl.toString()); - assertThat(LogService.getLogger().getName()).isEqualTo(getClass().getName()); - } - - @Test - public void isUsingGemFireDefaultConfigShouldBeTrueIfDefaultConfig() { - System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, - defaultConfigUrl.toString()); - - assertThat(LogService.getConfiguration().getConfigurationSource().toString()) - .contains(DEFAULT_CONFIG_FILE_NAME); - assertThat(LogService.isUsingGemFireDefaultConfig()).isTrue(); - } - - @Test - public void isUsingGemFireDefaultConfigShouldBeFalseIfCliConfig() { - System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, - cliConfigUrl.toString()); - - assertThat(LogService.getConfiguration().getConfigurationSource().toString()) - .doesNotContain(DEFAULT_CONFIG_FILE_NAME); - assertThat(LogService.isUsingGemFireDefaultConfig()).isFalse(); - } - - @Test - public void shouldUseCliConfigIfCliConfigIsSpecifiedViaClasspath() { - System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, - "classpath:" + CLI_CONFIG_FILE_NAME); - - assertThat(LogService.getConfiguration().getConfigurationSource().toString()) - .contains(CLI_CONFIG_FILE_NAME); - assertThat(LogService.isUsingGemFireDefaultConfig()).isFalse(); - } -} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithDistributedSystemIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithDistributedSystemIntegrationTest.java new file mode 100755 index 000000000000..4880f5c27ece --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithDistributedSystemIntegrationTest.java @@ -0,0 +1,1597 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_FILE; +import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_LEVEL; +import static org.apache.geode.internal.logging.LogWriterLevel.CONFIG; +import static org.apache.geode.internal.logging.LogWriterLevel.ERROR; +import static org.apache.geode.internal.logging.LogWriterLevel.FINE; +import static org.apache.geode.internal.logging.LogWriterLevel.FINER; +import static org.apache.geode.internal.logging.LogWriterLevel.FINEST; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.internal.logging.LogWriterLevel.SEVERE; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.getLoggerConfig; +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.LogWriter; +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.logging.log4j.FastLogger; +import org.apache.geode.internal.logging.log4j.Log4jAgent; +import org.apache.geode.internal.logging.log4j.LogWriterLogger; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for logging with {@link InternalDistributedSystem} lifecycle. + */ +@Category(LoggingTest.class) +public class LoggingWithDistributedSystemIntegrationTest { + + private static final String APPLICATION_LOGGER_NAME = "com.application"; + private static final AtomicInteger COUNTER = new AtomicInteger(); + + private String currentWorkingDirPath; + private File mainLogFile; + private String mainLogFilePath; + private File securityLogFile; + private String securityLogFilePath; + private InternalDistributedSystem system; + private String prefix; + + private Logger geodeLogger; + private Logger applicationLogger; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() { + File currentWorkingDir = new File(""); + currentWorkingDirPath = currentWorkingDir.getAbsolutePath(); + + String name = testName.getMethodName(); + mainLogFile = new File(temporaryFolder.getRoot(), name + "-main.log"); + mainLogFilePath = mainLogFile.getAbsolutePath(); + securityLogFile = new File(temporaryFolder.getRoot(), name + "-security.log"); + securityLogFilePath = securityLogFile.getAbsolutePath(); + + prefix = "ExpectedStrings: " + testName.getMethodName() + " message logged at level "; + + geodeLogger = LogService.getLogger(); + applicationLogger = LogManager.getLogger(APPLICATION_LOGGER_NAME); + + Log4jAgent.updateLogLevel(Level.INFO, getLoggerConfig(applicationLogger)); + } + + @After + public void tearDown() throws Exception { + if (system != null) { + system.disconnect(); + } + } + + @Test + public void applicationLoggerLevelIsInfo() { + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + } + + @Test + public void defaultConfigForLogging() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + LogConfig logConfig = system.getLogConfig(); + + assertThat(logConfig.getName()).isEqualTo(""); + assertThat(logConfig.getLogFile().getAbsolutePath()).isEqualTo(currentWorkingDirPath); + assertThat(logConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(logConfig.getLogDiskSpaceLimit()).isEqualTo(0); + assertThat(logConfig.getLogFileSizeLimit()).isEqualTo(0); + assertThat(logConfig.getSecurityLogFile().getAbsolutePath()).isEqualTo(currentWorkingDirPath); + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(CONFIG.intLevel()); + } + + @Test + public void bothLogFilesConfigured() throws Exception { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(SECURITY_LOG_FILE, securityLogFilePath); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriterLogger = (LogWriterLogger) system.getLogWriter(); + LogWriterLogger securityLogWriterLogger = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> { + system.getLogWriter().info("log another line"); + + assertThat(mainLogFile).exists(); + assertThat(securityLogFile).exists(); + + // assertThat mainLogFile is not empty + try (FileInputStream fis = new FileInputStream(mainLogFile)) { + assertThat(fis.available()).isGreaterThan(0); + } + }); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(CONFIG.intLevel()); + + assertThat(distributionConfig.getLogFile().getAbsolutePath()).isEqualTo(mainLogFilePath); + assertThat(distributionConfig.getSecurityLogFile().getAbsolutePath()) + .isEqualTo(securityLogFilePath); + + assertThat(system.getLogWriter()).isInstanceOf(LogWriterLogger.class); + assertThat(system.getSecurityLogWriter()).isInstanceOf(LogWriterLogger.class); + + assertThat(logWriterLogger.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + assertThat(securityLogWriterLogger.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + securityLogWriterLogger.info("test: security log file created at info"); + + // assertThat securityLogFile is not empty + try (FileInputStream fis = new FileInputStream(securityLogFile)) { + assertThat(fis.available()).isGreaterThan(0); + } + + LogWriter logWriter = logWriterLogger; + assertThat(logWriter.finestEnabled()).isFalse(); + assertThat(logWriter.finerEnabled()).isFalse(); + assertThat(logWriter.fineEnabled()).isFalse(); + assertThat(logWriter.configEnabled()).isTrue(); + assertThat(logWriter.infoEnabled()).isTrue(); + assertThat(logWriter.warningEnabled()).isTrue(); + assertThat(logWriter.errorEnabled()).isTrue(); + assertThat(logWriter.severeEnabled()).isTrue(); + + FastLogger logWriterFastLogger = logWriterLogger; + assertThat(logWriterFastLogger.isDelegating()).isFalse(); + assertThat(logWriterFastLogger.isTraceEnabled()).isFalse(); + assertThat(logWriterFastLogger.isDebugEnabled()).isFalse(); + assertThat(logWriterFastLogger.isInfoEnabled()).isTrue(); + assertThat(logWriterFastLogger.isWarnEnabled()).isTrue(); + assertThat(logWriterFastLogger.isErrorEnabled()).isTrue(); + assertThat(logWriterFastLogger.isFatalEnabled()).isTrue(); + + LogWriter securityLogWriter = securityLogWriterLogger; + assertThat(securityLogWriter.finestEnabled()).isFalse(); + assertThat(securityLogWriter.finerEnabled()).isFalse(); + assertThat(securityLogWriter.fineEnabled()).isFalse(); + assertThat(securityLogWriter.configEnabled()).isTrue(); + assertThat(securityLogWriter.infoEnabled()).isTrue(); + assertThat(securityLogWriter.warningEnabled()).isTrue(); + assertThat(securityLogWriter.errorEnabled()).isTrue(); + assertThat(securityLogWriter.severeEnabled()).isTrue(); + + FastLogger securityLogWriterFastLogger = logWriterLogger; + assertThat(securityLogWriterFastLogger.isDelegating()).isFalse(); + assertThat(securityLogWriterFastLogger.isTraceEnabled()).isFalse(); + assertThat(securityLogWriterFastLogger.isDebugEnabled()).isFalse(); + assertThat(securityLogWriterFastLogger.isInfoEnabled()).isTrue(); + assertThat(securityLogWriterFastLogger.isWarnEnabled()).isTrue(); + assertThat(securityLogWriterFastLogger.isErrorEnabled()).isTrue(); + assertThat(securityLogWriterFastLogger.isFatalEnabled()).isTrue(); + } + + @Test + public void mainLogWriterLogsToMainLogFile() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // CONFIG level + + assertThat(distributionConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(logWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + String message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // FINE level + + distributionConfig.setLogLevel(FINE.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(logWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + + message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR level + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(logWriter.getLogWriterLevel()).isEqualTo(ERROR.intLevel()); + + message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void securityLogWriterLogsToMainLogFile() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // CONFIG level + + assertThat(distributionConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + String message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // FINE level + + distributionConfig.setLogLevel(FINE.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR level + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void geodeLoggerLogsToMainLogFile() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // CONFIG level + + assertThat(distributionConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.INFO); + + String message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // FINE level + + distributionConfig.setLogLevel(FINE.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); + + message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR level + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.ERROR); + + message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void applicationLoggerLogsToMainLogFile() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // CONFIG level + + assertThat(distributionConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + + String message = createMessage(Level.TRACE); + applicationLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + applicationLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + applicationLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + applicationLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + applicationLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + applicationLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // FINE level + + distributionConfig.setLogLevel(FINE.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + + message = createMessage(Level.TRACE); + applicationLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + applicationLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + applicationLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + applicationLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + applicationLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + applicationLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR level + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + + message = createMessage(Level.TRACE); + applicationLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + applicationLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + applicationLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + applicationLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + applicationLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + applicationLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void mainLogWriterLogsToMainLogFileWithMainLogLevelFine() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // FINE level + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(logWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + + String message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR level + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(logWriter.getLogWriterLevel()).isEqualTo(ERROR.intLevel()); + + message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void securityLogWriterLogsToMainLogFileWithMainLogLevelFine() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + String message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void geodeLoggerLogsToMainLogFileWithMainLogLevelFine() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // FINE level + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); + + String message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR level + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.ERROR); + + message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void mainLogWriterLogsToMainLogFileWithMainLogLevelDebug() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, Level.DEBUG.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // DEBUG LEVEL + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(logWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + + String message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR LEVEL + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(logWriter.getLogWriterLevel()).isEqualTo(ERROR.intLevel()); + + message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void securityLogWriterLogsToMainLogFileWithMainLogLevelDebug() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, Level.DEBUG.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + String message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void geodeLoggerLogsToMainLogFileWithMainLogLevelDebug() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, Level.DEBUG.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + // DEBUG LEVEL + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); + + String message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + // ERROR LEVEL + + distributionConfig.setLogLevel(ERROR.intLevel()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(ERROR.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.ERROR); + + message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void logsToDifferentLogFilesWithMainLogLevelFine() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + config.setProperty(SECURITY_LOG_FILE, securityLogFilePath); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); + LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> { + assertThat(mainLogFile).exists(); + assertThat(securityLogFile).exists(); + }); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(CONFIG.intLevel()); + + assertThat(logWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); + + String message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(securityLogFile).contains(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + geodeLogger.debug(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + @Test + public void logsToDifferentLogFilesWithBothLogLevelsFine() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + config.setProperty(SECURITY_LOG_FILE, securityLogFilePath); + config.setProperty(SECURITY_LOG_LEVEL, FINE.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); + LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> { + assertThat(mainLogFile).exists(); + assertThat(securityLogFile).exists(); + }); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(FINE.intLevel()); + + assertThat(logWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); + + String message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(securityLogFile).contains(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(securityLogFile).contains(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(securityLogFile).contains(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(securityLogFile).contains(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(securityLogFile).contains(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(securityLogFile).contains(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(securityLogFile).doesNotContain(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + /** + * tests scenario where security log has not been set but a level has been set to a less granular + * level than that of the regular log. Verifies that the correct logs for security show up in the + * regular log as expected + */ + @Test + public void mainLogWriterLogsToMainLogFileWithHigherSecurityLogLevel() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + config.setProperty(SECURITY_LOG_LEVEL, INFO.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + + assertThat(logWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + + String message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + /** + * tests scenario where security log has not been set but a level has been set to a less granular + * level than that of the regular log. Verifies that the correct logs for security show up in the + * regular log as expected + */ + @Test + public void securityLogWriterLogsToMainLogFileWithHigherSecurityLogLevel() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + config.setProperty(SECURITY_LOG_LEVEL, INFO.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + String message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + /** + * tests scenario where security log has not been set but a level has been set to a less granular + * level than that of the regular log. Verifies that the correct logs for security show up in the + * regular log as expected + */ + @Test + public void geodeLoggerLogsToMainLogFileWithHigherSecurityLogLevel() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, FINE.name()); + config.setProperty(SECURITY_LOG_LEVEL, INFO.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(FINE.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.DEBUG); + + String message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + /** + * tests scenario where security log has not been set but a level has been set to a more granular + * level than that of the regular log. Verifies that the correct logs for security show up in the + * regular log as expected + */ + @Test + public void mainLogWriterLogsToMainLogFileWithLowerSecurityLogLevel() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, INFO.name()); + config.setProperty(SECURITY_LOG_LEVEL, FINE.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger logWriter = (LogWriterLogger) system.getLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(INFO.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(FINE.intLevel()); + + assertThat(logWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + String message = createMessage(FINEST); + logWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + logWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + logWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(CONFIG); + logWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + logWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + logWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + logWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + logWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + /** + * tests scenario where security log has not been set but a level has been set to a more granular + * level than that of the regular log. Verifies that the correct logs for security show up in the + * regular log as expected + */ + @Test + public void securityLogWriterLogsToMainLogFileWithLowerSecurityLogLevel() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, INFO.name()); + config.setProperty(SECURITY_LOG_LEVEL, FINE.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + LogWriterLogger securityLogWriter = (LogWriterLogger) system.getSecurityLogWriter(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(INFO.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(FINE.intLevel()); + + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(FINE.intLevel()); + + String message = createMessage(FINEST); + securityLogWriter.finest(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINER); + securityLogWriter.finer(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(FINE); + securityLogWriter.fine(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(CONFIG); + securityLogWriter.config(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(INFO); + securityLogWriter.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(WARNING); + securityLogWriter.warning(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(ERROR); + securityLogWriter.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(SEVERE); + securityLogWriter.severe(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + /** + * tests scenario where security log has not been set but a level has been set to a more granular + * level than that of the regular log. Verifies that the correct logs for security show up in the + * regular log as expected + */ + @Test + public void geodeLoggerLogsToMainLogFileWithLowerSecurityLogLevel() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFilePath); + config.setProperty(LOG_LEVEL, INFO.name()); + config.setProperty(SECURITY_LOG_LEVEL, FINE.name()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + DistributionConfig distributionConfig = system.getConfig(); + + await().untilAsserted(() -> assertThat(mainLogFile).exists()); + + assertThat(distributionConfig.getLogLevel()).isEqualTo(INFO.intLevel()); + assertThat(distributionConfig.getSecurityLogLevel()).isEqualTo(FINE.intLevel()); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.INFO); + + String message = createMessage(Level.TRACE); + geodeLogger.trace(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.DEBUG); + geodeLogger.debug(message); + LogFileAssert.assertThat(mainLogFile).doesNotContain(message); + + message = createMessage(Level.INFO); + geodeLogger.info(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.WARN); + geodeLogger.warn(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.ERROR); + geodeLogger.error(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + + message = createMessage(Level.FATAL); + geodeLogger.fatal(message); + LogFileAssert.assertThat(mainLogFile).contains(message); + } + + private String createMessage(LogWriterLevel logLevel) { + return prefix + logLevel.name() + " [" + COUNTER.incrementAndGet() + "]"; + } + + private String createMessage(Level level) { + return prefix + level.name() + " [" + COUNTER.incrementAndGet() + "]"; + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorIntegrationTest.java new file mode 100644 index 000000000000..cd1ed3546969 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorIntegrationTest.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.distributed.ConfigurationProperties.NAME; +import static org.apache.geode.internal.logging.LogWriterLevel.CONFIG; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.distributed.Locator; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.distributed.internal.InternalLocator; +import org.apache.geode.internal.AvailablePort; +import org.apache.geode.internal.logging.log4j.LogWriterLogger; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for logging with {@link InternalLocator} lifecycle. + */ +@Category(LoggingTest.class) +public class LoggingWithLocatorIntegrationTest { + + private String name; + private int port; + private String currentWorkingDirPath; + private File logFile; + private File securityLogFile; + + private InternalLocator locator; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() throws Exception { + name = testName.getMethodName(); + + File currentWorkingDir = new File(""); + currentWorkingDirPath = currentWorkingDir.getAbsolutePath(); + logFile = new File(temporaryFolder.getRoot(), + testName.getMethodName() + "-system-" + System.currentTimeMillis() + ".log"); + securityLogFile = new File(""); + + port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET); + } + + @After + public void tearDown() { + if (locator != null) { + locator.stop(); + } + } + + @Test + public void startLocatorDefaultLoggingConfig() throws Exception { + Properties config = new Properties(); + + locator = InternalLocator.startLocator(port, null, null, null, null, false, config, null); + + LogConfig logConfig = locator.getLogConfig(); + + assertThat(logConfig.getName()).isEqualTo(""); + assertThat(logConfig.getLogFile().getAbsolutePath()).isEqualTo(currentWorkingDirPath); + assertThat(logConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(logConfig.getLogDiskSpaceLimit()).isEqualTo(0); + assertThat(logConfig.getLogFileSizeLimit()).isEqualTo(0); + assertThat(logConfig.getSecurityLogFile().getAbsolutePath()) + .isEqualTo(currentWorkingDirPath); + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(CONFIG.intLevel()); + } + + @Test + public void startLocatorDefaultLoggingConfigWithLogFile() throws Exception { + Properties config = new Properties(); + + locator = InternalLocator.startLocator(port, logFile, null, null, null, false, config, null); + + LogConfig logConfig = locator.getLogConfig(); + + assertThat(logConfig.getName()).isEqualTo(""); + assertThat(logConfig.getLogFile().getAbsolutePath()).isEqualTo(logFile.getAbsolutePath()); + assertThat(logConfig.getLogLevel()).isEqualTo(CONFIG.intLevel()); + assertThat(logConfig.getLogDiskSpaceLimit()).isEqualTo(0); + assertThat(logConfig.getLogFileSizeLimit()).isEqualTo(0); + assertThat(logConfig.getSecurityLogFile().getAbsolutePath()) + .isEqualTo(currentWorkingDirPath); + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(CONFIG.intLevel()); + } + + @Test + public void startLocatorAndDSCreatesLogFile() throws Exception { + Properties config = new Properties(); + config.setProperty(LOCATORS, "localhost[" + port + "]"); + config.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false"); + + locator = (InternalLocator) Locator.startLocatorAndDS(port, logFile, config); + + await().untilAsserted(() -> assertThat(logFile).exists()); + + // assertThat logFile is not empty + try (FileInputStream fis = new FileInputStream(logFile)) { + assertThat(fis.available()).isGreaterThan(0); + } + + InternalDistributedSystem system = (InternalDistributedSystem) locator.getDistributedSystem(); + + assertThat(system.getLogWriter()).isInstanceOf(LogWriterLogger.class); + assertThat(system.getSecurityLogWriter()).isInstanceOf(LogWriterLogger.class); + + LogWriterLogger logWriterLogger = (LogWriterLogger) system.getLogWriter(); + LogWriterLogger securityLogWriterLogger = (LogWriterLogger) system.getSecurityLogWriter(); + + assertThat(logWriterLogger.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + assertThat(securityLogWriterLogger.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + DistributionConfig distributionConfig = system.getConfig(); + + assertThat(distributionConfig.getLogFile().getAbsolutePath()) + .isEqualTo(logFile.getAbsolutePath()); + assertThat(distributionConfig.getSecurityLogFile().getAbsolutePath()) + .isEqualTo(currentWorkingDirPath); + + assertThat(securityLogFile).doesNotExist(); + } + + @Test + public void locatorWithNoDS() throws Exception { + Properties config = new Properties(); + config.setProperty(NAME, name); + config.setProperty(LOG_FILE, logFile.getAbsolutePath()); + config.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false"); + + locator = InternalLocator.startLocator(port, null, null, null, null, false, config, null); + Logger logger = LogService.getLogger(); + + // assert that logging goes to logFile + String logMessageBeforeClose = "Logging before locator is stopped in " + name; + logger.info(logMessageBeforeClose); + + LogFileAssert.assertThat(logFile).contains(logMessageBeforeClose); + + locator.stop(); + + // assert that logging stops going to logFile + String logMessageAfterClose = "Logging after locator is stopped in " + name; + logger.info(logMessageAfterClose); + LogFileAssert.assertThat(logFile).doesNotContain(logMessageAfterClose); + } + + @Test + public void locatorWithDS() throws Exception { + Properties config = new Properties(); + config.setProperty(NAME, name); + config.setProperty(LOG_FILE, logFile.getAbsolutePath()); + config.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false"); + + locator = (InternalLocator) InternalLocator.startLocatorAndDS(port, null, config); + Logger logger = LogService.getLogger(); + + // assert that logging goes to logFile + String logMessageBeforeClose = "Logging before locator is stopped in " + name; + logger.info(logMessageBeforeClose); + + LogFileAssert.assertThat(logFile).contains(logMessageBeforeClose); + + locator.stop(); + + // assert that logging stops going to logFile + String logMessageAfterClose = "Logging after locator is stopped in " + name; + logger.info(logMessageAfterClose); + LogFileAssert.assertThat(logFile).doesNotContain(logMessageAfterClose); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorLauncherIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorLauncherIntegrationTest.java new file mode 100644 index 000000000000..50d318ade3ba --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithLocatorLauncherIntegrationTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.Banner.BannerHeader.displayValues; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.distributed.LocatorLauncher; +import org.apache.geode.distributed.LocatorLauncherIntegrationTestCase; +import org.apache.geode.internal.process.ProcessControllerFactory; +import org.apache.geode.internal.process.ProcessType; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests of logging with {@link LocatorLauncher}. + */ +@Category(LoggingTest.class) +public class LoggingWithLocatorLauncherIntegrationTest extends LocatorLauncherIntegrationTestCase { + + @Before + public void setUp() throws Exception { + System.setProperty(ProcessType.PROPERTY_TEST_PREFIX, getUniqueName() + "-"); + assertThat(new ProcessControllerFactory().isAttachAPIFound()).isTrue(); + + givenRunningLocator(); + } + + @After + public void tearDown() throws Exception { + disconnectFromDS(); + } + + @Test + public void logFileExists() { + assertThat(getLogFile()).exists(); + } + + @Test + public void logFileContainsBanner() { + LogFileAssert.assertThat(getLogFile()).contains(displayValues()); + } + + @Test + public void logFileContainsBannerOnlyOnce() { + LogFileAssert.assertThat(getLogFile()).containsOnlyOnce(displayValues()); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithServerLauncherIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithServerLauncherIntegrationTest.java new file mode 100644 index 000000000000..182e1c4e000d --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/LoggingWithServerLauncherIntegrationTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.Banner.BannerHeader.displayValues; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.distributed.ServerLauncher; +import org.apache.geode.distributed.ServerLauncherIntegrationTestCase; +import org.apache.geode.internal.process.ProcessControllerFactory; +import org.apache.geode.internal.process.ProcessType; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests of logging with {@link ServerLauncher}. + */ +@Category(LoggingTest.class) +public class LoggingWithServerLauncherIntegrationTest extends ServerLauncherIntegrationTestCase { + + @Before + public void setUp() throws Exception { + System.setProperty(ProcessType.PROPERTY_TEST_PREFIX, getUniqueName() + "-"); + assertThat(new ProcessControllerFactory().isAttachAPIFound()).isTrue(); + + givenRunningServer(); + } + + @After + public void tearDown() throws Exception { + disconnectFromDS(); + } + + @Test + public void logFileExists() { + assertThat(getLogFile()).exists(); + } + + @Test + public void logFileContainsBanner() { + LogFileAssert.assertThat(getLogFile()).contains(displayValues()); + } + + @Test + public void logFileContainsBannerOnlyOnce() { + LogFileAssert.assertThat(getLogFile()).containsOnlyOnce(displayValues()); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ManagerLogWriterFactoryIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ManagerLogWriterFactoryIntegrationTest.java new file mode 100644 index 000000000000..d7264f446691 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/ManagerLogWriterFactoryIntegrationTest.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.LogWriterLevel.FINE; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.internal.statistics.StatisticsConfig; + +/** + * Integration tests for {@link ManagerLogWriterFactory}. + */ +public class ManagerLogWriterFactoryIntegrationTest { + + private File mainLogFile; + private String mainLogFilePath; + private File securityLogFile; + private String securityLogFilePath; + private LogConfig mainLogConfig; + private LogConfig securityLogConfig; + private StatisticsConfig statisticsConfig; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() { + String name = getClass().getSimpleName() + "_" + testName.getMethodName(); + + mainLogFile = new File(temporaryFolder.getRoot(), name + "-main.log"); + mainLogFilePath = mainLogFile.getAbsolutePath(); + + securityLogFile = new File(temporaryFolder.getRoot(), name + "-security.log"); + securityLogFilePath = securityLogFile.getAbsolutePath(); + + mainLogConfig = mock(LogConfig.class); + securityLogConfig = mock(LogConfig.class); + statisticsConfig = mock(StatisticsConfig.class); + + when(mainLogConfig.getLogFile()).thenReturn(mainLogFile); + when(mainLogConfig.getLogLevel()).thenReturn(FINE.intLevel()); + + when(securityLogConfig.getLogFile()).thenReturn(mainLogFile); + when(securityLogConfig.getLogLevel()).thenReturn(FINE.intLevel()); + when(securityLogConfig.getSecurityLogFile()).thenReturn(securityLogFile); + when(securityLogConfig.getSecurityLogLevel()).thenReturn(WARNING.intLevel()); + } + + @Test + public void getLogFileReturnsMainLogFileIfSecurityIsFalse() { + File logFile = new ManagerLogWriterFactory().setSecurity(false).getLogFile(mainLogConfig); + + assertThat(logFile.getAbsolutePath()).isEqualTo(mainLogFilePath); + } + + @Test + public void getLogFileReturnsSecurityLogFileIfSecurityIsTrue() { + File logFile = new ManagerLogWriterFactory().setSecurity(true).getLogFile(securityLogConfig); + + assertThat(logFile.getAbsolutePath()).isEqualTo(securityLogFilePath); + } + + @Test + public void getLogLevelReturnsMainLogLevelIfSecurityIsFalse() { + int level = new ManagerLogWriterFactory().setSecurity(false).getLogLevel(mainLogConfig); + + assertThat(level).isEqualTo(FINE.intLevel()); + } + + @Test + public void getLogLevelReturnsSecurityLogLevelIfSecurityIsTrue() { + int level = new ManagerLogWriterFactory().setSecurity(true).getLogLevel(securityLogConfig); + + assertThat(level).isEqualTo(WARNING.intLevel()); + } + + @Test + public void createReturnsManagerLogWriterIfSecurityIsFalse() { + ManagerLogWriter logWriter = + new ManagerLogWriterFactory().setSecurity(false).create(mainLogConfig, statisticsConfig); + + assertThat(logWriter).isNotInstanceOf(SecurityManagerLogWriter.class); + } + + @Test + public void createUsesMainLogFileIfSecurityIsFalse() { + new ManagerLogWriterFactory().setSecurity(false).create(mainLogConfig, statisticsConfig); + + assertThat(mainLogFile).exists(); + assertThat(securityLogFile).doesNotExist(); + } + + @Test + public void createReturnsSecurityManagerLogWriterIfSecurityIsTrue() { + ManagerLogWriter logWriter = + new ManagerLogWriterFactory().setSecurity(true).create(securityLogConfig, statisticsConfig); + + assertThat(logWriter).isInstanceOf(SecurityManagerLogWriter.class); + } + + @Test + public void createUsesSecurityLogFileIfSecurityIsTrue() { + new ManagerLogWriterFactory().setSecurity(true).create(securityLogConfig, statisticsConfig); + + assertThat(mainLogFile).doesNotExist(); + assertThat(securityLogFile).exists(); + } + + @Test + public void createSetsConfigOnLogWriterIfSecurityIsFalse() { + ManagerLogWriter logWriter = + new ManagerLogWriterFactory().setSecurity(false).create(mainLogConfig, statisticsConfig); + + assertThat(logWriter.getConfig()).isNotNull(); + assertThat(logWriter.getConfig().getLogFile().getAbsolutePath()).isSameAs(mainLogFilePath); + } + + @Test + public void createSetsConfigWithSecurityLogFileIfSecurityIsTrue() { + ManagerLogWriter logWriter = + new ManagerLogWriterFactory().setSecurity(true).create(securityLogConfig, statisticsConfig); + + assertThat(logWriter.getConfig()).isNotNull().isInstanceOf(SecurityLogConfig.class); + assertThat(logWriter.getConfig().getLogFile().getAbsolutePath()).isSameAs(securityLogFilePath); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/NonBlankStrings.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/NonBlankStrings.java new file mode 100644 index 000000000000..d215caf2cfc9 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/NonBlankStrings.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +import java.util.List; +import java.util.stream.Collectors; + +public class NonBlankStrings { + + public static List nonBlankStrings(List values) { + return values.stream().filter(s -> isNotBlank(s)).collect(Collectors.toList()); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/StartupConfigurationLoggingIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/StartupConfigurationLoggingIntegrationTest.java new file mode 100644 index 000000000000..e76b0a09c0a6 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/StartupConfigurationLoggingIntegrationTest.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static java.lang.System.lineSeparator; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.distributed.ConfigurationProperties.NAME; +import static org.apache.geode.internal.logging.Configuration.STARTUP_CONFIGURATION; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.Banner; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for logging of the startup configuration. Startup configuration consists of + * {@link Configuration#STARTUP_CONFIGURATION} and {@link DistributionConfig#toLoggerString()}. + */ +@Category(LoggingTest.class) +public class StartupConfigurationLoggingIntegrationTest { + + private File mainLogFile; + private InternalDistributedSystem system; + private String banner; + private String[] startupConfiguration; + private Logger geodeLogger; + private String logMessage; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() { + String name = testName.getMethodName(); + mainLogFile = new File(temporaryFolder.getRoot(), name + "-main.log"); + + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFile.getAbsolutePath()); + config.setProperty(NAME, getClass().getSimpleName() + "_" + testName.getMethodName()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + banner = Banner.getString(null); + + DistributionConfig distributionConfig = system.getConfig(); + startupConfiguration = StringUtils + .split(STARTUP_CONFIGURATION + distributionConfig.toLoggerString(), lineSeparator()); + + geodeLogger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + } + + @After + public void tearDown() throws Exception { + if (system != null) { + system.disconnect(); + } + } + + @Test + public void startupConfigurationIsLoggedToFile() { + LogFileAssert.assertThat(mainLogFile).contains(startupConfiguration); + } + + @Test + public void startupConfigurationIsLoggedToFileOnlyOnce() { + LogFileAssert.assertThat(mainLogFile).containsOnlyOnce(startupConfiguration); + } + + @Test + public void startupConfigurationIsLoggedToFileAfterBanner() throws Exception { + List bannerLines = Arrays.asList(StringUtils.split(banner, lineSeparator())); + List startupConfigLines = Arrays.asList(startupConfiguration); + List logLines = FileUtils.readLines(mainLogFile, Charset.defaultCharset()); + + boolean foundBanner = false; + boolean foundStartupConfig = false; + + for (String line : logLines) { + if (bannerLines.contains(line)) { + assertThat(foundStartupConfig) + .as("Banner should be logged before startup configuration: " + logLines).isFalse(); + foundBanner = true; + } + if (startupConfigLines.contains(line)) { + assertThat(foundBanner) + .as("Startup configuration should be logged before banner: " + logLines).isTrue(); + foundStartupConfig = true; + } + } + + assertThat(foundBanner).as("Banner not found in: " + logLines).isTrue(); + assertThat(foundStartupConfig).as("Startup configuration not found in: " + logLines).isTrue(); + } + + @Test + public void startupConfigurationIsLoggedToFileBeforeLogMessage() throws Exception { + geodeLogger.info(logMessage); + + List startupConfigLines = Arrays.asList(startupConfiguration); + List logLines = FileUtils.readLines(mainLogFile, Charset.defaultCharset()); + + boolean foundStartupConfig = false; + boolean foundLogMessage = false; + + for (String line : logLines) { + if (startupConfigLines.contains(line)) { + assertThat(foundLogMessage) + .as("Startup configuration should be before log message: " + logLines).isFalse(); + foundStartupConfig = true; + } + if (line.contains(logMessage)) { + assertThat(foundStartupConfig) + .as("Log message should be after startup configuration: " + logLines).isTrue(); + foundLogMessage = true; + } + } + + assertThat(foundStartupConfig).as("Startup configuration not found in: " + logLines).isTrue(); + assertThat(foundLogMessage).as("Log message not found in: " + logLines).isTrue(); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/SystemOutRuleAndSystemErrRuleIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/SystemOutRuleAndSystemErrRuleIntegrationTest.java new file mode 100644 index 000000000000..aded0b439e5e --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/SystemOutRuleAndSystemErrRuleIntegrationTest.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.PrintStream; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.SystemErrRule; +import org.junit.contrib.java.lang.system.SystemOutRule; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Verifies behavior of {@code SystemOutRule} and {@code SystemErrRule} that other Geode logging + * tests depend on. If this behavior changes, then those tests may also need to change. + */ +@Category(LoggingTest.class) +public class SystemOutRuleAndSystemErrRuleIntegrationTest { + + private static PrintStream systemOutBeforeRule; + private static PrintStream systemErrBeforeRule; + + private PrintStream systemOutAfterRule; + private PrintStream systemErrAfterRule; + private String message; + + @Rule + public SystemOutRule systemOutRule = new SystemOutRule().enableLog(); + + @Rule + public SystemErrRule systemErrRule = new SystemErrRule().enableLog(); + + @BeforeClass + public static void beforeClass() { + systemOutBeforeRule = System.out; + systemErrBeforeRule = System.err; + } + + @Before + public void setUp() { + systemOutAfterRule = System.out; + systemErrAfterRule = System.err; + message = "simple message"; + } + + @AfterClass + public static void afterClass() { + systemOutBeforeRule = null; + systemErrBeforeRule = null; + } + + @Test + public void ruleDoesNotReceiveFromSystemOutBeforeRule() { + systemOutBeforeRule.println(message); + + assertThat(systemOutRule.getLog()).doesNotContain(message); + } + + @Test + public void ruleDoesReceiveFromSystemOutAfterRule() { + systemOutAfterRule.println(message); + + assertThat(systemOutRule.getLog()).contains(message); + } + + @Test + public void ruleDoesNotReceiveFromSystemErrBeforeRule() { + systemErrBeforeRule.println(message); + + assertThat(systemErrRule.getLog()).doesNotContain(message); + } + + @Test + public void ruleDoesReceiveFromSystemErrAfterRule() { + systemErrAfterRule.println(message); + + assertThat(systemErrRule.getLog()).contains(message); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest.java new file mode 100644 index 000000000000..b0d55d225bd9 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.internal.logging.Configuration.MAIN_LOGGER_NAME; +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.net.URL; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.SessionContext; +import org.apache.geode.internal.statistics.StatisticsConfig; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; +import org.apache.geode.test.junit.categories.SecurityTest; + +/** + * Integration tests for main and security {@link LogWriterAppender}s, loggers, and + * {@link ConfigurationProperties#LOG_FILE} and {@link ConfigurationProperties#SECURITY_LOG_FILE}. + */ +@Category({LoggingTest.class, SecurityTest.class}) +public class BothLogWriterAppendersIntegrationTest { + + private static final String CONFIG_FILE_NAME = "BothLogWriterAppendersIntegrationTest_log4j2.xml"; + private static final String MAIN_APPENDER_NAME = "LOGWRITER"; + private static final String SECURITY_APPENDER_NAME = "SECURITYLOGWRITER"; + + private static String configFilePath; + + private File securityLogFile; + private Logger mainGeodeLogger; + private Logger securityGeodeLogger; + private String logMessage; + private LogWriterAppender mainLogWriterAppender; + private LogWriterAppender securityLogWriterAppender; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + String name = testName.getMethodName(); + File mainLogFile = new File(temporaryFolder.getRoot(), name + ".log"); + securityLogFile = new File(temporaryFolder.getRoot(), name + "-security.log"); + + LogConfig logConfig = mock(LogConfig.class); + when(logConfig.getName()).thenReturn(name); + when(logConfig.getLogFile()).thenReturn(mainLogFile); + when(logConfig.getSecurityLogFile()).thenReturn(securityLogFile); + + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(logConfig); + when(logConfigSupplier.getStatisticsConfig()).thenReturn(mock(StatisticsConfig.class)); + + SessionContext sessionContext = mock(SessionContext.class); + when(sessionContext.getLogConfigSupplier()).thenReturn(logConfigSupplier); + + mainGeodeLogger = LogService.getLogger(MAIN_LOGGER_NAME); + securityGeodeLogger = LogService.getLogger(SECURITY_LOGGER_NAME); + + logMessage = "Logging in " + testName.getMethodName(); + + mainLogWriterAppender = loggerContextRule.getAppender(MAIN_APPENDER_NAME, + LogWriterAppender.class); + securityLogWriterAppender = loggerContextRule.getAppender(SECURITY_APPENDER_NAME, + LogWriterAppender.class); + + mainLogWriterAppender.createSession(sessionContext); + mainLogWriterAppender.startSession(); + mainLogWriterAppender.clearLogEvents(); + + securityLogWriterAppender.createSession(sessionContext); + securityLogWriterAppender.startSession(); + securityLogWriterAppender.clearLogEvents(); + } + + @After + public void tearDown() throws Exception { + mainLogWriterAppender.stopSession(); + securityLogWriterAppender.stopSession(); + } + + @Test + public void mainLogWriterAppenderLogEventsIsEmptyByDefault() { + assertThat(mainLogWriterAppender.getLogEvents()).isEmpty(); + } + + @Test + public void securityLogWriterAppenderLogEventsIsEmptyByDefault() { + assertThat(securityLogWriterAppender.getLogEvents()).isEmpty(); + } + + @Test + public void geodeLoggerAppendsToLogWriterAppender() { + mainGeodeLogger.info(logMessage); + + assertThat(mainLogWriterAppender.getLogEvents()).hasSize(1); + } + + @Test + public void geodeLoggerDoesNotAppendToSecurityLogWriterAppender() { + mainGeodeLogger.info(logMessage); + + assertThat(securityLogWriterAppender.getLogEvents()).isEmpty(); + } + + @Test + public void geodeSecurityLoggerAppendsToSecurityLogWriterAppender() { + securityGeodeLogger.info(logMessage); + + assertThat(securityLogWriterAppender.getLogEvents()).hasSize(1); + } + + @Test + public void geodeSecurityLoggerDoesNotAppendToLogWriterAppender() { + securityGeodeLogger.info(logMessage); + + assertThat(mainLogWriterAppender.getLogEvents()).isEmpty(); + } + + @Test + public void securityGeodeLoggerLogsToSecurityLogFile() { + securityGeodeLogger.info(logMessage); + + LogFileAssert.assertThat(securityLogFile).exists().contains(logMessage); + } + + @Test + public void securityGeodeLoggerDoesNotLogToMainLogFile() { + securityGeodeLogger.info(logMessage); + + assertThat(mainLogWriterAppender.getLogEvents()).isEmpty(); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CustomConfigWithCacheIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CacheWithCustomLogConfigIntegrationTest.java similarity index 62% rename from geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CustomConfigWithCacheIntegrationTest.java rename to geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CacheWithCustomLogConfigIntegrationTest.java index bf9e9d981814..e95927689366 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CustomConfigWithCacheIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CacheWithCustomLogConfigIntegrationTest.java @@ -17,6 +17,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; import static org.apache.geode.test.util.ResourceUtils.getResource; import static org.assertj.core.api.Assertions.assertThat; @@ -27,6 +28,7 @@ import java.util.regex.Pattern; import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.test.appender.ListAppender; @@ -40,6 +42,7 @@ import org.junit.contrib.java.lang.system.SystemOutRule; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheFactory; @@ -47,11 +50,13 @@ import org.apache.geode.test.junit.categories.LoggingTest; /** - * Integration tests with custom log4j2 configuration. + * Integration tests for {@link Cache} with custom {@code log4j2.xml}. */ @Category(LoggingTest.class) -public class CustomConfigWithCacheIntegrationTest { +public class CacheWithCustomLogConfigIntegrationTest { + private static final String CONFIG_FILE_NAME = + "CacheWithCustomLogConfigIntegrationTest_log4j2.xml"; private static final String CONFIG_LAYOUT_PREFIX = "CUSTOM"; private static final String CUSTOM_REGEX_STRING = "CUSTOM: level=[A-Z]+ time=\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3} [^ ]{3} message=.*[\\n]+throwable=.*$"; @@ -59,11 +64,12 @@ public class CustomConfigWithCacheIntegrationTest { private static String configFilePath; - private LogWriterLogger logWriterLogger; - private String logMessage; - private ListAppender listAppender; - private Cache cache; + private Logger geodeLogger; + private Logger logger; + private String infoMessage; + private String warnMessage; + private ListAppender listAppender; @ClassRule public static SystemOutRule systemOutRule = new SystemOutRule().enableLog(); @@ -77,12 +83,13 @@ public class CustomConfigWithCacheIntegrationTest { @Rule public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + @Rule + public TestName testName = new TestName(); + @BeforeClass public static void setUpLogConfigFile() throws Exception { - String configFileName = - CustomConfigWithCacheIntegrationTest.class.getSimpleName() + "_log4j2.xml"; - URL resource = getResource(configFileName); - configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), configFileName) + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) .getAbsolutePath(); } @@ -91,16 +98,14 @@ public void setUp() throws Exception { Properties config = new Properties(); config.setProperty(LOCATORS, ""); config.setProperty(MCAST_PORT, "0"); - config.setProperty(LOG_LEVEL, "info"); + config.setProperty(LOG_LEVEL, INFO.name()); cache = new CacheFactory(config).create(); - logWriterLogger = (LogWriterLogger) cache.getLogger(); - logMessage = "this is a log statement"; - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - + geodeLogger = (LogWriterLogger) cache.getLogger(); + logger = LogService.getLogger(); + infoMessage = "INFO in " + testName.getMethodName(); + warnMessage = "WARN in " + testName.getMethodName(); listAppender = loggerContextRule.getListAppender("CUSTOM"); systemOutRule.clearLog(); @@ -109,27 +114,59 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { - if (cache != null) { - cache.close(); - } + cache.close(); } @Test - public void cacheLogWriterMessageShouldMatchCustomConfig() { - logWriterLogger.info(logMessage); - - LogEvent logEvent = findLogEventContaining(logMessage); - - assertThat(logEvent.getLoggerName()).isEqualTo(logWriterLogger.getName()); - assertThat(logEvent.getLevel()).isEqualTo(Level.INFO); - assertThat(logEvent.getMessage().getFormattedMessage()).isEqualTo(logMessage); + public void loggedMessageShouldMatchCustomLayout() { + geodeLogger.warn(warnMessage); - assertThat(systemOutRule.getLog()).contains(Level.INFO.name()); - assertThat(systemOutRule.getLog()).contains(logMessage); + assertThat(systemOutRule.getLog()).contains(Level.WARN.name()); + assertThat(systemOutRule.getLog()).contains(warnMessage); assertThat(systemOutRule.getLog()).contains(CONFIG_LAYOUT_PREFIX); assertThat(CUSTOM_REGEX.matcher(systemOutRule.getLog()).matches()).isTrue(); } + @Test + public void cacheLogWriterInfoMessageIsSuppressed() { + geodeLogger.info(infoMessage); + + assertThat(findLogEventContaining(infoMessage)).as(logEventContaining(infoMessage)).isNull(); + } + + @Test + public void cacheLogWriterWarnMessageIsLogged() { + geodeLogger.warn(warnMessage); + + LogEvent logEvent = findLogEventContaining(warnMessage); + assertThat(logEvent).as(logEventContaining(warnMessage)).isNotNull(); + assertThat(logEvent.getLoggerName()).isEqualTo(geodeLogger.getName()); + assertThat(logEvent.getLevel()).isEqualTo(Level.WARN); + assertThat(logEvent.getMessage().getFormattedMessage()).isEqualTo(warnMessage); + } + + @Test + public void loggerInfoMessageIsSuppressed() { + logger.info(infoMessage); + + assertThat(findLogEventContaining(infoMessage)).as(logEventContaining(infoMessage)).isNull(); + } + + @Test + public void loggerWarnMessageIsLogged() { + logger.warn(warnMessage); + + LogEvent logEvent = findLogEventContaining(warnMessage); + assertThat(logEvent).as(logEventContaining(warnMessage)).isNotNull(); + assertThat(logEvent.getLoggerName()).isEqualTo(logger.getName()); + assertThat(logEvent.getLevel()).isEqualTo(Level.WARN); + assertThat(logEvent.getMessage().getFormattedMessage()).isEqualTo(warnMessage); + } + + private String logEventContaining(final String logMessage) { + return "LogEvent containing " + logMessage; + } + private LogEvent findLogEventContaining(final String logMessage) { List logEvents = listAppender.getEvents(); for (LogEvent logEvent : logEvents) { @@ -137,7 +174,6 @@ private LogEvent findLogEventContaining(final String logMessage) { return logEvent; } } - throw new AssertionError( - "Failed to find LogEvent containing " + logMessage + " in " + logEvents); + return null; } } diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CacheWithDefaultAppendersIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CacheWithDefaultAppendersIntegrationTest.java new file mode 100644 index 000000000000..0956da97d90a --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CacheWithDefaultAppendersIntegrationTest.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.ALERT_APPENDER_NAME; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.GEODE_CONSOLE_APPENDER_NAME; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.LOGWRITER_APPENDER_NAME; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.SECURITY_LOGWRITER_APPENDER_NAME; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Properties; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Validates the default appenders that should exist when a {@code Cache} is created. + */ +@Category(LoggingTest.class) +public class CacheWithDefaultAppendersIntegrationTest { + + private InternalCache cache; + private Configuration configuration; + + @Before + public void setUp() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + + cache = (InternalCache) new CacheFactory(config).create(); + + Logger coreLogger = (Logger) LogManager.getRootLogger(); + LoggerContext context = coreLogger.getContext(); + + configuration = context.getConfiguration(); + } + + @After + public void tearDown() { + cache.close(); + } + + @Test + public void hasGeodeConsoleAppenderNamed_GEODE_CONSOLE_APPENDER_NAME() { + Appender appender = configuration.getAppender(GEODE_CONSOLE_APPENDER_NAME); + + assertThat(appender).isNotNull().isInstanceOf(GeodeConsoleAppender.class); + } + + @Test + public void hasAlertAppenderNamed_ALERT_APPENDER_NAME() { + Appender appender = configuration.getAppender(ALERT_APPENDER_NAME); + + assertThat(appender).isNotNull().isInstanceOf(AlertAppender.class); + } + + @Test + public void hasLogWriterAppenderNamed_LOGWRITER_APPENDER_NAME() { + Appender appender = configuration.getAppender(LOGWRITER_APPENDER_NAME); + + assertThat(appender).isNotNull().isInstanceOf(LogWriterAppender.class); + } + + @Test + public void hasLogWriterAppenderNamed_SECURITY_LOGWRITER_APPENDER_NAME() { + Appender appender = configuration.getAppender(SECURITY_LOGWRITER_APPENDER_NAME); + + assertThat(appender).isNotNull().isInstanceOf(LogWriterAppender.class); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest.java new file mode 100644 index 000000000000..7509da3c28c1 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.internal.logging.Configuration.DEFAULT_LOGWRITER_LEVEL; +import static org.apache.geode.internal.logging.Configuration.create; +import static org.apache.geode.internal.logging.InternalLogWriter.FINE_LEVEL; +import static org.apache.geode.internal.logging.InternalLogWriter.WARNING_LEVEL; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.net.URL; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.internal.logging.Configuration; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link Configuration} and log level changes with + * {@link GeodeConsoleAppender}. + */ +@Category(LoggingTest.class) +public class ConfigurationWithLogLevelChangesIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "ConfigurationWithLogLevelChangesIntegrationTest_log4j2.xml"; + private static final String APPENDER_NAME = "STDOUT"; + private static final String APPLICATION_LOGGER_NAME = "com.company.application"; + + private static String configFilePath; + + private LogConfig config; + private Configuration configuration; + private Logger geodeLogger; + private Logger applicationLogger; + private String logMessage; + private GeodeConsoleAppender geodeConsoleAppender; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + config = mock(LogConfig.class); + when(config.getLogLevel()).thenReturn(DEFAULT_LOGWRITER_LEVEL); + when(config.getSecurityLogLevel()).thenReturn(DEFAULT_LOGWRITER_LEVEL); + + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(config); + + configuration = create(LogLevelUpdateOccurs.ALWAYS, LogLevelUpdateScope.GEODE_LOGGERS); + configuration.initialize(logConfigSupplier); + + geodeLogger = LogService.getLogger(); + applicationLogger = LogService.getLogger(APPLICATION_LOGGER_NAME); + + logMessage = "Logging in " + testName.getMethodName(); + + geodeConsoleAppender = + loggerContextRule.getAppender(APPENDER_NAME, GeodeConsoleAppender.class); + } + + @After + public void tearDown() throws Exception { + geodeConsoleAppender.clearLogEvents(); + configuration.shutdown(); + } + + @Test + public void geodeLoggerDebugNotLoggedByDefault() { + // act + geodeLogger.debug(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).isEmpty(); + } + + @Test + public void geodeLoggerDebugLoggedAfterLoweringLogLevelToFine() { + // arrange + when(config.getLogLevel()).thenReturn(FINE_LEVEL); + configuration.configChanged(); + + // act + geodeLogger.debug(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).hasSize(1); + LogEvent event = geodeConsoleAppender.getLogEvents().get(0); + assertThat(event.getLoggerName()).isEqualTo(getClass().getName()); + assertThat(event.getLevel()).isEqualTo(Level.DEBUG); + assertThat(event.getMessage().getFormattedMessage()).isEqualTo(logMessage); + } + + @Test + public void geodeLoggerDebugNotLoggedAfterRestoringLogLevelToDefault() { + // arrange + when(config.getLogLevel()).thenReturn(FINE_LEVEL); + configuration.configChanged(); + + // re-arrange + geodeConsoleAppender.clearLogEvents(); + when(config.getLogLevel()).thenReturn(DEFAULT_LOGWRITER_LEVEL); + configuration.configChanged(); + + // act + geodeLogger.debug(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).isEmpty(); + } + + @Test + public void applicationLoggerBelowLevelUnaffectedByLoweringLogLevelChanges() { + // arrange + when(config.getLogLevel()).thenReturn(FINE_LEVEL); + configuration.configChanged(); + + // act + applicationLogger.debug(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).isEmpty(); + } + + @Test + public void applicationLoggerInfoLoggedByDefault() { + // act + applicationLogger.info(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).hasSize(1); + LogEvent event = geodeConsoleAppender.getLogEvents().get(0); + assertThat(event.getLoggerName()).isEqualTo(APPLICATION_LOGGER_NAME); + assertThat(event.getLevel()).isEqualTo(Level.INFO); + assertThat(event.getMessage().getFormattedMessage()).isEqualTo(logMessage); + } + + @Test + public void applicationLoggerAboveLevelUnaffectedByLoweringLogLevelChanges() { + // arrange + geodeConsoleAppender.clearLogEvents(); + when(config.getLogLevel()).thenReturn(FINE_LEVEL); + configuration.configChanged(); + + // act + applicationLogger.info(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).hasSize(1); + } + + @Test + public void applicationLoggerAboveLevelUnaffectedByRaisingLogLevelChanges() { + // arrange + geodeConsoleAppender.clearLogEvents(); + when(config.getLogLevel()).thenReturn(WARNING_LEVEL); + configuration.configChanged(); + + // act + applicationLogger.info(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).hasSize(1); + } + + @Test + public void infoStatementNotLoggedAfterRaisingLogLevelToWarning() { + // arrange + geodeConsoleAppender.clearLogEvents(); + when(config.getLogLevel()).thenReturn(WARNING_LEVEL); + configuration.configChanged(); + + // act + geodeLogger.info(logMessage); + + // assert + assertThat(geodeConsoleAppender.getLogEvents()).isEmpty(); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest.java index 2001d4422af9..931cb1c221b2 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest.java @@ -22,87 +22,80 @@ import java.net.URL; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LifeCycle; -import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.apache.logging.log4j.core.appender.DefaultErrorHandler; import org.apache.logging.log4j.core.appender.OutputStreamManager; import org.apache.logging.log4j.junit.LoggerContextRule; -import org.apache.logging.log4j.test.appender.ListAppender; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemErrRule; import org.junit.contrib.java.lang.system.SystemOutRule; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import org.apache.geode.test.junit.categories.LoggingTest; +/** + * Verifies behavior of {@code SystemOutRule} with {@code LoggerContextRule} that other Geode + * logging tests depends on. If this behavior changes, then those tests may also need to change. + */ @Category(LoggingTest.class) public class ConsoleAppenderWithLoggerContextRuleIntegrationTest { + private static final String CONFIG_FILE_NAME = + "ConsoleAppenderWithLoggerContextRuleIntegrationTest_log4j2.xml"; + private static final String APPENDER_NAME = "STDOUT"; + private static String configFilePath; - private Logger postConfigLogger; + private Logger logger; private String logMessage; + private ConsoleAppender consoleAppender; @ClassRule public static SystemOutRule systemOutRule = new SystemOutRule().enableLog(); - @ClassRule - public static SystemErrRule systemErrRule = new SystemErrRule().enableLog(); - @ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + @Rule + public TestName testName = new TestName(); + @BeforeClass public static void setUpLogConfigFile() throws Exception { - String configFileName = - ConsoleAppenderWithLoggerContextRuleIntegrationTest.class.getSimpleName() + "_log4j2.xml"; - URL resource = getResource(configFileName); - configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), configFileName) + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) .getAbsolutePath(); } @Before public void setUp() throws Exception { - postConfigLogger = LogManager.getLogger(); - logMessage = "this is a log statement"; + logger = LogManager.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + consoleAppender = loggerContextRule.getAppender(APPENDER_NAME, ConsoleAppender.class); systemOutRule.clearLog(); - systemErrRule.clearLog(); } @Test - public void delegateConsoleAppenderIsConfigured() { - assertThat(loggerContextRule.getListAppender("LIST")).isNotNull(); - - ListAppender listAppender = findAppender(ListAppender.class); - assertThat(listAppender).isNotNull(); - - ConsoleAppender consoleAppender = findAppender(ConsoleAppender.class); - assertThat(consoleAppender).isNotNull(); - + public void consoleAppenderIsConfigured() { assertThat(consoleAppender.getFilter()).isNull(); assertThat(consoleAppender.getHandler()).isInstanceOf(DefaultErrorHandler.class); assertThat(consoleAppender.getImmediateFlush()).isTrue(); assertThat(consoleAppender.getLayout()).isNotNull(); assertThat(consoleAppender.getManager()).isInstanceOf(OutputStreamManager.class); - assertThat(consoleAppender.getName()).isEqualTo("STDOUT"); + assertThat(consoleAppender.getName()).isEqualTo(APPENDER_NAME); assertThat(consoleAppender.getState()).isSameAs(LifeCycle.State.STARTED); assertThat(consoleAppender.getTarget()).isSameAs(ConsoleAppender.Target.SYSTEM_OUT); @@ -116,27 +109,10 @@ public void delegateConsoleAppenderIsConfigured() { } @Test - public void staticSystemOutRuleCapturesConsoleAppenderOutputFromPostConfigLogger() { - postConfigLogger.info(logMessage); + public void staticSystemOutRuleCapturesConsoleAppenderOutput() { + logger.info(logMessage); assertThat(systemOutRule.getLog()).contains(Level.INFO.name().toLowerCase()); assertThat(systemOutRule.getLog()).contains(logMessage); - - assertThat(systemErrRule.getLog()).isEmpty(); - } - - private T findAppender(Class appenderClass) { - LoggerContext loggerContext = - ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).getContext(); - Map appenders = loggerContext.getConfiguration().getAppenders(); - List> appenderClasses = new ArrayList<>(); - for (Appender appender : appenders.values()) { - appenderClasses.add(appender.getClass()); - if (appenderClass.isAssignableFrom(appender.getClass())) { - return appenderClass.cast(appender); - } - } - assertThat(appenderClasses).contains(appenderClass); - return null; } } diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithSystemOutRuleIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithSystemOutRuleIntegrationTest.java deleted file mode 100644 index 22d48a62b43d..000000000000 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithSystemOutRuleIntegrationTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.geode.internal.logging.log4j; - -import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; -import static org.apache.geode.test.util.ResourceUtils.getResource; -import static org.apache.logging.log4j.core.config.ConfigurationFactory.CONFIGURATION_FILE_PROPERTY; -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.File; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.LifeCycle; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.ConsoleAppender; -import org.apache.logging.log4j.core.appender.DefaultErrorHandler; -import org.apache.logging.log4j.core.appender.OutputStreamManager; -import org.apache.logging.log4j.status.StatusLogger; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemErrRule; -import org.junit.contrib.java.lang.system.SystemOutRule; -import org.junit.experimental.categories.Category; -import org.junit.rules.TemporaryFolder; - -import org.apache.geode.internal.logging.LogService; -import org.apache.geode.test.junit.categories.LoggingTest; - -/** - * Verifies that we can capture output of {@code ConsoleAppender}. If this behavior changes, then - * Geode logging tests may also need to change. - */ -@Category(LoggingTest.class) -public class ConsoleAppenderWithSystemOutRuleIntegrationTest { - - private static final Logger classLoadedLogger = LogManager.getLogger(); - - private String beforeConfigFile; - private Level beforeLevel; - - private Logger preConfigLogger; - private Logger postConfigLogger; - private String logMessage; - - @ClassRule - public static SystemOutRule systemOutRule = new SystemOutRule().enableLog(); - - @ClassRule - public static SystemErrRule systemErrRule = new SystemErrRule().enableLog(); - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Before - public void setUp() throws Exception { - preConfigLogger = LogManager.getLogger(); - - Configurator.shutdown(); - - beforeConfigFile = System.getProperty(CONFIGURATION_FILE_PROPERTY); - beforeLevel = StatusLogger.getLogger().getLevel(); - - String configFileName = getClass().getSimpleName() + "_log4j2.xml"; - File configFile = createFileFromResource(getResource(configFileName), - temporaryFolder.getRoot(), configFileName); - - System.setProperty(CONFIGURATION_FILE_PROPERTY, configFile.getAbsolutePath()); - LogService.reconfigure(); - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - - systemOutRule.clearLog(); - systemErrRule.clearLog(); - - postConfigLogger = LogManager.getLogger(); - logMessage = "this is a log statement"; - } - - @After - public void tearDown() { - Configurator.shutdown(); - - System.clearProperty(CONFIGURATION_FILE_PROPERTY); - if (beforeConfigFile != null) { - System.setProperty(CONFIGURATION_FILE_PROPERTY, beforeConfigFile); - } - StatusLogger.getLogger().setLevel(beforeLevel); - - LogService.reconfigure(); - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isTrue(); - } - - @Test - public void delegateConsoleAppenderIsConfigured() { - ConsoleAppender consoleAppender = findAppender(ConsoleAppender.class); - assertThat(consoleAppender).isNotNull(); - - assertThat(consoleAppender.getFilter()).isNull(); - assertThat(consoleAppender.getHandler()).isInstanceOf(DefaultErrorHandler.class); - assertThat(consoleAppender.getImmediateFlush()).isTrue(); - assertThat(consoleAppender.getLayout()).isNotNull(); - assertThat(consoleAppender.getManager()).isInstanceOf(OutputStreamManager.class); - assertThat(consoleAppender.getName()).isEqualTo("STDOUT"); - assertThat(consoleAppender.getState()).isSameAs(LifeCycle.State.STARTED); - assertThat(consoleAppender.getTarget()).isSameAs(ConsoleAppender.Target.SYSTEM_OUT); - - OutputStreamManager outputStreamManager = consoleAppender.getManager(); - assertThat(outputStreamManager.isOpen()).isTrue(); - assertThat(outputStreamManager.getByteBuffer()).isInstanceOf(ByteBuffer.class); - assertThat(outputStreamManager.hasOutputStream()).isTrue(); - assertThat(outputStreamManager.getContentFormat()).isEmpty(); - assertThat(outputStreamManager.getLoggerContext()).isNull(); - assertThat(outputStreamManager.getName()).isEqualTo("SYSTEM_OUT.false.false"); - } - - @Test - public void staticSystemOutRuleCapturesConsoleAppenderOutputFromPostConfigLogger() { - postConfigLogger.info(logMessage); - - assertThat(systemOutRule.getLog()).contains(Level.INFO.name().toLowerCase()); - assertThat(systemOutRule.getLog()).contains(logMessage); - - assertThat(systemErrRule.getLog()).isEmpty(); - } - - @Test - public void staticSystemOutRuleFailsToCaptureConsoleAppenderOutputFromPreConfigLogger() { - preConfigLogger.info(logMessage); - - assertThat(systemOutRule.getLog()).isEmpty(); - assertThat(systemErrRule.getLog()).isEmpty(); - } - - @Test - public void staticSystemOutRuleFailsToCaptureConsoleAppenderOutputFromClassLoadedLogger() { - classLoadedLogger.info(logMessage); - - assertThat(systemOutRule.getLog()).isEmpty(); - assertThat(systemErrRule.getLog()).isEmpty(); - } - - private T findAppender(Class appenderClass) { - LoggerContext loggerContext = - ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).getContext(); - Map appenders = loggerContext.getConfiguration().getAppenders(); - List> appenderClasses = new ArrayList<>(); - for (Appender appender : appenders.values()) { - appenderClasses.add(appender.getClass()); - if (appenderClass.isAssignableFrom(appender.getClass())) { - return appenderClass.cast(appender); - } - } - assertThat(appenderClasses).contains(appenderClass); - return null; - } -} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest.java new file mode 100644 index 000000000000..28133f8bd126 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_FILE; +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; + +import java.io.File; +import java.net.URL; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.LogWriter; +import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for logging of main and security {@code Logger}s and {@link LogWriter}s to + * {@link ConfigurationProperties#LOG_FILE} and {@link ConfigurationProperties#SECURITY_LOG_FILE} + * with {@link DistributedSystem}. + */ +@Category(LoggingTest.class) +public class DistributedSystemWithBothLogWriterAppendersIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "DistributedSystemWithBothLogWriterAppendersIntegrationTest_log4j2.xml"; + + private static String configFilePath; + + private File mainLogFile; + private File securityLogFile; + private InternalDistributedSystem system; + private Logger mainLogger; + private Logger securityLogger; + private LogWriter mainLogWriter; + private LogWriter securityLogWriter; + private String logMessage; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + String name = testName.getMethodName(); + mainLogFile = new File(temporaryFolder.getRoot(), name + "-main.log"); + securityLogFile = new File(temporaryFolder.getRoot(), name + "-security.log"); + + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, mainLogFile.getAbsolutePath()); + config.setProperty(SECURITY_LOG_FILE, securityLogFile.getAbsolutePath()); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + mainLogger = LogService.getLogger(); + securityLogger = LogService.getLogger(SECURITY_LOGGER_NAME); + + mainLogWriter = system.getLogWriter(); + securityLogWriter = system.getSecurityLogWriter(); + + mainLogger.info("Starting {}", getClass().getName()); + securityLogger.info("Starting {}", getClass().getName()); + + await().until(() -> mainLogFile.exists()); + await().until(() -> securityLogFile.exists()); + + logMessage = "Logging " + testName.getMethodName(); + } + + @After + public void tearDown() throws Exception { + system.disconnect(); + } + + @Test + public void mainLogger_debug_notLoggedByDefault() { + mainLogger.debug(logMessage); + + LogFileAssert.assertThat(mainLogFile).doesNotContain(logMessage); + } + + @Test + public void mainLogger_logsTo_mainLogFile() { + mainLogger.info(logMessage); + + LogFileAssert.assertThat(mainLogFile).contains(logMessage); + } + + @Test + public void mainLogger_doesNotLogTo_securityLogFile() { + mainLogger.info(logMessage); + + LogFileAssert.assertThat(securityLogFile).doesNotContain(logMessage); + } + + @Test + public void securityLogger_debug_notLoggedByDefault() { + securityLogger.debug(logMessage); + + LogFileAssert.assertThat(securityLogFile).doesNotContain(logMessage); + } + + @Test + public void securityLogger_logsTo_securityLogFile() { + securityLogger.info(logMessage); + + LogFileAssert.assertThat(securityLogFile).contains(logMessage); + } + + @Test + public void securityLogger_doesNotLogTo_mainLogFile() { + securityLogger.info(logMessage); + + LogFileAssert.assertThat(mainLogFile).doesNotContain(logMessage); + } + + @Test + public void mainLogWriter_fine_notLoggedByDefault() { + mainLogWriter.fine(logMessage); + + LogFileAssert.assertThat(mainLogFile).doesNotContain(logMessage); + } + + @Test + public void mainLogWriter_logsTo_mainLogFile() { + mainLogWriter.info(logMessage); + + LogFileAssert.assertThat(mainLogFile).contains(logMessage); + } + + @Test + public void mainLogWriter_doesNotLogTo_securityLogFile() { + mainLogWriter.info(logMessage); + + LogFileAssert.assertThat(securityLogFile).doesNotContain(logMessage); + } + + @Test + public void securityLogWriter_fine_notLoggedByDefault() { + securityLogWriter.fine(logMessage); + + LogFileAssert.assertThat(securityLogFile).doesNotContain(logMessage); + } + + @Test + public void securityLogWriter_logsTo_securityLogFile() { + securityLogWriter.info(logMessage); + + LogFileAssert.assertThat(securityLogFile).contains(logMessage); + } + + @Test + public void securityLogWriter_doesNotLogTo_mainLogFile() { + securityLogWriter.info(logMessage); + + LogFileAssert.assertThat(mainLogFile).doesNotContain(logMessage); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest.java new file mode 100644 index 000000000000..cdd707148b2b --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.internal.logging.Configuration.DEFAULT_LOGWRITER_LEVEL; +import static org.apache.geode.internal.logging.Configuration.LOG_LEVEL_UPDATE_OCCURS_PROPERTY; +import static org.apache.geode.internal.logging.InternalLogWriter.FINE_LEVEL; +import static org.apache.geode.internal.logging.InternalLogWriter.WARNING_LEVEL; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import java.net.URL; +import java.util.List; +import java.util.Properties; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link DistributedSystem} and log level changes with + * {@link GeodeConsoleAppender}. + */ +@Category(LoggingTest.class) +public class DistributedSystemWithLogLevelChangesIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "DistributedSystemWithLogLevelChangesIntegrationTest_log4j2.xml"; + private static final String APPENDER_NAME = "STDOUT"; + private static final String APPLICATION_LOGGER_NAME = "com.company.application"; + + private static String configFilePath; + + private InternalDistributedSystem system; + private DistributionConfig distributionConfig; + private Logger geodeLogger; + private Logger applicationLogger; + private String logMessage; + private GeodeConsoleAppender geodeConsoleAppender; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, LogLevelUpdateOccurs.ALWAYS.name()); + + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + + system = (InternalDistributedSystem) DistributedSystem.connect(config); + + distributionConfig = system.getConfig(); + geodeLogger = LogService.getLogger(); + applicationLogger = LogService.getLogger(APPLICATION_LOGGER_NAME); + logMessage = "Logging in " + testName.getMethodName(); + geodeConsoleAppender = + loggerContextRule.getAppender(APPENDER_NAME, GeodeConsoleAppender.class); + } + + @After + public void tearDown() throws Exception { + system.disconnect(); + geodeConsoleAppender.clearLogEvents(); + } + + @Test + public void debugNotLoggedByDefault() { + geodeLogger.debug(logMessage); + + assertThatLogEventsDoesNotContain(logMessage, getClass().getName(), Level.DEBUG); + } + + @Test + public void debugLoggedAfterLoweringLogLevelToFine() { + distributionConfig.setLogLevel(FINE_LEVEL); + + geodeLogger.debug(logMessage); + + assertThatLogEventsContains(logMessage, geodeLogger.getName(), Level.DEBUG); + } + + @Test + public void debugNotLoggedAfterRestoringLogLevelToDefault() { + distributionConfig.setLogLevel(FINE_LEVEL); + + system.getConfig().setLogLevel(DEFAULT_LOGWRITER_LEVEL); + geodeLogger.debug(logMessage); + + assertThatLogEventsDoesNotContain(logMessage, geodeLogger.getName(), Level.DEBUG); + } + + @Test + public void applicationLoggerInfoLoggedByDefault() { + applicationLogger.info(logMessage); + + assertThatLogEventsContains(logMessage, applicationLogger.getName(), Level.INFO); + } + + @Test + public void applicationLoggerBelowLevelUnaffectedByLoweringLogLevelChanges() { + distributionConfig.setLogLevel(FINE_LEVEL); + + applicationLogger.debug(logMessage); + + assertThatLogEventsDoesNotContain(logMessage, applicationLogger.getName(), Level.DEBUG); + } + + @Test + public void applicationLoggerAboveLevelUnaffectedByLoweringLogLevelChanges() { + distributionConfig.setLogLevel(FINE_LEVEL); + + applicationLogger.info(logMessage); + + assertThatLogEventsContains(logMessage, applicationLogger.getName(), Level.INFO); + } + + @Test + public void applicationLoggerAboveLevelUnaffectedByRaisingLogLevelChanges() { + distributionConfig.setLogLevel(WARNING_LEVEL); + + applicationLogger.info(logMessage); + + assertThatLogEventsContains(logMessage, applicationLogger.getName(), Level.INFO); + } + + @Test + public void infoStatementNotLoggedAfterRaisingLogLevelToWarning() { + distributionConfig.setLogLevel(WARNING_LEVEL); + + geodeLogger.info(logMessage); + + assertThatLogEventsDoesNotContain(logMessage, geodeLogger.getName(), Level.INFO); + } + + private void assertThatLogEventsContains(String message, String loggerName, Level level) { + List logEvents = geodeConsoleAppender.getLogEvents(); + for (LogEvent logEvent : logEvents) { + if (logEvent.getMessage().getFormattedMessage().contains(message)) { + assertThat(logEvent.getMessage().getFormattedMessage()).isEqualTo(message); + assertThat(logEvent.getLoggerName()).isEqualTo(loggerName); + assertThat(logEvent.getLevel()).isEqualTo(level); + return; + } + } + fail("Expected message " + message + " not found in " + logEvents); + } + + private void assertThatLogEventsDoesNotContain(String message, String loggerName, Level level) { + List logEvents = geodeConsoleAppender.getLogEvents(); + for (LogEvent logEvent : logEvents) { + if (logEvent.getMessage().getFormattedMessage().contains(message) && + logEvent.getLoggerName().equals(loggerName) && logEvent.getLevel().equals(level)) { + fail("Expected message " + message + " should not be contained in " + logEvents); + } + } + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerIntegrationTest.java index 1fcd650613e1..dd27c20b8995 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerIntegrationTest.java @@ -14,9 +14,12 @@ */ package org.apache.geode.internal.logging.log4j; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.apache.geode.internal.logging.Configuration.DEFAULT_LOGWRITER_LEVEL; +import static org.apache.geode.internal.logging.Configuration.MAIN_LOGGER_NAME; +import static org.apache.geode.internal.logging.Configuration.create; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.BufferedWriter; import java.io.File; @@ -27,21 +30,26 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.apache.geode.internal.logging.Configuration; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; import org.apache.geode.internal.logging.LogService; import org.apache.geode.test.junit.categories.LoggingTest; /** - * Tests FastLogger isDebugEnabled and isTraceEnabled with various configurations. + * Integration tests for {@link FastLogger} with various configurations. * *

* For filters see https://logging.apache.org/log4j/2.0/manual/filters.html @@ -49,53 +57,63 @@ @Category(LoggingTest.class) public class FastLoggerIntegrationTest { + /** + * This config file is generated dynamically by the test class. + */ + private static final String CONFIG_FILE_NAME = "FastLoggerIntegrationTest_log4j2.xml"; private static final String TEST_LOGGER_NAME = FastLogger.class.getPackage().getName(); private static final String ENABLED_MARKER_NAME = "ENABLED"; private static final String UNUSED_MARKER_NAME = "UNUSED"; - private File configFile; - private String configFileLocation; + private static File configFile; + private static String configFilePath; + + private Configuration configuration; private Logger logger; - private LoggerContext appenderContext; private Marker enabledMarker; private Marker unusedMarker; - @Rule - public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + configFile = new File(temporaryFolder.getRoot(), CONFIG_FILE_NAME); + configFilePath = configFile.getAbsolutePath(); + writeSimpleConfigFile(configFile, Level.WARN); + } @Before public void setUp() throws Exception { - System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY); - configFile = new File(temporaryFolder.getRoot(), "log4j2-test.xml"); - configFileLocation = configFile.toURI().toURL().toString(); enabledMarker = MarkerManager.getMarker(ENABLED_MARKER_NAME); unusedMarker = MarkerManager.getMarker(UNUSED_MARKER_NAME); - setUpLogService(); + + logger = LogService.getLogger(TEST_LOGGER_NAME); + + assertThat(LogService.getLogger(MAIN_LOGGER_NAME).getLevel()).isEqualTo(Level.FATAL); + assertThat(logger).isInstanceOf(FastLogger.class); + assertThat(logger.getLevel()).isEqualTo(Level.WARN); + + LogConfig logConfig = mock(LogConfig.class); + when(logConfig.getLogLevel()).thenReturn(DEFAULT_LOGWRITER_LEVEL); + when(logConfig.getSecurityLogLevel()).thenReturn(DEFAULT_LOGWRITER_LEVEL); + + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(logConfig); + + configuration = create(LogLevelUpdateOccurs.NEVER, LogLevelUpdateScope.GEODE_LOGGERS); + configuration.initialize(logConfigSupplier); } @After - public void tearDown() { - System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY); - LogService.reconfigure(); - } + public void tearDown() throws Exception { + configuration.shutdown(); - private void setUpLogService() throws Exception { - // Load a base config and do some sanity checks writeSimpleConfigFile(configFile, Level.WARN); - System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, configFileLocation); - - LogService.reconfigure(); - LogService.getLogger().getName(); // This causes the config file to be loaded - logger = LogService.getLogger(TEST_LOGGER_NAME); - appenderContext = - ((org.apache.logging.log4j.core.Logger) LogService.getRootLogger()).getContext(); - - assertThat(LogService.getLogger(LogService.BASE_LOGGER_NAME).getLevel(), is(Level.FATAL)); - assertThat(logger, is(instanceOf(FastLogger.class))); - assertThat(logger.getLevel(), is(Level.WARN)); + loggerContextRule.reconfigure(); } @Test @@ -297,34 +315,33 @@ public void appenderRefFilterIsDelegating() throws Exception { private void verifyIsDelegatingForDebugOrLower(final Level level, final boolean expectIsDelegating) throws Exception { writeSimpleConfigFile(configFile, level); - appenderContext.reconfigure(); - - assertThat(logger.getLevel(), is(level)); - - assertThat(logger.isTraceEnabled(), is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(), is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(), is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(), is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(), is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(), is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(logger.isTraceEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.FATAL))); - - final boolean delegating = ((FastLogger) logger).isDelegating(); - assertThat(delegating, is(expectIsDelegating)); - assertThat(delegating, is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(delegating, is(expectIsDelegating)); + loggerContextRule.reconfigure(); + configuration.configChanged(); + + assertThat(logger.getLevel()).isEqualTo(level); + + assertThat(logger.isTraceEnabled()).isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled()).isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled()).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled()).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled()).isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled()).isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(logger.isTraceEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + boolean delegating = ((FastLogger) logger).isDelegating(); + assertThat(delegating).isEqualTo(expectIsDelegating); + assertThat(delegating).isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(delegating).isEqualTo(expectIsDelegating); } /** @@ -335,47 +352,44 @@ private void verifyIsDelegatingForDebugOrLower(final Level level, */ private void verifyIsDelegatingForLoggerFilter(final Level level, final boolean expectIsDelegating) throws Exception { - assertThat(expectIsDelegating, is(true)); // always true for Logger Filter + assertThat(expectIsDelegating).isEqualTo(true); // always true for Logger Filter writeLoggerFilterConfigFile(configFile, level); - appenderContext.reconfigure(); - - assertThat(logger.getLevel(), is(level)); - - assertThat(logger.isTraceEnabled(), is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(), is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(), is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(), is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(), is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(), is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(logger.isTraceEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(logger.isTraceEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(((FastLogger) logger).isDelegating(), is(expectIsDelegating)); + loggerContextRule.reconfigure(); + configuration.configChanged(); + + assertThat(logger.getLevel()).isEqualTo(level); + + assertThat(logger.isTraceEnabled()).isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled()).isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled()).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled()).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled()).isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled()).isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(logger.isTraceEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled(enabledMarker)).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled(enabledMarker)).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(logger.isTraceEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(((FastLogger) logger).isDelegating()).isEqualTo(expectIsDelegating); } /** @@ -386,37 +400,38 @@ private void verifyIsDelegatingForLoggerFilter(final Level level, */ private void verifyIsDelegatingForContextWideFilter(final Level level, final boolean expectIsDelegating) throws Exception { - assertThat(expectIsDelegating, is(true)); // always true for Context-wide Filter + assertThat(expectIsDelegating).isEqualTo(true); // always true for Context-wide Filter writeContextWideFilterConfigFile(configFile, level); - appenderContext.reconfigure(); + loggerContextRule.reconfigure(); + configuration.configChanged(); - assertThat(logger.getLevel(), is(level)); + assertThat(logger.getLevel()).isEqualTo(level); // note: unlike other filters, Context-wide filters are processed BEFORE isEnabled checks - assertThat(logger.isTraceEnabled(), is(false)); - assertThat(logger.isDebugEnabled(), is(false)); - assertThat(logger.isInfoEnabled(), is(false)); - assertThat(logger.isWarnEnabled(), is(false)); - assertThat(logger.isErrorEnabled(), is(false)); - assertThat(logger.isFatalEnabled(), is(false)); + assertThat(logger.isTraceEnabled()).isEqualTo(false); + assertThat(logger.isDebugEnabled()).isEqualTo(false); + assertThat(logger.isInfoEnabled()).isEqualTo(false); + assertThat(logger.isWarnEnabled()).isEqualTo(false); + assertThat(logger.isErrorEnabled()).isEqualTo(false); + assertThat(logger.isFatalEnabled()).isEqualTo(false); - assertThat(logger.isTraceEnabled(enabledMarker), is(true)); - assertThat(logger.isDebugEnabled(enabledMarker), is(true)); - assertThat(logger.isInfoEnabled(enabledMarker), is(true)); - assertThat(logger.isWarnEnabled(enabledMarker), is(true)); - assertThat(logger.isErrorEnabled(enabledMarker), is(true)); - assertThat(logger.isFatalEnabled(enabledMarker), is(true)); + assertThat(logger.isTraceEnabled(enabledMarker)).isEqualTo(true); + assertThat(logger.isDebugEnabled(enabledMarker)).isEqualTo(true); + assertThat(logger.isInfoEnabled(enabledMarker)).isEqualTo(true); + assertThat(logger.isWarnEnabled(enabledMarker)).isEqualTo(true); + assertThat(logger.isErrorEnabled(enabledMarker)).isEqualTo(true); + assertThat(logger.isFatalEnabled(enabledMarker)).isEqualTo(true); - assertThat(logger.isTraceEnabled(unusedMarker), is(false)); - assertThat(logger.isDebugEnabled(unusedMarker), is(false)); - assertThat(logger.isInfoEnabled(unusedMarker), is(false)); - assertThat(logger.isWarnEnabled(unusedMarker), is(false)); - assertThat(logger.isErrorEnabled(unusedMarker), is(false)); - assertThat(logger.isFatalEnabled(unusedMarker), is(false)); + assertThat(logger.isTraceEnabled(unusedMarker)).isEqualTo(false); + assertThat(logger.isDebugEnabled(unusedMarker)).isEqualTo(false); + assertThat(logger.isInfoEnabled(unusedMarker)).isEqualTo(false); + assertThat(logger.isWarnEnabled(unusedMarker)).isEqualTo(false); + assertThat(logger.isErrorEnabled(unusedMarker)).isEqualTo(false); + assertThat(logger.isFatalEnabled(unusedMarker)).isEqualTo(false); - assertThat(((FastLogger) logger).isDelegating(), is(expectIsDelegating)); + assertThat(((FastLogger) logger).isDelegating()).isEqualTo(expectIsDelegating); } /** @@ -427,47 +442,44 @@ private void verifyIsDelegatingForContextWideFilter(final Level level, */ private void verifyIsDelegatingForAppenderFilter(final Level level, final boolean expectIsDelegating) throws Exception { - assertThat(expectIsDelegating, is(true)); // always true for Appender Filter + assertThat(expectIsDelegating).isEqualTo(true); // always true for Appender Filter writeAppenderFilterConfigFile(configFile, level); - appenderContext.reconfigure(); - - assertThat(logger.getLevel(), is(level)); - - assertThat(logger.isTraceEnabled(), is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(), is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(), is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(), is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(), is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(), is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(logger.isTraceEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(logger.isTraceEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(((FastLogger) logger).isDelegating(), is(expectIsDelegating)); + loggerContextRule.reconfigure(); + configuration.configChanged(); + + assertThat(logger.getLevel()).isEqualTo(level); + + assertThat(logger.isTraceEnabled()).isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled()).isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled()).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled()).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled()).isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled()).isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(logger.isTraceEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled(enabledMarker)).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled(enabledMarker)).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(logger.isTraceEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(((FastLogger) logger).isDelegating()).isEqualTo(expectIsDelegating); } /** @@ -478,47 +490,44 @@ private void verifyIsDelegatingForAppenderFilter(final Level level, */ private void verifyIsDelegatingForAppenderRefFilter(final Level level, final boolean expectIsDelegating) throws Exception { - assertThat(expectIsDelegating, is(true)); // always true for AppenderRef Filter + assertThat(expectIsDelegating).isEqualTo(true); // always true for AppenderRef Filter writeAppenderRefFilterConfigFile(configFile, level); - appenderContext.reconfigure(); - - assertThat(logger.getLevel(), is(level)); - - assertThat(logger.isTraceEnabled(), is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(), is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(), is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(), is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(), is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(), is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(logger.isTraceEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(enabledMarker), - is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(logger.isTraceEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.TRACE))); - assertThat(logger.isDebugEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.DEBUG))); - assertThat(logger.isInfoEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.INFO))); - assertThat(logger.isWarnEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.WARN))); - assertThat(logger.isErrorEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.ERROR))); - assertThat(logger.isFatalEnabled(unusedMarker), - is(level.isLessSpecificThan(Level.FATAL))); - - assertThat(((FastLogger) logger).isDelegating(), is(expectIsDelegating)); + loggerContextRule.reconfigure(); + configuration.configChanged(); + + assertThat(logger.getLevel()).isEqualTo(level); + + assertThat(logger.isTraceEnabled()).isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled()).isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled()).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled()).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled()).isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled()).isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(logger.isTraceEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled(enabledMarker)).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled(enabledMarker)).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled(enabledMarker)) + .isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(logger.isTraceEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.TRACE)); + assertThat(logger.isDebugEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.DEBUG)); + assertThat(logger.isInfoEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.INFO)); + assertThat(logger.isWarnEnabled(unusedMarker)).isEqualTo(level.isLessSpecificThan(Level.WARN)); + assertThat(logger.isErrorEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.ERROR)); + assertThat(logger.isFatalEnabled(unusedMarker)) + .isEqualTo(level.isLessSpecificThan(Level.FATAL)); + + assertThat(((FastLogger) logger).isDelegating()).isEqualTo(expectIsDelegating); } private boolean expectDelegating(final boolean value) { diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerWithDefaultConfigIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerWithDefaultConfigIntegrationTest.java index 99fdea235452..ebab71cc2307 100755 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerWithDefaultConfigIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/FastLoggerWithDefaultConfigIntegrationTest.java @@ -14,49 +14,44 @@ */ package org.apache.geode.internal.logging.log4j; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isEmptyOrNullString; -import static org.junit.Assert.assertThat; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.experimental.categories.Category; +import org.apache.geode.internal.logging.Configuration; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; import org.apache.geode.internal.logging.LogService; import org.apache.geode.test.junit.categories.LoggingTest; /** - * Integration tests for FastLogger when using the default log4j2 config for GemFire. + * Integration tests for {@link FastLogger} when using the default {@code log4j2.xml} for Geode. */ @Category(LoggingTest.class) public class FastLoggerWithDefaultConfigIntegrationTest { - private static final String TEST_LOGGER_NAME = FastLogger.class.getPackage().getName(); - private Logger logger; - @Rule - public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); - @Before public void setUp() throws Exception { - System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY); - LogService.reconfigure(); - } + LogConfig logConfig = mock(LogConfig.class); + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); - /** - * System property "log4j.configurationFile" should be - * "/org/apache/geode/internal/logging/log4j/log4j2-default.xml" - */ - @Test - public void configurationFilePropertyIsDefaultConfig() { - assertThat(System.getProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY), - isEmptyOrNullString()); + when(logConfig.getLogLevel()).thenReturn(INFO.intLevel()); + when(logConfig.getSecurityLogLevel()).thenReturn(INFO.intLevel()); + when(logConfigSupplier.getLogConfig()).thenReturn(logConfig); + + Configuration configuration = + Configuration.create(LogLevelUpdateOccurs.ALWAYS, LogLevelUpdateScope.GEODE_LOGGERS); + configuration.initialize(logConfigSupplier); } /** @@ -64,7 +59,7 @@ public void configurationFilePropertyIsDefaultConfig() { */ @Test public void isUsingGemFireDefaultConfig() { - assertThat(LogService.isUsingGemFireDefaultConfig(), is(true)); + assertThat(Log4jAgent.isUsingGemFireDefaultConfig()).isTrue(); } /** @@ -72,9 +67,9 @@ public void isUsingGemFireDefaultConfig() { */ @Test public void logServiceReturnsFastLoggers() { - logger = LogService.getLogger(TEST_LOGGER_NAME); + logger = LogService.getLogger(); - assertThat(logger, is(instanceOf(FastLogger.class))); + assertThat(logger).isInstanceOf(FastLogger.class); } /** @@ -82,8 +77,8 @@ public void logServiceReturnsFastLoggers() { */ @Test public void isDelegatingShouldBeFalse() { - logger = LogService.getLogger(TEST_LOGGER_NAME); + logger = LogService.getLogger(); - assertThat(((FastLogger) logger).isDelegating(), is(false)); + assertThat(((FastLogger) logger).isDelegating()).isFalse(); } } diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest.java index 56f385525182..b7daa930f4d0 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest.java @@ -32,20 +32,27 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import org.apache.geode.internal.logging.LogService; import org.apache.geode.test.junit.categories.LoggingTest; +/** + * Integration tests for using {@link LogMarker#GEMFIRE_VERBOSE} with {@code MarkerFilter} having + * {@code onMatch} of {@code ACCEPT} and {@code onMismatch} of {@code DENY}. + */ @Category(LoggingTest.class) public class GemfireVerboseMarkerFilterAcceptIntegrationTest { + private static final String CONFIG_FILE_NAME = + "GemfireVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml"; private static final String APPENDER_NAME = "LIST"; private static String configFilePath; + private ListAppender listAppender; private Logger logger; private String logMessage; - private ListAppender listAppender; @ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -53,24 +60,21 @@ public class GemfireVerboseMarkerFilterAcceptIntegrationTest { @Rule public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + @Rule + public TestName testName = new TestName(); + @BeforeClass public static void setUpLogConfigFile() throws Exception { - String configFileName = - GemfireVerboseMarkerFilterAcceptIntegrationTest.class.getSimpleName() + "_log4j2.xml"; - URL resource = getResource(configFileName); - configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), configFileName) + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) .getAbsolutePath(); } @Before public void setUp() throws Exception { - logger = LogService.getLogger(); - logMessage = "this is a log statement"; - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - listAppender = loggerContextRule.getListAppender(APPENDER_NAME); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); } @Test diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest.java index 87cec2f8aca3..5bc4e2329ff1 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest.java @@ -30,20 +30,27 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import org.apache.geode.internal.logging.LogService; import org.apache.geode.test.junit.categories.LoggingTest; +/** + * Integration tests for using {@link LogMarker#GEMFIRE_VERBOSE} with {@code MarkerFilter} having + * {@code onMatch} of {@code DENY} and {@code onMismatch} of {@code ACCEPT}. + */ @Category(LoggingTest.class) public class GemfireVerboseMarkerFilterDenyIntegrationTest { + private static final String CONFIG_FILE_NAME = + "GemfireVerboseMarkerFilterDenyIntegrationTest_log4j2.xml"; private static final String APPENDER_NAME = "LIST"; private static String configFilePath; + private ListAppender listAppender; private Logger logger; private String logMessage; - private ListAppender listAppender; @ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -51,24 +58,21 @@ public class GemfireVerboseMarkerFilterDenyIntegrationTest { @Rule public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + @Rule + public TestName testName = new TestName(); + @BeforeClass public static void setUpLogConfigFile() throws Exception { - String configFileName = - GemfireVerboseMarkerFilterDenyIntegrationTest.class.getSimpleName() + "_log4j2.xml"; - URL resource = getResource(configFileName); - configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), configFileName) + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) .getAbsolutePath(); } @Before public void setUp() throws Exception { - logger = LogService.getLogger(); - logMessage = "this is a log statement"; - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - listAppender = loggerContextRule.getListAppender(APPENDER_NAME); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); } @Test diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest.java new file mode 100644 index 000000000000..bf87b27f28ad --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest.java @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URL; +import java.nio.ByteBuffer; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LifeCycle; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.appender.DefaultErrorHandler; +import org.apache.logging.log4j.core.appender.OutputStreamManager; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link GeodeConsoleAppender}. + */ +@Category(LoggingTest.class) +public class GeodeConsoleAppenderIntegrationTest { + + private static final String CONFIG_FILE_NAME = "GeodeConsoleAppenderIntegrationTest_log4j2.xml"; + private static final String APPENDER_NAME = "STDOUT"; + private static final String OUTPUT_STREAM_MANAGER_NAME = "null.SYSTEM_OUT.false.false"; + private static final String DELEGATE_APPENDER_NAME = "STDOUT_DELEGATE"; + private static final String DELEGATE_OUTPUT_STREAM_MANAGER_NAME = "SYSTEM_OUT.false.false"; + + private static String configFilePath; + + private GeodeConsoleAppender geodeConsoleAppender; + private Logger logger; + private String logMessage; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + geodeConsoleAppender = + loggerContextRule.getAppender("STDOUT", GeodeConsoleAppender.class); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + } + + @After + public void tearDown() throws Exception { + geodeConsoleAppender.clearLogEvents(); + } + + @Test + public void getLogEventsIsEmptyByDefault() { + assertThat(geodeConsoleAppender.getLogEvents()).isEmpty(); + } + + @Test + public void getLogEventsReturnsLoggedEvents() { + logger.info(logMessage); + + assertThat(geodeConsoleAppender.getLogEvents()).hasSize(1); + + LogEvent event = geodeConsoleAppender.getLogEvents().get(0); + assertThat(event.getLoggerName()).isEqualTo(getClass().getName()); + assertThat(event.getLevel()).isEqualTo(Level.INFO); + assertThat(event.getMessage().getFormattedMessage()).isEqualTo(logMessage); + } + + @Test + public void pausedDoesNotLog() { + geodeConsoleAppender.pause(); + + logger.info(logMessage); + + assertThat(geodeConsoleAppender.getLogEvents()).isEmpty(); + } + + @Test + public void resumeAfterPausedLogs() { + geodeConsoleAppender.pause(); + geodeConsoleAppender.resume(); + + logger.info(logMessage); + + assertThat(geodeConsoleAppender.getLogEvents()).hasSize(1); + } + + @Test + public void resumeWithoutPauseStillLogs() { + geodeConsoleAppender.resume(); + + logger.info(logMessage); + + assertThat(geodeConsoleAppender.getLogEvents()).hasSize(1); + } + + @Test + public void isPausedReturnsTrueAfterPause() { + geodeConsoleAppender.pause(); + + assertThat(geodeConsoleAppender.isPaused()).isTrue(); + } + + @Test + public void isPausedReturnsFalseAfterResume() { + geodeConsoleAppender.pause(); + geodeConsoleAppender.resume(); + + assertThat(geodeConsoleAppender.isPaused()).isFalse(); + } + + @Test + public void resumeWithoutPauseDoesNothing() { + geodeConsoleAppender.resume(); + + assertThat(geodeConsoleAppender.isPaused()).isFalse(); + } + + @Test + public void isPausedReturnsFalseByDefault() { + assertThat(geodeConsoleAppender.isPaused()).isFalse(); + } + + @Test + public void geodeConsoleAppenderIsConfigured() { + assertThat(geodeConsoleAppender).isNotNull(); + + assertThat(geodeConsoleAppender.getFilter()).isNull(); + assertThat(geodeConsoleAppender.getHandler()).isInstanceOf(DefaultErrorHandler.class); + assertThat(geodeConsoleAppender.getImmediateFlush()).isTrue(); + assertThat(geodeConsoleAppender.getLayout()).isNotNull(); + assertThat(geodeConsoleAppender.getManager()).isInstanceOf(OutputStreamManager.class); + assertThat(geodeConsoleAppender.getName()).isEqualTo(APPENDER_NAME); + assertThat(geodeConsoleAppender.getState()).isSameAs(LifeCycle.State.STARTED); + // assertThat(geodeConsoleAppender.getTarget()).isSameAs(ConsoleAppender.Target.SYSTEM_OUT); + + OutputStreamManager outputStreamManager = geodeConsoleAppender.getManager(); + assertThat(outputStreamManager.isOpen()).isTrue(); + assertThat(outputStreamManager.getByteBuffer()).isInstanceOf(ByteBuffer.class); + assertThat(outputStreamManager.hasOutputStream()).isTrue(); + assertThat(outputStreamManager.getContentFormat()).isEmpty(); + assertThat(outputStreamManager.getLoggerContext()).isNull(); + assertThat(outputStreamManager.getName()).isEqualTo(OUTPUT_STREAM_MANAGER_NAME); + } + + @Test + public void delegateConsoleAppenderIsConfigured() { + ConsoleAppender consoleAppender = geodeConsoleAppender.getDelegate(); + assertThat(consoleAppender).isNotNull(); + + assertThat(consoleAppender.getFilter()).isNull(); + assertThat(consoleAppender.getHandler()).isInstanceOf(DefaultErrorHandler.class); + assertThat(consoleAppender.getImmediateFlush()).isTrue(); + assertThat(consoleAppender.getLayout()).isNotNull(); + assertThat(consoleAppender.getManager()).isInstanceOf(OutputStreamManager.class); + assertThat(consoleAppender.getName()).isEqualTo(DELEGATE_APPENDER_NAME); + assertThat(consoleAppender.getState()).isSameAs(LifeCycle.State.STARTED); + assertThat(consoleAppender.getTarget()).isSameAs(ConsoleAppender.Target.SYSTEM_OUT); + + OutputStreamManager outputStreamManager = consoleAppender.getManager(); + assertThat(outputStreamManager.isOpen()).isTrue(); + assertThat(outputStreamManager.getByteBuffer()).isInstanceOf(ByteBuffer.class); + assertThat(outputStreamManager.hasOutputStream()).isTrue(); + assertThat(outputStreamManager.getContentFormat()).isEmpty(); + assertThat(outputStreamManager.getLoggerContext()).isNull(); + assertThat(outputStreamManager.getName()).isEqualTo(DELEGATE_OUTPUT_STREAM_MANAGER_NAME); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithCacheIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithCacheIntegrationTest.java new file mode 100644 index 000000000000..d1d35687f9b2 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithCacheIntegrationTest.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static java.lang.System.lineSeparator; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.net.URL; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.test.junit.categories.LoggingTest; + +@Category(LoggingTest.class) +public class GeodeConsoleAppenderWithCacheIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "GeodeConsoleAppenderWithCacheIntegrationTest_log4j2.xml"; + + private static String configFilePath; + + private InternalCache cache; + private GeodeConsoleAppender geodeConsoleAppender; + private File logFile; + private Logger logger; + private String logMessage; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + String name = testName.getMethodName(); + logFile = new File(temporaryFolder.getRoot(), name + ".log"); + + geodeConsoleAppender = + loggerContextRule.getAppender("STDOUT", GeodeConsoleAppender.class); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + } + + @After + public void tearDown() { + if (cache != null) { + cache.close(); + } + } + + @Test + public void logsToStdoutIfLogFileNotSpecified() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + + cache = (InternalCache) new CacheFactory(config).create(); + + logger.info(logMessage); + + LogEvent foundLogEvent = null; + for (LogEvent logEvent : geodeConsoleAppender.getLogEvents()) { + if (logEvent.getMessage().getFormattedMessage().contains(logMessage)) { + foundLogEvent = logEvent; + break; + } + } + assertThat(foundLogEvent).as(logEventsShouldContain(logMessage, foundLogEvent)).isNotNull(); + } + + @Test + public void stopsLoggingToStdoutWhenLoggingToLogFileStarts() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, logFile.getAbsolutePath()); + + cache = (InternalCache) new CacheFactory(config).create(); + + logger.info(logMessage); + + LogEvent foundLogEvent = null; + for (LogEvent logEvent : geodeConsoleAppender.getLogEvents()) { + if (logEvent.getMessage().getFormattedMessage().contains(logMessage)) { + foundLogEvent = logEvent; + break; + } + } + assertThat(foundLogEvent).as(logEventsShouldNotContain(logMessage, foundLogEvent)).isNull(); + } + + @Test + public void resumesLoggingToStdoutWhenLoggingToLogFileStops() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, logFile.getAbsolutePath()); + + cache = (InternalCache) new CacheFactory(config).create(); + + cache.close(); + + logger.info(logMessage); + + LogEvent foundLogEvent = null; + for (LogEvent logEvent : geodeConsoleAppender.getLogEvents()) { + if (logEvent.getMessage().getFormattedMessage().contains(logMessage)) { + foundLogEvent = logEvent; + break; + } + } + assertThat(foundLogEvent).as(logEventsShouldContain(logMessage, foundLogEvent)).isNotNull(); + } + + private String logEventsShouldContain(String logMessage, LogEvent logEvent) { + return "Expecting:" + lineSeparator() + " " + geodeConsoleAppender.getLogEvents() + + lineSeparator() + "to contain:" + lineSeparator() + " " + logMessage + + lineSeparator() + "but could not find:" + lineSeparator() + " " + logEvent; + } + + private String logEventsShouldNotContain(String logMessage, LogEvent logEvent) { + return "Expecting:" + lineSeparator() + " " + geodeConsoleAppender.getLogEvents() + + lineSeparator() + "to not contain:" + lineSeparator() + " " + logMessage + + lineSeparator() + "but found:" + lineSeparator() + " " + logEvent; + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest.java new file mode 100644 index 000000000000..ed244089daf6 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URL; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.SystemErrRule; +import org.junit.contrib.java.lang.system.SystemOutRule; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link GeodeConsoleAppender} with {@code SystemOutRule} and + * {@code SystemErrRule}. + * + *

+ * Verifies that {@code SystemOutRule} can capture the output of {@link GeodeConsoleAppender}. + * If this behavior changes, then Geode logging tests may also need to change. + */ +@Category(LoggingTest.class) +public class GeodeConsoleAppenderWithSystemOutRuleIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "GeodeConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml"; + + private static String configFilePath; + + private Logger logger; + private String logMessage; + + @ClassRule + public static SystemOutRule systemOutRule = new SystemOutRule().enableLog(); + + @ClassRule + public static SystemErrRule systemErrRule = new SystemErrRule().enableLog(); + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + systemOutRule.clearLog(); + systemErrRule.clearLog(); + + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + } + + @Test + public void staticSystemOutRuleCapturesConsoleAppenderOutput() { + logger.info(logMessage); + + assertThat(systemOutRule.getLog()).contains(logMessage); + assertThat(systemErrRule.getLog()).isEmpty(); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest.java index 00c8da1afe61..a0c96038d0ac 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest.java @@ -32,20 +32,27 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import org.apache.geode.internal.logging.LogService; import org.apache.geode.test.junit.categories.LoggingTest; +/** + * Integration tests for using {@link LogMarker#GEODE_VERBOSE} with {@code MarkerFilter} having + * {@code onMatch} of {@code ACCEPT} and {@code onMismatch} of {@code DENY}. + */ @Category(LoggingTest.class) public class GeodeVerboseMarkerFilterAcceptIntegrationTest { + private static final String CONFIG_FILE_NAME = + "GeodeVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml"; private static final String APPENDER_NAME = "LIST"; private static String configFilePath; + private ListAppender listAppender; private Logger logger; private String logMessage; - private ListAppender listAppender; @ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -53,24 +60,21 @@ public class GeodeVerboseMarkerFilterAcceptIntegrationTest { @Rule public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + @Rule + public TestName testName = new TestName(); + @BeforeClass public static void setUpLogConfigFile() throws Exception { - String configFileName = - GeodeVerboseMarkerFilterAcceptIntegrationTest.class.getSimpleName() + "_log4j2.xml"; - URL resource = getResource(configFileName); - configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), configFileName) + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) .getAbsolutePath(); } @Before public void setUp() throws Exception { - logger = LogService.getLogger(); - logMessage = "this is a log statement"; - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - listAppender = loggerContextRule.getListAppender(APPENDER_NAME); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); } @Test diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest.java index 99a00ae6f0f1..a2015a77321d 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest.java @@ -32,20 +32,27 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import org.apache.geode.internal.logging.LogService; import org.apache.geode.test.junit.categories.LoggingTest; +/** + * Integration tests for using {@link LogMarker#GEMFIRE_VERBOSE} with {@code MarkerFilter} having + * {@code onMatch} of {@code DENY} and {@code onMismatch} of {@code ACCEPT}. + */ @Category(LoggingTest.class) public class GeodeVerboseMarkerFilterDenyIntegrationTest { + private static final String CONFIG_FILE_NAME = + "GeodeVerboseMarkerFilterDenyIntegrationTest_log4j2.xml"; private static final String APPENDER_NAME = "LIST"; private static String configFilePath; + private ListAppender listAppender; private Logger logger; private String logMessage; - private ListAppender listAppender; @ClassRule public static TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -53,24 +60,21 @@ public class GeodeVerboseMarkerFilterDenyIntegrationTest { @Rule public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + @Rule + public TestName testName = new TestName(); + @BeforeClass public static void setUpLogConfigFile() throws Exception { - String configFileName = - GeodeVerboseMarkerFilterDenyIntegrationTest.class.getSimpleName() + "_log4j2.xml"; - URL resource = getResource(configFileName); - configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), configFileName) + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) .getAbsolutePath(); } @Before public void setUp() throws Exception { - logger = LogService.getLogger(); - logMessage = "this is a log statement"; - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); - listAppender = loggerContextRule.getListAppender(APPENDER_NAME); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); } @Test diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CustomConfigWithLogServiceIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogServiceWithCustomLogConfigIntegrationTest.java similarity index 83% rename from geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CustomConfigWithLogServiceIntegrationTest.java rename to geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogServiceWithCustomLogConfigIntegrationTest.java index 23c6f798be72..4d04fc0d8d33 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/CustomConfigWithLogServiceIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogServiceWithCustomLogConfigIntegrationTest.java @@ -14,6 +14,7 @@ */ package org.apache.geode.internal.logging.log4j; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.getConfigurationInfo; import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; import static org.apache.geode.test.util.ResourceUtils.getResource; import static org.assertj.core.api.Assertions.assertThat; @@ -35,16 +36,19 @@ import org.junit.contrib.java.lang.system.SystemOutRule; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; import org.apache.geode.internal.logging.LogService; import org.apache.geode.test.junit.categories.LoggingTest; /** - * Integration tests with custom log4j2 configuration. + * Integration tests for {@link LogService} with custom logging configuration. */ @Category(LoggingTest.class) -public class CustomConfigWithLogServiceIntegrationTest { +public class LogServiceWithCustomLogConfigIntegrationTest { + private static final String CONFIG_FILE_NAME = + "LogServiceWithCustomLogConfigIntegrationTest_log4j2.xml"; private static final String CONFIG_LAYOUT_PREFIX = "CUSTOM"; private static final String CUSTOM_REGEX_STRING = "CUSTOM: level=[A-Z]+ time=\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3} [^ ]{3} message=.*[\\n]+throwable=.*$"; @@ -68,27 +72,29 @@ public class CustomConfigWithLogServiceIntegrationTest { @Rule public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + @Rule + public TestName testName = new TestName(); + @BeforeClass public static void setUpLogConfigFile() throws Exception { - String configFileName = - CustomConfigWithCacheIntegrationTest.class.getSimpleName() + "_log4j2.xml"; - URL resource = getResource(configFileName); - configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), configFileName) + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) .getAbsolutePath(); } @Before public void setUp() throws Exception { - logger = LogService.getLogger(); - logMessage = "this is a log statement"; - - assertThat(LogService.isUsingGemFireDefaultConfig()).as(LogService.getConfigurationInfo()) - .isFalse(); + systemOutRule.clearLog(); + systemErrRule.clearLog(); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); listAppender = loggerContextRule.getListAppender("CUSTOM"); + } - systemOutRule.clearLog(); - systemErrRule.clearLog(); + @Test + public void isUsingGemFireDefaultConfigIsFalse() { + assertThat(Log4jAgent.isUsingGemFireDefaultConfig()).as(getConfigurationInfo()).isFalse(); } @Test diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest.java index 3106d80217b3..0344e35b6455 100644 --- a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest.java +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest.java @@ -14,238 +14,193 @@ */ package org.apache.geode.internal.logging.log4j; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.regex.Pattern; - +import static java.nio.charset.Charset.defaultCharset; +import static org.apache.commons.io.FileUtils.readLines; +import static org.apache.geode.internal.logging.NonBlankStrings.nonBlankStrings; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.net.URL; +import java.util.List; + +import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.message.ParameterizedMessage; +import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; -import org.apache.geode.internal.logging.InternalLogWriter; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.LogMessageRegex; import org.apache.geode.internal.logging.LogService; -import org.apache.geode.internal.logging.PureLogWriter; +import org.apache.geode.internal.logging.SessionContext; import org.apache.geode.test.junit.categories.LoggingTest; /** - * Tests the LogWriterAppender. + * Integration tests for {@link LogWriterAppender}. */ @Category(LoggingTest.class) public class LogWriterAppenderIntegrationTest { - private Level previousLogLevel; - private LogWriterAppender appender; + private static final String CONFIG_FILE_NAME = "LogWriterAppenderIntegrationTest_log4j2.xml"; + private static final String APPENDER_NAME = "LOGWRITER"; + + private static String configFilePath; + + private File logFile; + private Logger logger; + private String logMessage; + private LogWriterAppender logWriterAppender; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } @Before - public void setUp() { - previousLogLevel = LogService.getBaseLogLevel(); + public void setUp() throws Exception { + String name = testName.getMethodName(); + logFile = new File(temporaryFolder.getRoot(), name + ".log"); + + LogConfig config = mock(LogConfig.class); + when(config.getName()).thenReturn(name); + when(config.getLogFile()).thenReturn(logFile); + + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(config); + + SessionContext sessionContext = mock(SessionContext.class); + when(sessionContext.getLogConfigSupplier()).thenReturn(logConfigSupplier); + + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + + logWriterAppender = + loggerContextRule.getAppender(APPENDER_NAME, LogWriterAppender.class); + logWriterAppender.createSession(sessionContext); + logWriterAppender.startSession(); } @After public void tearDown() { - LogService.setBaseLogLevel(previousLogLevel); - if (appender != null) { - appender.stop(); - Configurator.getLoggerConfig(LogService.BASE_LOGGER_NAME).getAppenders() - .remove(appender.getName()); - } + logWriterAppender.stopSession(); + logWriterAppender.clearLogEvents(); + } + + @Test + public void getLogEventsReturnsLoggedEvents() { + logWriterAppender.clearLogEvents(); + + logger.info(logMessage); + + assertThat(logWriterAppender.getLogEvents()).hasSize(1); + LogEvent event = logWriterAppender.getLogEvents().get(0); + assertThat(event.getLoggerName()).isEqualTo(getClass().getName()); + assertThat(event.getLevel()).isEqualTo(Level.INFO); + assertThat(event.getMessage().getFormattedMessage()).isEqualTo(logMessage); + } + + @Test + public void pausedDoesNotLog() { + logWriterAppender.pause(); + logWriterAppender.clearLogEvents(); + + logger.info(logMessage); + + assertThat(logWriterAppender.getLogEvents()).isEmpty(); } - /** - * Verifies that the appender is correctly added and removed from the Log4j configuration and that - * when the configuration is changed the appender is still there. - */ @Test - public void testAppenderToConfigHandling() { - LogService.setBaseLogLevel(Level.TRACE); + public void resumeAfterPausedLogs() { + logWriterAppender.pause(); + logWriterAppender.clearLogEvents(); + logWriterAppender.resume(); - final AppenderContext rootContext = LogService.getAppenderContext(); + logger.info(logMessage); - // Find out home many appenders exist before we get started - final int startingSize = rootContext.getLoggerConfig().getAppenders().size(); + assertThat(logWriterAppender.getLogEvents()).hasSize(1); + } - // System.out.println("Appenders " + - // context.getLoggerConfig().getAppenders().values().toString()); + @Test + public void resumeWithoutPauseStillLogs() { + logWriterAppender.clearLogEvents(); + logWriterAppender.resume(); - // Create the appender and verify it's part of the configuration - final StringWriter stringWriter = new StringWriter(); - final PureLogWriter logWriter = - new PureLogWriter(InternalLogWriter.FINE_LEVEL, new PrintWriter(stringWriter), ""); + logger.info(logMessage); - final AppenderContext[] contexts = new AppenderContext[2]; - contexts[0] = rootContext; // root context - contexts[1] = LogService.getAppenderContext(LogService.BASE_LOGGER_NAME); // "org.apache" - // context + assertThat(logWriterAppender.getLogEvents()).hasSize(1); + } - appender = - LogWriterAppender.create(contexts, LogService.MAIN_LOGGER_NAME, logWriter, null); + @Test + public void isPausedReturnsTrueAfterPause() { + logWriterAppender.pause(); + assertThat(logWriterAppender.isPaused()).isTrue(); + } - assertEquals(rootContext.getLoggerConfig().getAppenders().values().toString(), startingSize + 1, - rootContext.getLoggerConfig().getAppenders().size()); - assertTrue(rootContext.getLoggerConfig().getAppenders().containsKey(appender.getName())); + @Test + public void isPausedReturnsFalseAfterResume() { + logWriterAppender.pause(); + logWriterAppender.resume(); - // Modify the config and verify that the appender still exists - assertEquals(Level.TRACE, LogService.getLogger(LogService.BASE_LOGGER_NAME).getLevel()); - LogService.setBaseLogLevel(Level.DEBUG); - assertEquals(Level.DEBUG, LogService.getLogger(LogService.BASE_LOGGER_NAME).getLevel()); - assertTrue(rootContext.getLoggerConfig().getAppenders().containsKey(appender.getName())); + assertThat(logWriterAppender.isPaused()).isFalse(); + } - // Destroy the appender and verify that it was removed from log4j - appender.destroy(); - assertEquals(rootContext.getLoggerConfig().getAppenders().values().toString(), startingSize, - rootContext.getLoggerConfig().getAppenders().size()); - assertFalse(rootContext.getLoggerConfig().getAppenders().containsKey(appender.getName())); + @Test + public void resumeWithoutPauseDoesNothing() { + logWriterAppender.resume(); + + assertThat(logWriterAppender.isPaused()).isFalse(); + } + + @Test + public void isPausedReturnsFalseByDefault() { + assertThat(logWriterAppender.isPaused()).isFalse(); } - /** - * Verifies that writing to a Log4j logger will end up in the LogWriter's output. - */ @Test - public void testLogOutput() { - // Create the appender - final StringWriter stringWriter = new StringWriter(); - final PureLogWriter logWriter = - new PureLogWriter(InternalLogWriter.FINEST_LEVEL, new PrintWriter(stringWriter), ""); - - final AppenderContext[] contexts = new AppenderContext[2]; - contexts[0] = LogService.getAppenderContext(); // root context - contexts[1] = LogService.getAppenderContext(LogService.BASE_LOGGER_NAME); // "org.apache" - // context - - appender = - LogWriterAppender.create(contexts, LogService.MAIN_LOGGER_NAME, logWriter, null); - - final Logger logger = LogService.getLogger(); - - // set the level to TRACE - Configurator.setLevel(LogService.BASE_LOGGER_NAME, Level.TRACE); - Configurator.setLevel(LogService.MAIN_LOGGER_NAME, Level.TRACE); - - assertEquals(Level.TRACE, logger.getLevel()); - - logger.trace("TRACE MESSAGE"); - assertTrue(Pattern.compile(".*\\[finest .*TRACE MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logger.debug("DEBUG MESSAGE"); - assertTrue(Pattern.compile(".*\\[fine .*DEBUG MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logger.info("INFO MESSAGE"); - assertTrue(Pattern.compile(".*\\[info .*INFO MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logger.warn("ExpectedStrings: WARNING MESSAGE"); - assertTrue(Pattern.compile(".*\\[warning .*WARNING MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logger.error("ExpectedStrings: ERROR MESSAGE"); - assertTrue(Pattern.compile(".*\\[error .*ERROR MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logger.fatal("ExpectedStrings: FATAL MESSAGE"); - assertTrue(Pattern.compile(".*\\[severe .*FATAL MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - final Logger lowerLevelLogger = - LogService.getLogger(LogService.BASE_LOGGER_NAME + ".subpackage"); - lowerLevelLogger.fatal("ExpectedStrings: FATAL MESSAGE"); - assertTrue(Pattern.compile(".*\\[severe .*FATAL MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - appender.destroy(); - assertFalse(Configurator.getLoggerConfig(LogService.BASE_LOGGER_NAME).getAppenders() - .containsKey(appender.getName())); + public void logsToFile() throws Exception { + logger.info(logMessage); + + assertThat(logFile).exists(); + String content = FileUtils.readFileToString(logFile, defaultCharset()).trim(); + assertThat(content).contains(logMessage); } - /** - * Verifies that logging occurs at the levels set in the LogWriter - */ @Test - public void testLogWriterLevels() { - final String loggerName = LogService.MAIN_LOGGER_NAME; // this.getClass().getName(); - LogService.getLogger(); // Force logging to be initialized - - // Create the LogWriterLogger that will be attached to the appender - final LogWriterLogger logWriterLogger = LogWriterLogger.create(loggerName, false); - logWriterLogger.setLevel(Level.INFO); - - // Create the appender - final StringWriter stringWriter = new StringWriter(); - final PureLogWriter logWriter = - new PureLogWriter(InternalLogWriter.FINEST_LEVEL, new PrintWriter(stringWriter), ""); - - final AppenderContext[] contexts = new AppenderContext[2]; - // root context - contexts[0] = LogService.getAppenderContext(); - // "org.apache" context - contexts[1] = LogService.getAppenderContext(LogService.BASE_LOGGER_NAME); - - appender = LogWriterAppender.create(contexts, loggerName, logWriter, null); - - logWriter.finest("DIRECT MESSAGE"); - assertTrue(Pattern.compile(".*\\[finest .*DIRECT MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.INFO).setLoggerFqcn("NAME") - .setLoggerName("NAME").setMessage(new ParameterizedMessage("LOGEVENT MESSAGE")).build(); - appender.append(event); - assertTrue(Pattern.compile(".*\\[info .*LOGEVENT MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logWriterLogger.finest("FINEST MESSAGE"); - assertFalse(Pattern.compile(".*\\[finest .*FINEST MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logWriterLogger.fine("FINE MESSAGE"); - assertFalse(Pattern.compile(".*\\[fine .*FINE MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logWriterLogger.info("INFO MESSAGE"); - assertTrue(stringWriter.toString(), - Pattern.compile(".*\\[info .*INFO MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - // Change the level - logWriterLogger.setLevel(Level.DEBUG); - - logWriterLogger.finest("FINEST MESSAGE"); - assertFalse(Pattern.compile(".*\\[finest .*FINEST MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logWriterLogger.fine("FINE MESSAGE"); - assertTrue(Pattern.compile(".*\\[fine .*FINE MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - logWriterLogger.info("INFO MESSAGE"); - assertTrue(Pattern.compile(".*\\[info .*INFO MESSAGE.*", Pattern.DOTALL) - .matcher(stringWriter.toString()).matches()); - stringWriter.getBuffer().setLength(0); - - appender.destroy(); + public void linesInFileShouldMatchPatternLayout() throws Exception { + logger.info(logMessage); + + assertThat(logFile).exists(); + + List lines = nonBlankStrings(readLines(logFile, defaultCharset())); + assertThat(lines).hasSize(1); + + for (String line : lines) { + assertThat(line).matches(LogMessageRegex.getRegex()); + } } } diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest.java new file mode 100644 index 000000000000..06f9af330617 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.internal.logging.Configuration.DEFAULT_LOGWRITER_LEVEL; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.net.URL; + +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.SessionContext; +import org.apache.geode.internal.statistics.StatisticsConfig; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link LogWriterAppender} with + * {@link ConfigurationProperties#LOG_FILE_SIZE_LIMIT} and + * {@link ConfigurationProperties#LOG_DISK_SPACE_LIMIT}. + */ +@Category(LoggingTest.class) +public class LogWriterAppenderWithLimitsIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "LogWriterAppenderWithLimitsIntegrationTest_log4j2.xml"; + private static final String APPENDER_NAME = "LOGWRITER"; + private static final int MAX_LOG_DISK_SPACE_LIMIT = 1_000_000; + private static final int MAX_LOG_FILE_SIZE_LIMIT = 1_000_000; + + private static String configFilePath; + + private LogWriterAppender logWriterAppender; + private LogConfig config; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + logWriterAppender = loggerContextRule.getAppender(APPENDER_NAME, + LogWriterAppender.class); + + String name = testName.getMethodName(); + File logFile = temporaryFolder.newFile(name + ".log"); + + config = mock(LogConfig.class); + when(config.getName()).thenReturn(name); + when(config.getLogFile()).thenReturn(logFile); + when(config.getLogLevel()).thenReturn(DEFAULT_LOGWRITER_LEVEL); + when(config.getLogDiskSpaceLimit()).thenReturn(MAX_LOG_DISK_SPACE_LIMIT); + when(config.getLogFileSizeLimit()).thenReturn(MAX_LOG_FILE_SIZE_LIMIT); + + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(config); + when(logConfigSupplier.getStatisticsConfig()).thenReturn(mock(StatisticsConfig.class)); + + SessionContext sessionContext = mock(SessionContext.class); + when(sessionContext.getLogConfigSupplier()).thenReturn(logConfigSupplier); + + logWriterAppender.createSession(sessionContext); + } + + @After + public void tearDown() throws Exception { + logWriterAppender.clearLogEvents(); + } + + @Test + public void logDiskSpaceLimit() { + // log-disk-space-limit starts out as MAX_LOG_DISK_SPACE_LIMIT + LogConfig logConfig = logWriterAppender.getLogWriter().getConfig(); + assertThat(logConfig.getLogDiskSpaceLimit()).isEqualTo(MAX_LOG_DISK_SPACE_LIMIT); + + // log-disk-space-limit changes to 1_000 + when(config.getLogDiskSpaceLimit()).thenReturn(1_000); + logWriterAppender.configChanged(); + + assertThat(logConfig.getLogDiskSpaceLimit()).isEqualTo(1_000); + + // log-disk-space-limit changes back to MAX_LOG_DISK_SPACE_LIMIT + when(config.getLogDiskSpaceLimit()).thenReturn(MAX_LOG_DISK_SPACE_LIMIT); + logWriterAppender.configChanged(); + + assertThat(logConfig.getLogDiskSpaceLimit()).isEqualTo(MAX_LOG_DISK_SPACE_LIMIT); + } + + @Test + public void logFileSizeLimit() { + // log-file-size-limit starts out as MAX_LOG_FILE_SIZE_LIMIT + LogConfig logConfig = logWriterAppender.getLogWriter().getConfig(); + assertThat(logConfig.getLogFileSizeLimit()).isEqualTo(MAX_LOG_FILE_SIZE_LIMIT); + + // log-file-size-limit changes to 1_000 + when(config.getLogFileSizeLimit()).thenReturn(1_000); + logWriterAppender.configChanged(); + + assertThat(logConfig.getLogFileSizeLimit()).isEqualTo(1_000); + + // log-disk-space-limit changes back to MAX_LOG_FILE_SIZE_LIMIT + when(config.getLogFileSizeLimit()).thenReturn(MAX_LOG_FILE_SIZE_LIMIT); + logWriterAppender.configChanged(); + + assertThat(logConfig.getLogFileSizeLimit()).isEqualTo(MAX_LOG_FILE_SIZE_LIMIT); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest.java new file mode 100644 index 000000000000..ee38fec79ead --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static java.lang.System.lineSeparator; +import static java.nio.charset.Charset.defaultCharset; +import static org.apache.commons.io.FileUtils.readFileToString; +import static org.apache.commons.io.FileUtils.readLines; +import static org.apache.geode.internal.logging.LogMessageRegex.Group; +import static org.apache.geode.internal.logging.LogMessageRegex.getPattern; +import static org.apache.geode.internal.logging.NonBlankStrings.nonBlankStrings; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.net.URL; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.SessionContext; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link LogWriterAppender} with {@code memberName} in + * {@code log4j2.xml}. + */ +@Category(LoggingTest.class) +public class LogWriterAppenderWithMemberNameInXmlIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "LogWriterAppenderWithMemberNameInXmlIntegrationTest_log4j2.xml"; + private static final String APPENDER_NAME = "LOGWRITERWITHMEMBERNAME"; + private static final String MEMBER_NAME = "MEMBERNAME"; + + private static String configFilePath; + + private LogWriterAppender logWriterAppender; + private File logFile; + private Logger logger; + private String logMessage; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + String logFileName = MEMBER_NAME + ".log"; + logFile = new File(temporaryFolder.newFolder(testName.getMethodName()), logFileName); + + LogConfig config = mock(LogConfig.class); + when(config.getName()).thenReturn(""); + when(config.getLogFile()).thenReturn(logFile); + + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(config); + + SessionContext sessionContext = mock(SessionContext.class); + when(sessionContext.getLogConfigSupplier()).thenReturn(logConfigSupplier); + + logWriterAppender = + loggerContextRule.getAppender(APPENDER_NAME, LogWriterAppender.class); + logWriterAppender.createSession(sessionContext); + logWriterAppender.startSession(); + + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + } + + @After + public void tearDown() { + logWriterAppender.stopSession(); + } + + @Test + public void logsToSpecifiedFile() throws Exception { + logger.info(logMessage); + + assertThat(logFile).exists(); + String content = readFileToString(logFile, defaultCharset()).trim(); + assertThat(content).contains(logMessage); + } + + @Test + public void logLinesInFileShouldContainMemberName() throws Exception { + logger.info(logMessage); + + assertThat(logFile).exists(); + + List lines = nonBlankStrings(readLines(logFile, defaultCharset())); + assertThat(lines).hasSize(1); + + for (String line : lines) { + Matcher matcher = getPattern().matcher(line); + assertThat(matcher.matches()).as(failedToMatchRegex(line, getPattern())).isTrue(); + assertThat(matcher.group(Group.MEMBER_NAME.getName())).isEqualTo(MEMBER_NAME); + } + + } + + private String failedToMatchRegex(String line, Pattern pattern) { + String $ = lineSeparator(); + return $ + "Line:" + $ + " " + line + $ + "failed to match regex:" + $ + " " + pattern + $; + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest.java new file mode 100644 index 000000000000..9e3f9397b1af --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; +import static org.apache.geode.test.util.ResourceUtils.createFileFromResource; +import static org.apache.geode.test.util.ResourceUtils.getResource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.net.URL; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.SessionContext; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.categories.LoggingTest; +import org.apache.geode.test.junit.categories.SecurityTest; + +/** + * Integration tests for {@link LogWriterAppender} with security logger and + * {@link ConfigurationProperties#SECURITY_LOG_FILE}. + */ +@Category({LoggingTest.class, SecurityTest.class}) +public class SecurityLogWriterAppenderIntegrationTest { + + private static final String CONFIG_FILE_NAME = + "SecurityLogWriterAppenderIntegrationTest_log4j2.xml"; + private static final String SECURITY_APPENDER_NAME = "SECURITYLOGWRITER"; + + private static String configFilePath; + + private LogWriterAppender securityLogWriterAppender; + private File securityLogFile; + private SessionContext sessionContext; + private LogConfigSupplier logConfigSupplier; + private Logger securityGeodeLogger; + private String logMessage; + + @ClassRule + public static TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public LoggerContextRule loggerContextRule = new LoggerContextRule(configFilePath); + + @Rule + public TestName testName = new TestName(); + + @BeforeClass + public static void setUpLogConfigFile() throws Exception { + URL resource = getResource(CONFIG_FILE_NAME); + configFilePath = createFileFromResource(resource, temporaryFolder.getRoot(), CONFIG_FILE_NAME) + .getAbsolutePath(); + } + + @Before + public void setUp() throws Exception { + securityLogWriterAppender = loggerContextRule.getAppender(SECURITY_APPENDER_NAME, + LogWriterAppender.class); + + String name = testName.getMethodName(); + securityLogFile = new File(temporaryFolder.getRoot(), name + "-security.log"); + + LogConfig logConfig = mock(LogConfig.class); + when(logConfig.getName()).thenReturn(name); + when(logConfig.getSecurityLogFile()).thenReturn(securityLogFile); + + logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(logConfig); + + sessionContext = mock(SessionContext.class); + when(sessionContext.getLogConfigSupplier()).thenReturn(logConfigSupplier); + + securityGeodeLogger = LogService.getLogger(SECURITY_LOGGER_NAME); + logMessage = "Logging in " + testName.getMethodName(); + } + + @Test + public void securityLogWriterAppenderLogEventsIsEmptyByDefault() { + assertThat(securityLogWriterAppender.getLogEvents()).isEmpty(); + } + + @Test + public void geodeSecurityLoggerAppendsToSecurityLogWriterAppender() { + securityLogWriterAppender.createSession(sessionContext); + securityLogWriterAppender.startSession(); + + securityGeodeLogger.info(logMessage); + + assertThat(securityLogWriterAppender.getLogEvents()).hasSize(1); + } + + @Test + public void securityLogFileIsEmptyByDefault() { + securityGeodeLogger.info(logMessage); + + assertThat(securityLogFile).doesNotExist(); + } + + @Test + public void securityGeodeLoggerLogsToSecurityLogFile() { + securityLogWriterAppender.createSession(sessionContext); + securityLogWriterAppender.startSession(); + + securityGeodeLogger.info(logMessage); + + LogFileAssert.assertThat(securityLogFile).exists().contains(logMessage); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/management/MemberMXBeanShowLogIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/management/MemberMXBeanShowLogIntegrationTest.java new file mode 100644 index 000000000000..5c252c0e15b9 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/management/MemberMXBeanShowLogIntegrationTest.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.management; + +import static java.lang.System.lineSeparator; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.management.internal.ManagementConstants.DEFAULT_SHOW_LOG_LINES; +import static org.apache.geode.management.internal.ManagementConstants.MAX_SHOW_LOG_LINES; +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.util.Properties; + +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.management.internal.SystemManagementService; +import org.apache.geode.test.junit.categories.LoggingTest; +import org.apache.geode.test.junit.categories.ManagementTest; + +/** + * Integration tests for {@link MemberMXBean} with just a {@link Cache}. + */ +@Category({ManagementTest.class, LoggingTest.class}) +public class MemberMXBeanShowLogIntegrationTest { + + private File logFile; + private InternalCache cache; + private SystemManagementService managementService; + private Logger logger; + private String logMessage; + + private MemberMXBean memberMXBean; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() throws Exception { + logFile = new File(temporaryFolder.getRoot(), testName.getMethodName() + ".log"); + logger = LogService.getLogger(); + logMessage = "Logging in " + testName.getMethodName(); + } + + @After + public void tearDown() { + cache.close(); + } + + @Test + public void showLogWithoutLogFile() { + createCacheWithoutLogFile(); + + assertThat(memberMXBean.showLog(0)).isEqualTo( + "No log file was specified in the configuration, messages will be directed to stdout."); + } + + @Test + public void showLogIsNeverEmpty() { + createCacheWithLogFile(); + + assertThat(memberMXBean.showLog(-20)).isNotEmpty(); + assertThat(memberMXBean.showLog(0)).isNotEmpty(); + assertThat(memberMXBean.showLog(DEFAULT_SHOW_LOG_LINES)).isNotEmpty(); + assertThat(memberMXBean.showLog(MAX_SHOW_LOG_LINES)).isNotEmpty(); + } + + @Test + public void showLogZeroUsesDefault() { + createCacheWithLogFile(); + + String log = memberMXBean.showLog(0); + + // splitting on lineSeparator() results in a length near 30 + assertThat(log.split(lineSeparator()).length).as("Log: " + log).isGreaterThan(25) + .isLessThan(35); + } + + @Test + public void showLogNegativeUsesDefault() { + createCacheWithLogFile(); + + String log = memberMXBean.showLog(-20); + + // splitting on lineSeparator() results in a length near 30 + assertThat(log.split(lineSeparator()).length).as("Log: " + log).isGreaterThan(25) + .isLessThan(35); + } + + @Test + public void showLogDefault() { + createCacheWithLogFile(); + + String log = memberMXBean.showLog(DEFAULT_SHOW_LOG_LINES); + + // splitting on lineSeparator() results in a length near 30 + assertThat(log.split(lineSeparator()).length).as("Log: " + log).isGreaterThan(25) + .isLessThan(35); + } + + @Test + public void showLogMaxLinesCount() { + createCacheWithLogFile(); + + String log = memberMXBean.showLog(MAX_SHOW_LOG_LINES); + + // splitting on lineSeparator() results in a length near 100 + assertThat(log.split(lineSeparator()).length).as("Log: " + log).isGreaterThan(90) + .isLessThan(110); + } + + @Test + public void showLogGreaterThanMaxUsesMax() { + createCacheWithLogFile(); + + String log = memberMXBean.showLog(MAX_SHOW_LOG_LINES * 10); + + // splitting on lineSeparator() results in a length near 100 + assertThat(log.split(lineSeparator()).length).as("Log: " + log).isGreaterThan(90) + .isLessThan(110); + } + + @Test + public void showLogContainsMostRecentlyLoggedMessage() { + createCacheWithLogFile(); + logger.info(logMessage); + + String log = memberMXBean.showLog(0); + + assertThat(log).contains(logMessage); + } + + private void createCacheWithLogFile() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_FILE, logFile.getAbsolutePath()); + + cache = (InternalCache) new CacheFactory(config).create(); + + managementService = + (SystemManagementService) ManagementService.getExistingManagementService(cache); + await().until(() -> managementService.getMemberMXBean() != null); + memberMXBean = managementService.getMemberMXBean(); + assertThat(memberMXBean).isNotNull(); + } + + private void createCacheWithoutLogFile() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + + cache = (InternalCache) new CacheFactory(config).create(); + + managementService = + (SystemManagementService) ManagementService.getExistingManagementService(cache); + await().until(() -> managementService.getMemberMXBean() != null); + memberMXBean = managementService.getMemberMXBean(); + assertThat(memberMXBean).isNotNull(); + } +} diff --git a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunctionIntegrationTest.java b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunctionIntegrationTest.java new file mode 100644 index 000000000000..29276dbb4541 --- /dev/null +++ b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunctionIntegrationTest.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.management.internal.cli.functions; + +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.geode.distributed.ConfigurationProperties.SECURITY_LOG_LEVEL; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Properties; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; + +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.execute.FunctionContext; +import org.apache.geode.cache.execute.ResultSender; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.logging.InternalLogWriter; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Integration tests for {@link ChangeLogLevelFunction}. + */ +@Category(LoggingTest.class) +public class ChangeLogLevelFunctionIntegrationTest { + + private static final String APPLICATION_LOGGER_NAME = "com.application"; + + private InternalCache cache; + private Logger geodeLogger; + private Logger applicationLogger; + private InternalLogWriter mainLogWriter; + private InternalLogWriter securityLogWriter; + private LogConfig logConfig; + private FunctionContext functionContext; + + private ChangeLogLevelFunction changeLogLevelFunction; + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + @Before + public void setUp() { + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_LEVEL, Level.INFO.name()); + config.setProperty(SECURITY_LOG_LEVEL, Level.INFO.name()); + + cache = (InternalCache) new CacheFactory(config).create(); + InternalDistributedSystem system = cache.getInternalDistributedSystem(); + + mainLogWriter = (InternalLogWriter) cache.getLogger(); + assertThat(mainLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + securityLogWriter = (InternalLogWriter) cache.getSecurityLogger(); + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + + geodeLogger = LogService.getLogger(); + applicationLogger = LogManager.getLogger(APPLICATION_LOGGER_NAME); + + logConfig = system.getLogConfig(); + assertThat(logConfig.getLogLevel()).isEqualTo(INFO.intLevel()); + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + + functionContext = mock(FunctionContext.class); + when(functionContext.getCache()).thenReturn(cache); + when(functionContext.getArguments()).thenReturn(new Object[] {Level.WARN.name()}); + when(functionContext.getResultSender()).thenReturn(mock(ResultSender.class)); + + changeLogLevelFunction = new ChangeLogLevelFunction(); + } + + @After + public void tearDown() throws Exception { + if (cache != null) { + cache.close(); + } + } + + @Test + public void changesMainLogWriterLevel() { + changeLogLevelFunction.execute(functionContext); + + assertThat(mainLogWriter.getLogWriterLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void changesLogConfigLogLevel() { + changeLogLevelFunction.execute(functionContext); + + assertThat(logConfig.getLogLevel()).isEqualTo(WARNING.intLevel()); + } + + @Test + public void doesNotChangeSecurityLogWriterLogLevel() { + changeLogLevelFunction.execute(functionContext); + + assertThat(securityLogWriter.getLogWriterLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void doesNotChangeLogConfigSecurityLogLevel() { + changeLogLevelFunction.execute(functionContext); + + assertThat(logConfig.getSecurityLogLevel()).isEqualTo(INFO.intLevel()); + } + + @Test + public void changesGeodeLoggerLogLevel() { + changeLogLevelFunction.execute(functionContext); + + assertThat(geodeLogger.getLevel()).isEqualTo(Level.WARN); + } + + @Test + public void doesNotChangeApplicationLoggerLogLevel() { + changeLogLevelFunction.execute(functionContext); + + assertThat(applicationLogger.getLevel()).isEqualTo(Level.INFO); + } + + @Test + public void changesGemFireLogLevelSystemProperty() { + changeLogLevelFunction.execute(functionContext); + + assertThat(System.getProperty(DistributionConfig.GEMFIRE_PREFIX + LOG_LEVEL)) + .isEqualTo(Level.WARN.name()); + } + + @Test + public void doesNotChangeGemFireSecurityLogLevelSystemProperty() { + changeLogLevelFunction.execute(functionContext); + + assertThat(System.getProperty(DistributionConfig.GEMFIRE_PREFIX + SECURITY_LOG_LEVEL)).isNull(); + } +} diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt b/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt index f67da94f178d..96d78f6f83a4 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt +++ b/geode-core/src/integrationTest/resources/org/apache/geode/codeAnalysis/excludedClasses.txt @@ -14,11 +14,14 @@ org/apache/geode/distributed/internal/membership/gms/mgr/GMSMembershipManager$Bo org/apache/geode/distributed/internal/tcpserver/LocatorCancelException org/apache/geode/internal/AbstractConfig$SortedProperties org/apache/geode/internal/AvailablePort$Keeper +org/apache/geode/internal/Banner$BannerHeader org/apache/geode/internal/DSCODE org/apache/geode/internal/ExitCode org/apache/geode/internal/JarDeployer org/apache/geode/internal/ObjIdConcurrentMap org/apache/geode/internal/ObjIdConcurrentMap$Segment +org/apache/geode/internal/alerting/AlertLevel +org/apache/geode/internal/alerting/AlertingSession$State org/apache/geode/internal/cache/DiskStoreMonitor$DiskState org/apache/geode/internal/cache/InitialImageOperation$GIITestHook org/apache/geode/internal/cache/Oplog$OPLOG_TYPE @@ -47,8 +50,12 @@ org/apache/geode/internal/hll/HyperLogLogPlus$Builder org/apache/geode/internal/hll/HyperLogLogPlus$Format org/apache/geode/internal/hll/HyperLogLogPlus$HyperLogLogPlusMergeException org/apache/geode/internal/hll/HyperLogLogPlus$SerializationHolder +org/apache/geode/internal/logging/Configuration$LogLevelUpdateOccurs +org/apache/geode/internal/logging/Configuration$LogLevelUpdateScope +org/apache/geode/internal/logging/LogMessageRegex$Group +org/apache/geode/internal/logging/LogWriterLevel +org/apache/geode/internal/logging/SessionContext$State org/apache/geode/internal/logging/log4j/FastLogger -org/apache/geode/internal/logging/log4j/LogWriterAppenders$Identifier org/apache/geode/internal/logging/log4j/LogWriterLogger org/apache/geode/internal/logging/log4j/message/GemFireParameterizedMessage org/apache/geode/internal/logging/log4j/message/GemFireParameterizedMessageFactory diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..06baee97ad5e --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/BothLogWriterAppendersIntegrationTest_log4j2.xml @@ -0,0 +1,44 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CustomConfigWithLogServiceIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CacheWithCustomLogConfigIntegrationTest_log4j2.xml similarity index 86% rename from geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CustomConfigWithLogServiceIntegrationTest_log4j2.xml rename to geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CacheWithCustomLogConfigIntegrationTest_log4j2.xml index e57f9d4c95d8..6994f4054498 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CustomConfigWithLogServiceIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CacheWithCustomLogConfigIntegrationTest_log4j2.xml @@ -13,7 +13,7 @@ ~ or implied. See the License for the specific language governing permissions and limitations under ~ the License. --> - + CUSTOM: level=%level time=%date{yyyy/MM/dd HH:mm:ss.SSS z} message=%message%nthrowable=%throwable%n @@ -25,15 +25,15 @@ - - + + - + - + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..c77540bcca99 --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConfigurationWithLogLevelChangesIntegrationTest_log4j2.xml @@ -0,0 +1,38 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest_log4j2.xml index 87196fe62516..58aaa1ca9d2a 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithLoggerContextRuleIntegrationTest_log4j2.xml @@ -1,21 +1,19 @@ - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n @@ -23,7 +21,6 @@ - @@ -36,7 +33,6 @@ - diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..8eab15528002 --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithBothLogWriterAppendersIntegrationTest_log4j2.xml @@ -0,0 +1,44 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..c77540bcca99 --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/DistributedSystemWithLogLevelChangesIntegrationTest_log4j2.xml @@ -0,0 +1,38 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml index 2d6534ab5a1b..6757bf772080 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml @@ -13,7 +13,7 @@ ~ or implied. See the License for the specific language governing permissions and limitations under ~ the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest_log4j2.xml index 8509b4181a6d..a741d106bbca 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GemfireVerboseMarkerFilterDenyIntegrationTest_log4j2.xml @@ -13,7 +13,7 @@ ~ or implied. See the License for the specific language governing permissions and limitations under ~ the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..edfa2d8113b3 --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderIntegrationTest_log4j2.xml @@ -0,0 +1,38 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithCacheIntegrationTest_log4j2.xml similarity index 69% rename from geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml rename to geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithCacheIntegrationTest_log4j2.xml index 7f38e1472f24..76940ecae71f 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/ConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithCacheIntegrationTest_log4j2.xml @@ -15,14 +15,22 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n + true - + - + + + + + + + + @@ -31,10 +39,15 @@ + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..fca1e7011713 --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeConsoleAppenderWithSystemOutRuleIntegrationTest_log4j2.xml @@ -0,0 +1,38 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml index f73ea4bfa01c..cfeba88d4e50 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterAcceptIntegrationTest_log4j2.xml @@ -13,7 +13,7 @@ ~ or implied. See the License for the specific language governing permissions and limitations under ~ the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest_log4j2.xml index 5a32d9c514f3..08cee9435ecc 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/GeodeVerboseMarkerFilterDenyIntegrationTest_log4j2.xml @@ -13,7 +13,7 @@ ~ or implied. See the License for the specific language governing permissions and limitations under ~ the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CustomConfigWithCacheIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogServiceWithCustomLogConfigIntegrationTest_log4j2.xml similarity index 96% rename from geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CustomConfigWithCacheIntegrationTest_log4j2.xml rename to geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogServiceWithCustomLogConfigIntegrationTest_log4j2.xml index e57f9d4c95d8..a6d2d1270f82 100644 --- a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/CustomConfigWithCacheIntegrationTest_log4j2.xml +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogServiceWithCustomLogConfigIntegrationTest_log4j2.xml @@ -13,7 +13,7 @@ ~ or implied. See the License for the specific language governing permissions and limitations under ~ the License. --> - + CUSTOM: level=%level time=%date{yyyy/MM/dd HH:mm:ss.SSS z} message=%message%nthrowable=%throwable%n diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..2b06d9f3468e --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderIntegrationTest_log4j2.xml @@ -0,0 +1,38 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..6aee268e44d8 --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithLimitsIntegrationTest_log4j2.xml @@ -0,0 +1,38 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..a7348058571b --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/LogWriterAppenderWithMemberNameInXmlIntegrationTest_log4j2.xml @@ -0,0 +1,38 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest_log4j2.xml b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest_log4j2.xml new file mode 100644 index 000000000000..c0dac6a1a179 --- /dev/null +++ b/geode-core/src/integrationTest/resources/org/apache/geode/internal/logging/log4j/SecurityLogWriterAppenderIntegrationTest_log4j2.xml @@ -0,0 +1,39 @@ + + + + + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} %memberName <%thread> tid=%hexTid] %message%n%throwable%n + + + + + + + + + + + + + + + + + + + + + diff --git a/geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/CacheLoggingBenchmark.java b/geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/CacheLoggingBenchmark.java new file mode 100644 index 000000000000..e9684aa604bf --- /dev/null +++ b/geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/CacheLoggingBenchmark.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.apache.geode.cache.RegionShortcut.LOCAL; +import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE; +import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.logging.log4j.Level.INFO; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.util.Properties; + +import org.apache.logging.log4j.LogManager; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.Region; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.rules.accessible.AccessibleTemporaryFolder; + +@Measurement(iterations = 1, time = 1, timeUnit = MINUTES) +@Warmup(iterations = 1, time = 1, timeUnit = MINUTES) +@Fork(1) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(SECONDS) +@State(Scope.Benchmark) +@SuppressWarnings("unused") +public class CacheLoggingBenchmark { + + private FastLogger fastLogger; + private String message; + + private AccessibleTemporaryFolder temporaryFolder; + private InternalCache cache; + private Region region; + private String key; + private String value; + + @Setup(Level.Trial) + public void setUp() throws Throwable { + temporaryFolder = new AccessibleTemporaryFolder(); + temporaryFolder.before(); + + String name = getClass().getSimpleName(); + File logFile = new File(temporaryFolder.getRoot(), name + ".log"); + + Properties config = new Properties(); + config.setProperty(LOCATORS, ""); + config.setProperty(LOG_LEVEL, "INFO"); + config.setProperty(LOG_FILE, logFile.getAbsolutePath()); + + assertThat(logFile).doesNotExist(); + cache = (InternalCache) new CacheFactory(config).create(); + assertThat(logFile).exists(); + + region = cache.createRegionFactory(LOCAL).create(name + "-region"); + + fastLogger = new FastLogger(LogManager.getLogger()); + assertThat(fastLogger.getLevel()).isEqualTo(INFO); + assertThat(fastLogger.isDelegating()).isFalse(); + + message = "message"; + key = "key"; + value = "value"; + + LogFileAssert.assertThat(logFile).doesNotContain(message); + fastLogger.info(message); + LogFileAssert.assertThat(logFile).contains(message); + } + + @TearDown(Level.Trial) + public void tearDown() { + cache.close(); + temporaryFolder.after(); + } + + @Benchmark + public void infoLogStatement() { + fastLogger.info(message); + } + + @Benchmark + public void putStatement() { + region.put(key, value); + } +} diff --git a/geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderBenchmark.java b/geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderBenchmark.java new file mode 100644 index 000000000000..24f0e65aeba8 --- /dev/null +++ b/geode-core/src/jmh/java/org/apache/geode/internal/logging/log4j/LogWriterAppenderBenchmark.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.GEODE_CONSOLE_APPENDER_NAME; +import static org.apache.geode.internal.logging.log4j.Log4jAgent.LOGWRITER_APPENDER_NAME; +import static org.apache.logging.log4j.Level.INFO; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.SessionContext; +import org.apache.geode.test.assertj.LogFileAssert; +import org.apache.geode.test.junit.rules.accessible.AccessibleTemporaryFolder; + +@Measurement(iterations = 1, time = 1, timeUnit = MINUTES) +@Warmup(iterations = 1, time = 1, timeUnit = MINUTES) +@Fork(1) +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(SECONDS) +@State(Scope.Benchmark) +@SuppressWarnings("unused") +public class LogWriterAppenderBenchmark { + + private FastLogger fastLogger; + private String message; + + private AccessibleTemporaryFolder temporaryFolder; + private LogWriterAppender logWriterAppender; + + @Setup(Level.Trial) + public void setUp() throws Throwable { + temporaryFolder = new AccessibleTemporaryFolder(); + temporaryFolder.before(); + + String name = getClass().getSimpleName(); + File logFile = new File(temporaryFolder.getRoot(), name + ".log"); + + LogConfig config = mock(LogConfig.class); + when(config.getName()).thenReturn(name); + when(config.getLogFile()).thenReturn(logFile); + + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + when(logConfigSupplier.getLogConfig()).thenReturn(config); + + SessionContext sessionContext = mock(SessionContext.class); + when(sessionContext.getLogConfigSupplier()).thenReturn(logConfigSupplier); + + Logger coreLogger = (Logger) LogManager.getRootLogger(); + LoggerContext context = coreLogger.getContext(); + Configuration configuration = context.getConfiguration(); + + LoggerConfig loggerConfig = configuration.getLoggerConfig(coreLogger.getName()); + loggerConfig.removeAppender(GEODE_CONSOLE_APPENDER_NAME); + context.updateLoggers(); + + assertThat(logFile).doesNotExist(); + logWriterAppender = + LogWriterAppender.class.cast(configuration.getAppenders().get(LOGWRITER_APPENDER_NAME)); + logWriterAppender.createSession(sessionContext); + logWriterAppender.startSession(); + assertThat(logFile).exists(); + + FastLogger.setDelegating(false); + fastLogger = new FastLogger(LogManager.getLogger()); + assertThat(fastLogger.getLevel()).isEqualTo(INFO); + assertThat(fastLogger.isDelegating()).isFalse(); + + message = "message"; + + LogFileAssert.assertThat(logFile).doesNotContain(message); + fastLogger.info(message); + LogFileAssert.assertThat(logFile).contains(message); + } + + @TearDown(Level.Trial) + public void tearDown() { + logWriterAppender.stopSession(); + temporaryFolder.after(); + } + + @Benchmark + public void infoLogStatement() { + fastLogger.info(message); + } +} diff --git a/geode-core/src/main/java/org/apache/geode/admin/internal/AdminDistributedSystemImpl.java b/geode-core/src/main/java/org/apache/geode/admin/internal/AdminDistributedSystemImpl.java index c2b41bfa0fc9..7835de100afc 100755 --- a/geode-core/src/main/java/org/apache/geode/admin/internal/AdminDistributedSystemImpl.java +++ b/geode-core/src/main/java/org/apache/geode/admin/internal/AdminDistributedSystemImpl.java @@ -93,9 +93,9 @@ import org.apache.geode.internal.logging.InternalLogWriter; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LogWriterFactory; +import org.apache.geode.internal.logging.LoggingSession; +import org.apache.geode.internal.logging.NullLoggingSession; import org.apache.geode.internal.logging.log4j.LogMarker; -import org.apache.geode.internal.logging.log4j.LogWriterAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; import org.apache.geode.internal.util.concurrent.FutureResult; /** @@ -151,8 +151,6 @@ public class AdminDistributedSystemImpl implements org.apache.geode.admin.AdminD private volatile Set alertListeners = Collections.emptySet(); private final Object alertLock = new Object(); - private LogWriterAppender logWriterAppender; - private InternalLogWriter logWriter; /** The membership listeners registered on this distributed system */ @@ -164,6 +162,8 @@ public class AdminDistributedSystemImpl implements org.apache.geode.admin.AdminD private volatile List cacheListeners = Collections.EMPTY_LIST; private final Object cacheListLock = new Object(); + private final LoggingSession loggingSession; + /** * reference to AdminDistributedSystemImpl instance for feature requests #32887. *

@@ -191,12 +191,17 @@ public class AdminDistributedSystemImpl implements org.apache.geode.admin.AdminD // Constructor(s) // ------------------------------------------------------------------------- + private static LoggingSession createLoggingSession() { + return NullLoggingSession.create(); + } + /** * Constructs new DistributedSystemImpl with the given configuration. * * @param config configuration defining this distributed system */ public AdminDistributedSystemImpl(DistributedSystemConfigImpl config) { + loggingSession = createLoggingSession(); // init from config... this.config = config; @@ -215,8 +220,7 @@ public AdminDistributedSystemImpl(DistributedSystemConfigImpl config) { } // LOG: create LogWriterAppender unless one already exists - this.logWriterAppender = LogWriterAppenders.getOrCreateAppender( - LogWriterAppenders.Identifier.MAIN, false, this.config.createLogConfig(), false); + loggingSession.startSession(); // LOG: look in DistributedSystemConfigImpl for existing LogWriter to use InternalLogWriter existingLogWriter = this.config.getInternalLogWriter(); @@ -224,8 +228,7 @@ public AdminDistributedSystemImpl(DistributedSystemConfigImpl config) { this.logWriter = existingLogWriter; } else { // LOG: create LogWriterLogger - this.logWriter = LogWriterFactory.createLogWriterLogger(false, false, - this.config.createLogConfig(), false); + this.logWriter = LogWriterFactory.createLogWriterLogger(this.config.createLogConfig(), false); if (!Boolean.getBoolean(InternalLocator.INHIBIT_DM_BANNER)) { // LOG: changed statement from config to info this.logWriter.info(Banner.getString(null)); @@ -907,9 +910,7 @@ public boolean waitToBeConnected(long timeout) throws InterruptedException { */ public void disconnect() { synchronized (CONNECTION_SYNC) { - if (this.logWriterAppender != null) { - LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN); - } + loggingSession.stopSession(); try { if (thisAdminDS == this) { thisAdminDS = null; @@ -928,9 +929,7 @@ public void disconnect() { ((DistributedSystemConfigImpl) this.config).setDistributedSystem(null); } } finally { - if (logWriterAppender != null) { - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN); - } + loggingSession.shutdown(); } } } diff --git a/geode-core/src/main/java/org/apache/geode/admin/jmx/internal/AgentImpl.java b/geode-core/src/main/java/org/apache/geode/admin/jmx/internal/AgentImpl.java index 0356f88e5ff0..b7c3f59dba03 100644 --- a/geode-core/src/main/java/org/apache/geode/admin/jmx/internal/AgentImpl.java +++ b/geode-core/src/main/java/org/apache/geode/admin/jmx/internal/AgentImpl.java @@ -20,8 +20,10 @@ import java.rmi.server.RMIServerSocketFactory; import java.text.MessageFormat; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Properties; +import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; @@ -55,19 +57,19 @@ import org.apache.geode.admin.jmx.AgentConfig; import org.apache.geode.admin.jmx.AgentFactory; import org.apache.geode.distributed.internal.ClusterDistributionManager; -import org.apache.geode.internal.Banner; import org.apache.geode.internal.ExitCode; import org.apache.geode.internal.GemFireVersion; import org.apache.geode.internal.admin.remote.TailLogResponse; import org.apache.geode.internal.logging.InternalLogWriter; import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigListener; +import org.apache.geode.internal.logging.LogConfigSupplier; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LogWriterFactory; +import org.apache.geode.internal.logging.LoggingSession; import org.apache.geode.internal.logging.LoggingThread; -import org.apache.geode.internal.logging.log4j.AlertAppender; import org.apache.geode.internal.logging.log4j.LogMarker; -import org.apache.geode.internal.logging.log4j.LogWriterAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; +import org.apache.geode.internal.statistics.StatisticsConfig; /** * The GemFire JMX Agent provides the ability to administrate one GemFire distributed system via @@ -76,7 +78,7 @@ * @since GemFire 3.5 */ public class AgentImpl implements org.apache.geode.admin.jmx.Agent, - org.apache.geode.admin.jmx.internal.ManagedResource { + org.apache.geode.admin.jmx.internal.ManagedResource, LogConfigSupplier { private static final Logger logger = LogService.getLogger(); @@ -130,7 +132,6 @@ private static void checkDebug() { // ------------------------------------------------------------------------- /** This Agent's log writer */ - private LogWriterAppender logWriterAppender; private InternalLogWriter logWriter; /** This Agent's JMX http adaptor from MX4J */ @@ -170,6 +171,9 @@ private static void checkDebug() { private MBeanServer mBeanServer; + private final LoggingSession loggingSession; + private final Set logConfigListeners = new HashSet<>(); + // ------------------------------------------------------------------------- // Constructor(s) // ------------------------------------------------------------------------- @@ -182,6 +186,8 @@ private static void checkDebug() { * @throws IllegalArgumentException if agentConfig is null */ public AgentImpl(AgentConfigImpl agentConfig) throws AdminException, IllegalArgumentException { + loggingSession = LoggingSession.create(); + shutdownHook = new LoggingThread("Shutdown", false, () -> disconnectFromSystem()); addShutdownHook(); if (agentConfig == null) { @@ -239,10 +245,12 @@ private void initializeHelperMbean() { // Public operations // ------------------------------------------------------------------------- + @Override public AgentConfig getConfig() { return this.agentConfig; } + @Override public AdminDistributedSystem getDistributedSystem() { return this.system; } @@ -253,6 +261,7 @@ public AdminDistributedSystem getDistributedSystem() { * @throws GemFireIOException if unable to persist the configuration to props * @see #getPropertyFile */ + @Override public void saveProperties() { throw new GemFireIOException("saveProperties is no longer supported for security reasons"); } @@ -260,6 +269,7 @@ public void saveProperties() { /** * Starts the jmx agent */ + @Override public void start() { checkDebug(); @@ -272,9 +282,8 @@ public void start() { try { startHttpAdaptor(); } catch (StartupException e) { - AlertAppender.getInstance().shuttingDown(); - LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN); - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN); + loggingSession.stopSession(); + loggingSession.shutdown(); throw e; } @@ -282,9 +291,8 @@ public void start() { startRMIConnectorServer(); } catch (StartupException e) { stopHttpAdaptor(); - AlertAppender.getInstance().shuttingDown(); - LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN); - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN); + loggingSession.stopSession(); + loggingSession.shutdown(); throw e; } @@ -293,9 +301,8 @@ public void start() { } catch (StartupException e) { stopRMIConnectorServer(); stopHttpAdaptor(); - AlertAppender.getInstance().shuttingDown(); - LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN); - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN); + loggingSession.stopSession(); + loggingSession.shutdown(); throw e; } @@ -321,7 +328,6 @@ public void start() { } // getAutoConnect logger.info("GemFire JMX Agent is running..."); - LogWriterAppenders.startupComplete(LogWriterAppenders.Identifier.MAIN); if (memberInfoWithStatsMBean == null) { initializeHelperMbean(); @@ -331,11 +337,12 @@ public void start() { /** * Deregisters everything this Agent registered and releases the MBeanServer. */ + @Override public void stop() { try { logger.info("Stopping JMX agent"); - AlertAppender.getInstance().shuttingDown(); - LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN); + + loggingSession.stopSession(); // stop the GemFire Distributed System stopDistributedSystem(); @@ -356,7 +363,7 @@ public void stop() { logger.info("Agent has stopped"); } finally { - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN); + loggingSession.shutdown(); } } @@ -379,6 +386,7 @@ private void stopDistributedSystem() { } } + @Override public ObjectName manageDistributedSystem() throws MalformedObjectNameException { synchronized (CONN_SYNC) { if (isConnected()) { @@ -394,6 +402,7 @@ public ObjectName manageDistributedSystem() throws MalformedObjectNameException * * @return the object name of the system that the Agent is now connected to */ + @Override @edu.umd.cs.findbugs.annotations.SuppressWarnings( value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "This is only a style warning.") @@ -441,6 +450,7 @@ public ObjectName connectToSystem() throws AdminException, MalformedObjectNameEx /** * Disconnects from the current DistributedSystem (if connected to one). */ + @Override @edu.umd.cs.findbugs.annotations.SuppressWarnings( value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "This is only a style warning.") @@ -480,7 +490,9 @@ public void disconnectFromSystem() { * @return snapshot of the current log */ public String getLog() { - String childTail = tailFile(this.logWriterAppender.getChildLogFile()); + File childLogFile = loggingSession.getLogFile().isPresent() + ? loggingSession.getLogFile().get().getChildLogFile() : null; + String childTail = tailFile(childLogFile); String mainTail = tailFile(new File(this.agentConfig.getLogFile())); if (childTail == null && mainTail == null) { return "No log file configured, log messages will be directed to stdout."; @@ -510,6 +522,7 @@ public String getVersion() { // ------------------------------------------------------------------------- /** Returns true if this Agent is currently connected to a system. */ + @Override public boolean isConnected() { boolean result = false; synchronized (CONN_SYNC) { @@ -695,7 +708,7 @@ public int getLogFileSizeLimit() { */ public void setLogFileSizeLimit(int logFileSizeLimit) { this.agentConfig.setLogFileSizeLimit(logFileSizeLimit); - LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN); + logConfigChanged(); } /** @@ -714,7 +727,7 @@ public int getLogDiskSpaceLimit() { */ public void setLogDiskSpaceLimit(int logDiskSpaceLimit) { this.agentConfig.setLogDiskSpaceLimit(logDiskSpaceLimit); - LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN); + logConfigChanged(); } /** @@ -733,7 +746,7 @@ public String getLogFile() { */ public void setLogFile(String logFile) { this.agentConfig.setLogFile(logFile); - LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN); + logConfigChanged(); } /** @@ -752,7 +765,7 @@ public String getLogLevel() { */ public void setLogLevel(String logLevel) { this.agentConfig.setLogLevel(logLevel); - LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN); + logConfigChanged(); } /** Returns true if the Agent is set to auto connect to a system. */ @@ -813,6 +826,7 @@ private String tailFile(File f) { * * @return the GemFire mbeanServer */ + @Override public MBeanServer getMBeanServer() { return mBeanServer; } @@ -822,6 +836,7 @@ public MBeanServer getMBeanServer() { * * @return the logWriter */ + @Override public LogWriter getLogWriter() { return this.logWriter; } @@ -851,11 +866,12 @@ private void removeShutdownHook() { @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", justification = "Return value for file delete is not important here.") private void initLogWriter() throws org.apache.geode.admin.AdminException { + loggingSession.createSession(this); + final LogConfig logConfig = this.agentConfig.createLogConfig(); // LOG: create logWriterAppender here - this.logWriterAppender = LogWriterAppenders - .getOrCreateAppender(LogWriterAppenders.Identifier.MAIN, false, logConfig, false); + loggingSession.startSession(); // LOG: look in AgentConfigImpl for existing LogWriter to use InternalLogWriter existingLogWriter = this.agentConfig.getInternalLogWriter(); @@ -863,22 +879,17 @@ private void initLogWriter() throws org.apache.geode.admin.AdminException { this.logWriter = existingLogWriter; } else { // LOG: create LogWriterLogger - this.logWriter = LogWriterFactory.createLogWriterLogger(false, false, logConfig, false); - // LOG: changed statement from config to info - this.logWriter.info(Banner.getString(null)); + this.logWriter = LogWriterFactory.createLogWriterLogger(logConfig, false); // Set this log writer in AgentConfigImpl this.agentConfig.setInternalLogWriter(this.logWriter); } // LOG: create logWriter here - this.logWriter = LogWriterFactory.createLogWriterLogger(false, false, logConfig, false); + this.logWriter = LogWriterFactory.createLogWriterLogger(logConfig, false); // Set this log writer in AgentConfig this.agentConfig.setInternalLogWriter(this.logWriter); - // Print Banner information - logger.info(Banner.getString(this.agentConfig.getOriginalArgs())); - // LOG:CONFIG: changed next three statements from config to info logger.info(LogMarker.CONFIG_MARKER, String.format("Agent config property file name: %s", @@ -1412,28 +1423,60 @@ public void removeSSLProperty(String key) { // ManagedResource implementation // ------------------------------------------------------------------------- + @Override public String getMBeanName() { return this.mbeanName; } + @Override public ModelMBean getModelMBean() { return this.modelMBean; } + @Override public void setModelMBean(ModelMBean modelMBean) { this.modelMBean = modelMBean; } + @Override public ObjectName getObjectName() { return this.objectName; } + @Override public ManagedResourceType getManagedResourceType() { return ManagedResourceType.AGENT; } + @Override public void cleanupResource() {} + @Override + public LogConfig getLogConfig() { + return agentConfig.createLogConfig(); + } + + @Override + public StatisticsConfig getStatisticsConfig() { + return agentConfig.createStatisticsConfig(); + } + + @Override + public void addLogConfigListener(LogConfigListener logConfigListener) { + logConfigListeners.add(logConfigListener); + } + + @Override + public void removeLogConfigListener(LogConfigListener logConfigListener) { + logConfigListeners.remove(logConfigListener); + } + + void logConfigChanged() { + for (LogConfigListener listener : logConfigListeners) { + listener.configChanged(); + } + } + static class StartupException extends GemFireException { private static final long serialVersionUID = 6614145962199330348L; @@ -1520,6 +1563,7 @@ class ConnectionNotificationAdapter implements NotificationListener { * resent, without modification, to the listener. The MBean object should not use or modify * the object. (NOTE: copied from javax.management.NotificationListener) */ + @Override @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "BC_UNCONFIRMED_CAST", justification = "Only JMXConnectionNotification instances are used.") public void handleNotification(Notification notification, Object handback) { @@ -1559,6 +1603,7 @@ class ConnectionNotificationFilterImpl implements NotificationFilter { * @param notification The notification to be sent. * @return true if the notification has to be sent to the listener, false otherwise. */ + @Override public boolean isNotificationEnabled(Notification notification) { boolean isThisNotificationEnabled = false; if (notification.getType().equals(JMXConnectionNotification.OPENED) diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalDistributedSystem.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalDistributedSystem.java index 7d8e41e6e087..4fed864bdc2d 100644 --- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalDistributedSystem.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalDistributedSystem.java @@ -31,6 +31,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Properties; import java.util.ServiceLoader; import java.util.Set; @@ -57,7 +58,6 @@ import org.apache.geode.StatisticsTypeFactory; import org.apache.geode.SystemConnectException; import org.apache.geode.SystemFailure; -import org.apache.geode.admin.AlertLevel; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.CacheFactory; import org.apache.geode.cache.CacheXmlException; @@ -80,6 +80,10 @@ import org.apache.geode.internal.InternalInstantiator; import org.apache.geode.internal.SystemTimer; import org.apache.geode.internal.admin.remote.DistributionLocatorId; +import org.apache.geode.internal.alerting.AlertLevel; +import org.apache.geode.internal.alerting.AlertMessaging; +import org.apache.geode.internal.alerting.AlertingService; +import org.apache.geode.internal.alerting.AlertingSession; import org.apache.geode.internal.cache.CacheConfig; import org.apache.geode.internal.cache.CacheServerImpl; import org.apache.geode.internal.cache.EventID; @@ -90,12 +94,15 @@ import org.apache.geode.internal.cache.tier.sockets.EncryptorImpl; import org.apache.geode.internal.cache.xmlcache.CacheServerCreation; import org.apache.geode.internal.logging.InternalLogWriter; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigListener; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.LogFile; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LogWriterFactory; +import org.apache.geode.internal.logging.LoggingSession; import org.apache.geode.internal.logging.LoggingThread; -import org.apache.geode.internal.logging.log4j.AlertAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; +import org.apache.geode.internal.logging.NullLoggingSession; import org.apache.geode.internal.net.SocketCreatorFactory; import org.apache.geode.internal.offheap.MemoryAllocator; import org.apache.geode.internal.offheap.OffHeapStorage; @@ -104,6 +111,7 @@ import org.apache.geode.internal.statistics.DummyStatisticsImpl; import org.apache.geode.internal.statistics.GemFireStatSampler; import org.apache.geode.internal.statistics.LocalStatisticsImpl; +import org.apache.geode.internal.statistics.StatisticsConfig; import org.apache.geode.internal.statistics.StatisticsImpl; import org.apache.geode.internal.statistics.StatisticsManager; import org.apache.geode.internal.statistics.StatisticsTypeFactoryImpl; @@ -122,7 +130,7 @@ * @since GemFire 3.0 */ public class InternalDistributedSystem extends DistributedSystem - implements OsStatisticsFactory, StatisticsManager { + implements OsStatisticsFactory, StatisticsManager, LogConfigSupplier { /** * True if the user is allowed lock when memory resources appear to be overcommitted. @@ -203,13 +211,6 @@ public GrantorRequestProcessor.GrantorRequestContext getGrantorRequestContext() */ private DSClock clock; - // /** The log writer was provided by an external entity */ - // private boolean externalLogWriterProvided = false; - // - private LogWriterAppender logWriterAppender = null; - - private LogWriterAppender securityLogWriterAppender = null; - /** * Time this system was created */ @@ -325,6 +326,12 @@ public GrantorRequestProcessor.GrantorRequestContext getGrantorRequestContext() */ private boolean deltaEnabledOnServer = true; + private final AlertingSession alertingSession; + private final AlertingService alertingService; + + private final LoggingSession loggingSession; + private final Set logConfigListeners = new HashSet<>(); + public boolean isDeltaEnabledOnServer() { return deltaEnabledOnServer; } @@ -510,6 +517,9 @@ private static void resetReconnectAttemptCounter() { * @see DistributedSystem#connect */ private InternalDistributedSystem(Properties nonDefault) { + alertingSession = AlertingSession.create(); + alertingService = new AlertingService(); + loggingSession = LoggingSession.create(); // register DSFID types first; invoked explicitly so that all message type // initializations do not happen in first deserialization on a possibly @@ -648,38 +658,15 @@ private void initialize(SecurityManager securityManager, PostProcessor postProce try { SocketCreatorFactory.setDistributionConfig(config); - AlertAppender.getInstance().onConnect(this); - - // LOG: create LogWriterAppender(s) if log-file or security-log-file is specified - final boolean hasLogFile = - this.config.getLogFile() != null && !this.config.getLogFile().equals(new File("")); - final boolean hasSecurityLogFile = this.config.getSecurityLogFile() != null - && !this.config.getSecurityLogFile().equals(new File("")); - LogService.configureLoggers(hasLogFile, hasSecurityLogFile); - if (hasLogFile || hasSecurityLogFile) { - - // main log file - if (hasLogFile) { - // if log-file then create logWriterAppender - this.logWriterAppender = LogWriterAppenders.getOrCreateAppender( - LogWriterAppenders.Identifier.MAIN, this.isLoner, this.config, true); - } - - // security log file - if (hasSecurityLogFile) { - // if security-log-file then create securityLogWriterAppender - this.securityLogWriterAppender = LogWriterAppenders.getOrCreateAppender( - LogWriterAppenders.Identifier.SECURITY, this.isLoner, this.config, false); - } else { - // let security route to regular log-file or stdout - } - } + boolean logBanner = !attemptingToReconnect; + boolean logConfiguration = !attemptingToReconnect; + loggingSession.createSession(this, logBanner, logConfiguration); // LOG: create LogWriterLogger(s) for backwards compatibility of getLogWriter and // getSecurityLogWriter if (this.logWriter == null) { this.logWriter = - LogWriterFactory.createLogWriterLogger(this.isLoner, false, this.config, true); + LogWriterFactory.createLogWriterLogger(this.config, false); this.logWriter.fine("LogWriter is created."); } @@ -688,13 +675,15 @@ private void initialize(SecurityManager securityManager, PostProcessor postProce if (this.securityLogWriter == null) { // LOG: whole new LogWriterLogger instance for security this.securityLogWriter = - LogWriterFactory.createLogWriterLogger(this.isLoner, true, this.config, false); + LogWriterFactory.createLogWriterLogger(this.config, true); this.securityLogWriter.fine("SecurityLogWriter is created."); } Services.setLogWriter(this.logWriter); Services.setSecurityLogWriter(this.securityLogWriter); + loggingSession.startSession(); + this.clock = new DSClock(this.isLoner); if (this.attemptingToReconnect && logger.isDebugEnabled()) { @@ -813,16 +802,17 @@ private void initialize(SecurityManager securityManager, PostProcessor postProce } if (!statsDisabled) { - this.sampler = new GemFireStatSampler(this); + Optional logFile = loggingSession.getLogFile(); + if (logFile.isPresent()) { + sampler = new GemFireStatSampler(this, logFile.get()); + } else { + sampler = new GemFireStatSampler(this); + } this.sampler.start(); } - if (this.logWriterAppender != null) { - LogWriterAppenders.startupComplete(LogWriterAppenders.Identifier.MAIN); - } - if (this.securityLogWriterAppender != null) { - LogWriterAppenders.startupComplete(LogWriterAppenders.Identifier.SECURITY); - } + alertingSession.createSession(new AlertMessaging(this)); + alertingSession.startSession(); // Log any instantiators that were registered before the log writer // was created @@ -860,9 +850,10 @@ private void startInitLocator() throws InterruptedException { } DistributionLocatorId locId = new DistributionLocatorId(locatorString); try { - this.startedLocator = InternalLocator.createLocator(locId.getPort(), null, this.logWriter, - this.securityLogWriter, locId.getHost().getAddress(), locId.getHostnameForClients(), - this.originalConfig.toProperties(), false); + this.startedLocator = + InternalLocator.createLocator(locId.getPort(), NullLoggingSession.create(), null, + logWriter, securityLogWriter, locId.getHost().getAddress(), + locId.getHostnameForClients(), originalConfig.toProperties(), false); // if locator is started this way, cluster config is not enabled, set the flag correctly this.startedLocator.getConfig().setEnableClusterConfiguration(false); @@ -1406,17 +1397,9 @@ protected void disconnect(boolean preparingForReconnect, String reason, boolean } if (!this.attemptingToReconnect) { - if (this.logWriterAppender != null) { - LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN); - } - if (this.securityLogWriterAppender != null) { - // LOG:SECURITY: old code did NOT invoke this - LogWriterAppenders.stop(LogWriterAppenders.Identifier.SECURITY); - } + alertingSession.stopSession(); } - AlertAppender.getInstance().shuttingDown(); - } finally { // be ABSOLUTELY CERTAIN that dm closed try { // Do the bulk of the close... @@ -1457,12 +1440,7 @@ protected void disconnect(boolean preparingForReconnect, String reason, boolean } if (!this.attemptingToReconnect) { - if (this.logWriterAppender != null) { - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN); - } - if (this.securityLogWriterAppender != null) { - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.SECURITY); - } + loggingSession.stopSession(); } EventID.unsetDS(); @@ -1475,6 +1453,10 @@ protected void disconnect(boolean preparingForReconnect, String reason, boolean } finally { try { removeSystem(this); + if (!this.attemptingToReconnect) { + loggingSession.shutdown(); + } + alertingSession.shutdown(); // Close the config object this.config.close(); } finally { @@ -1610,6 +1592,40 @@ public DistributionConfig getConfig() { return this.config; } + public AlertingService getAlertingService() { + return alertingService; + } + + @Override + public LogConfig getLogConfig() { + return config; + } + + @Override + public StatisticsConfig getStatisticsConfig() { + return config; + } + + @Override + public void addLogConfigListener(LogConfigListener logConfigListener) { + logConfigListeners.add(logConfigListener); + } + + @Override + public void removeLogConfigListener(LogConfigListener logConfigListener) { + logConfigListeners.remove(logConfigListener); + } + + public Optional getLogFile() { + return loggingSession.getLogFile(); + } + + void logConfigChanged() { + for (LogConfigListener listener : logConfigListeners) { + listener.configChanged(); + } + } + /** * Returns the id of this connection to the distributed system. This is actually the port of the * distribution manager's distribution channel. @@ -2984,12 +3000,11 @@ public String forceStop() { } public boolean hasAlertListenerFor(DistributedMember member) { - return hasAlertListenerFor(member, AlertLevel.WARNING.getSeverity()); + return hasAlertListenerFor(member, AlertLevel.WARNING.intLevel()); } - public boolean hasAlertListenerFor(DistributedMember member, int severity) { - return AlertAppender.getInstance().hasAlertListener(member, severity); + return alertingService.hasAlertListener(member, AlertLevel.find(severity)); } /** diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java index dc0ed08fe906..e2ea6b8c62e2 100644 --- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Properties; +import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -66,12 +67,17 @@ import org.apache.geode.internal.cache.tier.sockets.TcpServerFactory; import org.apache.geode.internal.cache.wan.WANServiceProvider; import org.apache.geode.internal.logging.InternalLogWriter; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogConfigListener; +import org.apache.geode.internal.logging.LogConfigSupplier; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LogWriterFactory; +import org.apache.geode.internal.logging.LoggingSession; import org.apache.geode.internal.logging.LoggingThread; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; +import org.apache.geode.internal.logging.NullLoggingSession; import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.net.SocketCreatorFactory; +import org.apache.geode.internal.statistics.StatisticsConfig; import org.apache.geode.management.internal.JmxManagerLocator; import org.apache.geode.management.internal.JmxManagerLocatorRequest; import org.apache.geode.management.internal.configuration.domain.SharedConfigurationStatus; @@ -95,7 +101,7 @@ * * @since GemFire 4.0 */ -public class InternalLocator extends Locator implements ConnectListener { +public class InternalLocator extends Locator implements ConnectListener, LogConfigSupplier { private static final Logger logger = LogService.getLogger(); /** @@ -179,6 +185,10 @@ public class InternalLocator extends Locator implements ConnectListener { private volatile Thread restartThread; + private final LoggingSession loggingSession; + + private final Set logConfigListeners = new HashSet<>(); + public boolean isSharedConfigurationEnabled() { return this.config.getEnableClusterConfiguration(); } @@ -221,10 +231,8 @@ private static void removeLocator(InternalLocator locator) { return; } synchronized (locatorLock) { - LogWriterAppenders.stop(LogWriterAppenders.Identifier.MAIN); - LogWriterAppenders.stop(LogWriterAppenders.Identifier.SECURITY); - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.MAIN); - LogWriterAppenders.destroy(LogWriterAppenders.Identifier.SECURITY); + locator.loggingSession.stopSession(); + locator.loggingSession.shutdown(); if (locator.equals(InternalLocator.locator)) { InternalLocator.locator = null; } @@ -241,6 +249,7 @@ public LocatorMembershipListener getlocatorMembershipListener() { * startPeerLocation on the locator object. * * @param port the tcp/ip port to listen on + * @param loggingSession the LoggingSession to use, may be a NullLoggingSession which does nothing * @param logFile the file that log messages should be written to * @param logger a log writer that should be used (logFile parameter is ignored) * @param securityLogger the logger to be used for security related log messages @@ -248,7 +257,8 @@ public LocatorMembershipListener getlocatorMembershipListener() { * (e.g., mcast addr/port, other locators) * @param startDistributedSystem if true then this locator will also start its own ds */ - public static InternalLocator createLocator(int port, File logFile, InternalLogWriter logger, + public static InternalLocator createLocator(int port, LoggingSession loggingSession, File logFile, + InternalLogWriter logger, InternalLogWriter securityLogger, InetAddress bindAddress, String hostnameForClients, Properties distributedSystemProperties, boolean startDistributedSystem) { synchronized (locatorLock) { @@ -257,7 +267,7 @@ public static InternalLocator createLocator(int port, File logFile, InternalLogW "A locator can not be created because one already exists in this JVM."); } InternalLocator locator = - new InternalLocator(port, logFile, logger, securityLogger, bindAddress, + new InternalLocator(port, loggingSession, logFile, logger, securityLogger, bindAddress, hostnameForClients, distributedSystemProperties, null, startDistributedSystem); InternalLocator.locator = locator; return locator; @@ -298,9 +308,16 @@ public static InternalLocator startLocator(int port, File logFile, InternalLogWr boolean startedLocator = false; try { - newLocator = createLocator(port, logFile, logger, securityLogger, bindAddress, + // if startDistributedSystem is true then Locator uses a NullLoggingSession (does nothing) + LoggingSession loggingSession = + startDistributedSystem ? NullLoggingSession.create() : LoggingSession.create(); + + newLocator = createLocator(port, loggingSession, logFile, logger, securityLogger, bindAddress, hostnameForClients, dsProperties, startDistributedSystem); + loggingSession.createSession(newLocator); + loggingSession.startSession(); + try { newLocator.startPeerLocation(); @@ -373,7 +390,7 @@ public static boolean isDedicatedLocator() { * Creates a new {@code Locator} with the given port, log file, logger, and bind address. * * @param port the tcp/ip port to listen on - * @param logF the file that log messages should be written to + * @param logFile the file that log messages should be written to * @param logWriter a log writer that should be used (logFile parameter is ignored) * @param securityLogWriter the log writer to be used for security related log messages * @param hostnameForClients the name to give to clients for connecting to this locator @@ -382,17 +399,13 @@ public static boolean isDedicatedLocator() { * @param cfg the config if being called from a distributed system; otherwise null. * @param startDistributedSystem if true locator will start its own distributed system */ - private InternalLocator(int port, File logF, InternalLogWriter logWriter, - // LOG: 3 non-null sources: GemFireDistributionLocator, InternalDistributedSystem, - // LocatorLauncher - InternalLogWriter securityLogWriter, - // LOG: 1 non-null source: GemFireDistributionLocator(same instance as logWriter), - // InternalDistributedSystem + private InternalLocator(int port, LoggingSession loggingSession, File logFile, + InternalLogWriter logWriter, InternalLogWriter securityLogWriter, InetAddress bindAddress, String hostnameForClients, Properties distributedSystemProperties, DistributionConfigImpl cfg, boolean startDistributedSystem) { // TODO: the following three assignments are already done in superclass - this.logFile = logF; + this.logFile = logFile; this.bindAddress = bindAddress; this.hostnameForClients = hostnameForClients; @@ -427,39 +440,22 @@ private InternalLocator(int port, File logF, InternalLogWriter logWriter, this.config.unsafeSetLogFile(this.logFile); } - // LOG: create LogWriterAppenders (these are closed at shutdown) - final boolean hasLogFile = - this.config.getLogFile() != null && !this.config.getLogFile().equals(new File("")); - final boolean hasSecurityLogFile = this.config.getSecurityLogFile() != null - && !this.config.getSecurityLogFile().equals(new File("")); - LogService.configureLoggers(hasLogFile, hasSecurityLogFile); - if (hasLogFile || hasSecurityLogFile) { - - if (hasLogFile) { - // if log-file then create logWriterAppender - LogWriterAppenders.getOrCreateAppender(LogWriterAppenders.Identifier.MAIN, true, false, - this.config, !startDistributedSystem); - } - - if (hasSecurityLogFile) { - // if security-log-file then create securityLogWriterAppender - LogWriterAppenders.getOrCreateAppender(LogWriterAppenders.Identifier.SECURITY, true, false, - this.config, false); - } - // do not create a LogWriterAppender for security -- let it go through to logWriterAppender + if (loggingSession == null) { + throw new Error("LoggingSession must not be null"); + } else { + this.loggingSession = loggingSession; } // LOG: create LogWriters for GemFireTracer (or use whatever was passed in) if (logWriter == null) { - logWriter = LogWriterFactory.createLogWriterLogger(false, false, this.config, false); + logWriter = LogWriterFactory.createLogWriterLogger(this.config, false); if (logger.isDebugEnabled()) { logger.debug("LogWriter for locator is created."); } } if (securityLogWriter == null) { - securityLogWriter = LogWriterFactory.createLogWriterLogger(false, true, this.config, false); - logWriter.setLogWriterLevel(this.config.getSecurityLogLevel()); + securityLogWriter = LogWriterFactory.createLogWriterLogger(this.config, true); securityLogWriter.fine("SecurityLogWriter for locator is created."); } @@ -1090,6 +1086,37 @@ public Integer getPort() { return null; } + @Override + public LogConfig getLogConfig() { + return config; + } + + @Override + public StatisticsConfig getStatisticsConfig() { + return config; + } + + @Override + public void addLogConfigListener(LogConfigListener logConfigListener) { + logConfigListeners.add(logConfigListener); + } + + @Override + public void removeLogConfigListener(LogConfigListener logConfigListener) { + logConfigListeners.remove(logConfigListener); + } + + /** + * Apparently nothing provides RuntimeDistributionConfigImpl behavior in a stand-alone locator + * (without DS), so there are currently no callers of {@code logConfigChanged()}. Keep it? + */ + @SuppressWarnings("unused") + void logConfigChanged() { + for (LogConfigListener listener : logConfigListeners) { + listener.configChanged(); + } + } + class FetchSharedConfigStatus implements Callable { static final int SLEEPTIME = 1000; diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/RuntimeDistributionConfigImpl.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/RuntimeDistributionConfigImpl.java index 5a9e219ea8b3..ef981b0fe024 100644 --- a/geode-core/src/main/java/org/apache/geode/distributed/internal/RuntimeDistributionConfigImpl.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/RuntimeDistributionConfigImpl.java @@ -34,7 +34,6 @@ import org.apache.geode.GemFireIOException; import org.apache.geode.internal.ConfigSource; import org.apache.geode.internal.logging.LogService; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; /** * Provides an implementation of {@code DistributionConfig} that is used at runtime by an @@ -69,8 +68,7 @@ public RuntimeDistributionConfigImpl(InternalDistributedSystem system) { public void setLogLevel(int value) { logLevel = (Integer) checkAttribute(LOG_LEVEL, value); getAttSourceMap().put(LOG_LEVEL, ConfigSource.runtime()); - system.getInternalLogWriter().setLogWriterLevel(value); - LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN); + logConfigChanged(); } @Override @@ -123,14 +121,14 @@ public void setArchiveFileSizeLimit(int value) { public void setLogDiskSpaceLimit(int value) { logDiskSpaceLimit = (Integer) checkAttribute(LOG_DISK_SPACE_LIMIT, value); getAttSourceMap().put(LOG_DISK_SPACE_LIMIT, ConfigSource.runtime()); - LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN); + logConfigChanged(); } @Override public void setLogFileSizeLimit(int value) { logFileSizeLimit = (Integer) checkAttribute(LOG_FILE_SIZE_LIMIT, value); getAttSourceMap().put(LOG_FILE_SIZE_LIMIT, ConfigSource.runtime()); - LogWriterAppenders.configChanged(LogWriterAppenders.Identifier.MAIN); + logConfigChanged(); } @Override @@ -144,4 +142,8 @@ public List getModifiableAttributes() { public DistributionConfig takeSnapshot() { return new DistributionConfigSnapshot(this); } + + private void logConfigChanged() { + system.logConfigChanged(); + } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/Banner.java b/geode-core/src/main/java/org/apache/geode/internal/Banner.java index f184789e2432..9cece133be87 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/Banner.java +++ b/geode-core/src/main/java/org/apache/geode/internal/Banner.java @@ -14,6 +14,18 @@ */ package org.apache.geode.internal; +import static org.apache.geode.internal.Banner.BannerHeader.CLASS_PATH; +import static org.apache.geode.internal.Banner.BannerHeader.COMMAND_LINE_PARAMETERS; +import static org.apache.geode.internal.Banner.BannerHeader.COMMUNICATIONS_VERSION; +import static org.apache.geode.internal.Banner.BannerHeader.CURRENT_DIR; +import static org.apache.geode.internal.Banner.BannerHeader.HOME_DIR; +import static org.apache.geode.internal.Banner.BannerHeader.LIBRARY_PATH; +import static org.apache.geode.internal.Banner.BannerHeader.LICENSE_START; +import static org.apache.geode.internal.Banner.BannerHeader.LOG4J2_CONFIGURATION; +import static org.apache.geode.internal.Banner.BannerHeader.PROCESS_ID; +import static org.apache.geode.internal.Banner.BannerHeader.SYSTEM_PROPERTIES; +import static org.apache.geode.internal.Banner.BannerHeader.USER; + import java.io.PrintWriter; import java.io.StringWriter; import java.lang.management.ManagementFactory; @@ -29,7 +41,7 @@ import org.apache.geode.SystemFailure; import org.apache.geode.distributed.internal.DistributionConfig; -import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.ConfigurationInfo; import org.apache.geode.internal.util.ArgumentRedactor; /** @@ -37,6 +49,9 @@ */ public class Banner { + public static final String SEPARATOR = + "---------------------------------------------------------------------------"; + private Banner() { // everything is static so don't allow instance creation } @@ -72,8 +87,6 @@ static void print(PrintWriter out, String args[]) { sp.remove("os.name"); sp.remove("os.arch"); - final String SEPARATOR = - "---------------------------------------------------------------------------"; int processId = attemptToReadProcessId(); short currentOrdinal = Version.CURRENT_ORDINAL; @@ -94,28 +107,28 @@ static void print(PrintWriter out, String args[]) { printASFLicense(out); out.println(SEPARATOR); GemFireVersion.print(out); - out.println("Communications version: " + currentOrdinal); - out.println("Process ID: " + processId); - out.println("User: " + userName); - out.println("Current dir: " + userDir); - out.println("Home dir: " + userHome); + out.println(COMMUNICATIONS_VERSION.displayValue() + ": " + currentOrdinal); + out.println(PROCESS_ID.displayValue() + ": " + processId); + out.println(USER.displayValue() + ": " + userName); + out.println(CURRENT_DIR.displayValue() + ": " + userDir); + out.println(HOME_DIR.displayValue() + ": " + userHome); if (!commandLineArguments.isEmpty()) { - out.println("Command Line Parameters:"); + out.println(COMMAND_LINE_PARAMETERS.displayValue() + ":"); for (String arg : commandLineArguments) { out.println(" " + ArgumentRedactor.redact(arg)); } } - out.println("Class Path:"); + out.println(CLASS_PATH.displayValue() + ":"); prettyPrintPath((String) javaClassPath, out); - out.println("Library Path:"); + out.println(LIBRARY_PATH.displayValue() + ":"); prettyPrintPath((String) javaLibraryPath, out); if (Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "disableSystemPropertyLogging")) { out.println("System property logging disabled."); } else { - out.println("System Properties:"); + out.println(SYSTEM_PROPERTIES.displayValue() + ":"); for (Object o : sp.entrySet()) { Entry me = (Entry) o; String key = me.getKey().toString(); @@ -123,8 +136,8 @@ static void print(PrintWriter out, String args[]) { ArgumentRedactor.redactArgumentIfNecessary(key, String.valueOf(me.getValue())); out.println(" " + key + " = " + value); } - out.println("Log4J 2 Configuration:"); - out.println(" " + LogService.getConfigurationInfo()); + out.println(LOG4J2_CONFIGURATION.displayValue() + ":"); + out.println(" " + ConfigurationInfo.getConfigurationInfo()); } out.println(SEPARATOR); } @@ -154,7 +167,7 @@ private static int attemptToReadProcessId() { private static void printASFLicense(PrintWriter out) { out.println(" "); - out.println(" Licensed to the Apache Software Foundation (ASF) under one or more"); + out.println(" " + LICENSE_START.displayValue()); out.println(" contributor license agreements. See the NOTICE file distributed with this"); out.println(" work for additional information regarding copyright ownership."); out.println(" "); @@ -177,11 +190,60 @@ private static void printASFLicense(PrintWriter out) { * * @param args possibly null list of command line arguments */ - public static String getString(String args[]) { + public static String getString(String[] args) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); print(pw, args); pw.close(); return sw.toString(); } + + /** + * The headers of the log {@link Banner}. + */ + public enum BannerHeader { + + LICENSE_START("Licensed to the Apache Software Foundation (ASF) under one or more"), + BUILD_DATE(VersionDescription.BUILD_DATE), + BUILD_ID(VersionDescription.BUILD_ID), + BUILD_JAVA_VERSION(VersionDescription.BUILD_JAVA_VERSION), + BUILD_PLATFORM(VersionDescription.BUILD_PLATFORM), + PRODUCT_NAME(VersionDescription.PRODUCT_NAME), + PRODUCT_VERSION(VersionDescription.PRODUCT_VERSION), + SOURCE_DATE(VersionDescription.SOURCE_DATE), + SOURCE_REPOSITORY(VersionDescription.SOURCE_REPOSITORY), + SOURCE_REVISION(VersionDescription.SOURCE_REVISION), + NATIVE_VERSION(VersionDescription.NATIVE_VERSION), + RUNNING_ON(VersionDescription.RUNNING_ON), + COMMUNICATIONS_VERSION("Communications version"), + PROCESS_ID("Process ID"), + USER("User"), + CURRENT_DIR("Current dir"), + HOME_DIR("Home dir"), + COMMAND_LINE_PARAMETERS("Command Line Parameters"), + CLASS_PATH("Class Path"), + LIBRARY_PATH("Library Path"), + SYSTEM_PROPERTIES("System Properties"), + LOG4J2_CONFIGURATION("Log4J 2 Configuration"); + + private final String displayValue; + + BannerHeader(String displayValue) { + this.displayValue = displayValue; + } + + public String displayValue() { + return displayValue; + } + + public static String[] displayValues() { + String[] headerValues = new String[BannerHeader.values().length]; + int i = 0; + for (BannerHeader bannerHeader : BannerHeader.values()) { + headerValues[i] = bannerHeader.displayValue(); + i++; + } + return headerValues; + } + } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/VersionDescription.java b/geode-core/src/main/java/org/apache/geode/internal/VersionDescription.java index fa8f3fffe241..427fffcdad77 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/VersionDescription.java +++ b/geode-core/src/main/java/org/apache/geode/internal/VersionDescription.java @@ -20,12 +20,12 @@ import java.io.InputStream; import java.io.PrintWriter; +import java.net.UnknownHostException; import java.util.Map.Entry; import java.util.Optional; import java.util.Properties; import java.util.TreeMap; -import org.apache.geode.SystemFailure; import org.apache.geode.internal.net.SocketCreator; public class VersionDescription { @@ -76,6 +76,10 @@ public class VersionDescription { */ public static final String BUILD_JAVA_VERSION = "Build-Java-Version"; + static final String NATIVE_VERSION = "Native version"; + + static final String RUNNING_ON = "Running on"; + /** * the version properties */ @@ -128,28 +132,21 @@ void print(PrintWriter pw) { } // not stored in the description map - pw.println("Native version: " + getNativeCodeVersion()); - printHostInfo(pw); + pw.println(NATIVE_VERSION + ": " + getNativeCodeVersion()); + pw.println(getRunningOnInfo()); + } + + private static String getRunningOnInfo() { + String line = getLocalHost() + ", " + Runtime.getRuntime().availableProcessors() + " cpu(s), " + + getOsArchitecture() + ' ' + getOsName() + ' ' + getOsVersion() + ' '; + return String.format(RUNNING_ON + ": %s", line); } - private void printHostInfo(PrintWriter pw) throws Error { + private static String getLocalHost() { try { - String sb = SocketCreator.getLocalHost().toString() + ", " - + Runtime.getRuntime().availableProcessors() + " cpu(s), " + getOsArchitecture() + ' ' - + getOsName() + ' ' + getOsVersion() + ' '; - pw.println(String.format("Running on: %s", sb)); - } catch (VirtualMachineError err) { - SystemFailure.initiateFailure(err); - // If this ever returns, rethrow the error. We're poisoned - // now, so don't let this thread continue. - throw err; - } catch (Throwable t) { - // Whenever you catch Error or Throwable, you must also - // catch VirtualMachineError (see above). However, there is - // _still_ a possibility that you are dealing with a cascading - // error condition, so you also need to check to see if the JVM - // is still usable: - SystemFailure.checkFailure(); + return SocketCreator.getLocalHost().toString(); + } catch (UnknownHostException e) { + return e.getMessage(); } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/remote/TailLogResponse.java b/geode-core/src/main/java/org/apache/geode/internal/admin/remote/TailLogResponse.java index 371583834c20..c22c38316438 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/admin/remote/TailLogResponse.java +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/remote/TailLogResponse.java @@ -12,8 +12,6 @@ * or implied. See the License for the specific language governing permissions and limitations under * the License. */ - - package org.apache.geode.internal.admin.remote; import java.io.DataInput; @@ -29,10 +27,8 @@ import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.distributed.internal.membership.InternalDistributedMember; +import org.apache.geode.internal.logging.LogFile; import org.apache.geode.internal.logging.LogService; -import org.apache.geode.internal.logging.log4j.LogWriterAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; - public class TailLogResponse extends AdminResponse { private static final Logger logger = LogService.getLogger(); @@ -46,17 +42,15 @@ public static TailLogResponse create(DistributionManager dm, m.setRecipient(recipient); try { InternalDistributedSystem sys = dm.getSystem(); - LogWriterAppender lwa = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); - if (lwa != null) { - m.childTail = tailSystemLog(lwa.getChildLogFile()); + if (sys.getLogFile().isPresent()) { + LogFile logFile = sys.getLogFile().get(); + m.childTail = tailSystemLog(logFile.getChildLogFile()); m.tail = tailSystemLog(sys.getConfig()); if (m.tail == null) { m.tail = "No log file was specified in the configuration, messages will be directed to stdout."; } } else { - // Assert.assertTrue(false, "TailLogRequest/Response processed in application vm with shared - // logging."); m.childTail = tailSystemLog((File) null); m.tail = tailSystemLog(sys.getConfig()); if (m.tail == null) { @@ -71,6 +65,7 @@ public static TailLogResponse create(DistributionManager dm, return m; } + @Override public int getDSFID() { return TAIL_LOG_RESPONSE; } @@ -129,28 +124,6 @@ public static String tailSystemLog(File logFile) throws IOException { return messageString.trim(); } - // private static String readSystemLog(File logFile) throws IOException { - // if (logFile == null || logFile.equals(new File(""))) { - // return null; - // } - // long fileLength = logFile.length(); - // byte[] buffer = new byte[(int)fileLength]; - // BufferedInputStream in = new BufferedInputStream(new FileInputStream(logFile)); - // in.read(buffer, 0, buffer.length); - // return new String(buffer).trim(); - // } - - // private static String readSystemLog(DistributionConfig sc) throws IOException { - // File logFile = sc.getLogFile(); - // if (logFile == null || logFile.equals(new File(""))) { - // return null; - // } - // if (!logFile.isAbsolute()) { - // logFile = new File(logFile.getAbsolutePath()); - // } - // return readSystemLog(logFile); - // } - private static String tailSystemLog(DistributionConfig sc) throws IOException { File logFile = sc.getLogFile(); if (logFile == null || logFile.equals(new File(""))) { @@ -161,5 +134,4 @@ private static String tailSystemLog(DistributionConfig sc) throws IOException { } return tailSystemLog(logFile); } - } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/Configuration.java b/geode-core/src/main/java/org/apache/geode/internal/logging/Configuration.java new file mode 100644 index 000000000000..566d9dd3ac78 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/Configuration.java @@ -0,0 +1,237 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.lang.SystemPropertyHelper.GEODE_PREFIX; +import static org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs.ONLY_WHEN_USING_DEFAULT_CONFIG; +import static org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope.GEODE_LOGGERS; +import static org.apache.geode.internal.logging.InternalLogWriter.CONFIG_LEVEL; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; + +import org.apache.geode.annotations.TestingOnly; +import org.apache.geode.internal.ClassPathLoader; + +/** + * Provides logging configuration by managing an {@link ProviderAgent} for the logging backend + * provider. + */ +public class Configuration implements LogConfigListener { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + public static final int DEFAULT_LOGWRITER_LEVEL = CONFIG_LEVEL; + + public static final String STARTUP_CONFIGURATION = "Startup Configuration: "; + + /** + * Default logging backend configuration file used for command-line tools including GFSH. + */ + public static final String CLI_CONFIG = "/log4j2-cli.xml"; + + public static final String GEODE_LOGGER_PREFIX = "org.apache.geode"; + public static final String MAIN_LOGGER_NAME = GEODE_LOGGER_PREFIX; + public static final String SECURITY_LOGGER_NAME = GEODE_LOGGER_PREFIX + ".security"; + + /** + * System property that may be used to override which {@code LogLevelUpdateOccurs} to use. + */ + public static final String LOG_LEVEL_UPDATE_OCCURS_PROPERTY = + GEODE_PREFIX + "LOG_LEVEL_UPDATE_OCCURS"; + + /** + * System property that may be used to override which {@code LogLevelUpdateScope} to use. + */ + static final String LOG_LEVEL_UPDATE_SCOPE_PROPERTY = + GEODE_PREFIX + "LOG_LEVEL_UPDATE_SCOPE"; + + /** + * System property that may be used to override which {@code ProviderAgent} to use. + */ + static final String PROVIDER_AGENT_NAME_PROPERTY = GEODE_PREFIX + "PROVIDER_AGENT_NAME"; + + /** + * The default {@code ProviderAgent} is {@code Log4jAgent}. + */ + static final String DEFAULT_PROVIDER_AGENT_NAME = + "org.apache.geode.internal.logging.log4j.Log4jAgent"; + + /** + * The default {@code LogLevelUpdateOccurs} is {@code ONLY_WHEN_USING_DEFAULT_CONFIG}. + */ + private static final LogLevelUpdateOccurs DEFAULT_LOG_LEVEL_UPDATE_OCCURS = + ONLY_WHEN_USING_DEFAULT_CONFIG; + + /** + * The default {@code LogLevelUpdateScope} is {@code GEODE_LOGGERS}. + */ + private static final LogLevelUpdateScope DEFAULT_LOG_LEVEL_UPDATE_SCOPE = GEODE_LOGGERS; + + private final LogLevelUpdateOccurs logLevelUpdateOccurs; + private final LogLevelUpdateScope logLevelUpdateScope; + + private final ProviderAgent providerAgent; + + /** + * Protected by synchronization on Configuration instance. + */ + private LogConfigSupplier logConfigSupplier; + + public static Configuration create() { + return create(getLogLevelUpdateOccurs(), getLogLevelUpdateScope(), createProviderAgent()); + } + + @TestingOnly + public static Configuration create(final ProviderAgent providerAgent) { + return create(getLogLevelUpdateOccurs(), getLogLevelUpdateScope(), providerAgent); + } + + @TestingOnly + public static Configuration create(final LogLevelUpdateOccurs logLevelUpdateOccurs, + final LogLevelUpdateScope logLevelUpdateScope) { + return create(logLevelUpdateOccurs, logLevelUpdateScope, createProviderAgent()); + } + + @TestingOnly + public static Configuration create(final LogLevelUpdateOccurs logLevelUpdateOccurs, + final LogLevelUpdateScope logLevelUpdateScope, final ProviderAgent providerAgent) { + return new Configuration(logLevelUpdateOccurs, logLevelUpdateScope, providerAgent); + } + + private Configuration(final LogLevelUpdateOccurs logLevelUpdateOccurs, + final LogLevelUpdateScope logLevelUpdateScope, final ProviderAgent providerAgent) { + this.logLevelUpdateOccurs = logLevelUpdateOccurs; + this.logLevelUpdateScope = logLevelUpdateScope; + this.providerAgent = providerAgent; + } + + static LogLevelUpdateOccurs getLogLevelUpdateOccurs() { + try { + return LogLevelUpdateOccurs.valueOf(System.getProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, + DEFAULT_LOG_LEVEL_UPDATE_OCCURS.name()).toUpperCase()); + } catch (IllegalArgumentException e) { + return DEFAULT_LOG_LEVEL_UPDATE_OCCURS; + } + } + + static LogLevelUpdateScope getLogLevelUpdateScope() { + try { + return LogLevelUpdateScope.valueOf(System.getProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, + DEFAULT_LOG_LEVEL_UPDATE_SCOPE.name()).toUpperCase()); + } catch (IllegalArgumentException e) { + return DEFAULT_LOG_LEVEL_UPDATE_SCOPE; + } + } + + static ProviderAgent createProviderAgent() { + String agentClassName = + System.getProperty(PROVIDER_AGENT_NAME_PROPERTY, DEFAULT_PROVIDER_AGENT_NAME); + try { + Class agentClass = + ClassPathLoader.getLatest().forName(agentClassName).asSubclass(ProviderAgent.class); + return agentClass.newInstance(); + } catch (ClassNotFoundException | ClassCastException | InstantiationException + | IllegalAccessException e) { + LOGGER.warn("Unable to create ProviderAgent of type {}", agentClassName, e); + } + return new NullProviderAgent(); + } + + /** + * Initializes logging configuration with the {@code LogConfigSupplier}. This configuration will + * register as a {@code LogConfigListener} and configure the {@code ProviderAgent}. + */ + public synchronized void initialize(final LogConfigSupplier logConfigSupplier) { + if (logConfigSupplier == null) { + throw new IllegalArgumentException("LogConfigSupplier must not be null"); + } + this.logConfigSupplier = logConfigSupplier; + logConfigSupplier.addLogConfigListener(this); + + configChanged(); + } + + @Override + public synchronized void configChanged() { + if (logConfigSupplier == null) { + throw new IllegalStateException("LogConfigSupplier must not be null"); + } + + LogConfig logConfig = logConfigSupplier.getLogConfig(); + + providerAgent.configure(logConfig, logLevelUpdateOccurs, logLevelUpdateScope); + } + + void enableLoggingToStandardOutput() { + providerAgent.enableLoggingToStandardOutput(); + } + + void disableLoggingToStandardOutputIfLoggingToFile() { + LogConfig logConfig = logConfigSupplier.getLogConfig(); + if (logConfig.getLogFile().exists()) { + providerAgent.disableLoggingToStandardOutput(); + } + } + + /** + * Removes this configuration as a {@code LogConfigListener} if it's currently registered and + * cleans up the {@code ProviderAgent}. + */ + public synchronized void shutdown() { + if (logConfigSupplier != null) { + logConfigSupplier.removeLogConfigListener(this); + logConfigSupplier = null; + } + + providerAgent.cleanup(); + } + + @TestingOnly + synchronized LogConfigSupplier getLogConfigSupplier() { + return logConfigSupplier; + } + + /** + * Controls whether or not log level updates should be triggered. + */ + public enum LogLevelUpdateOccurs { + NEVER, + ONLY_WHEN_USING_DEFAULT_CONFIG, + ALWAYS; + + public boolean never() { + return this == NEVER; + } + + public boolean always() { + return this == ALWAYS; + } + + public boolean onlyWhenUsingDefaultConfig() { + return this == ONLY_WHEN_USING_DEFAULT_CONFIG; + } + } + + /** + * Controls the scope of which packages of loggers are updated when the log level changes. + */ + public enum LogLevelUpdateScope { + GEODE_LOGGERS, + GEODE_AND_SECURITY_LOGGERS, + GEODE_AND_APPLICATION_LOGGERS, + ALL_LOGGERS + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/ConfigurationInfo.java b/geode-core/src/main/java/org/apache/geode/internal/logging/ConfigurationInfo.java new file mode 100644 index 000000000000..16fb1f777320 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/ConfigurationInfo.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; + +import org.apache.geode.internal.ClassPathLoader; + +/** + * Fetches the configuration info from {@code Log4jAgent} without direct class dependency. + * + *

+ * This could potentially be modified to support any logging backend but currently the only caller + * is the log Banner which is static. + */ +public class ConfigurationInfo { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + /** + * Fetches the configuration info from Log4jAgent without direct class dependency. + * + *

+ * If the Log4J2 Core classes are not in the classpath, the return value is simply + * "No configuration info found." + */ + public static String getConfigurationInfo() { + try { + Class agentClass = + ClassPathLoader.getLatest().forName(Configuration.DEFAULT_PROVIDER_AGENT_NAME) + .asSubclass(ProviderAgent.class); + Method method = agentClass.getMethod("getConfigurationInfo", null); + return (String) method.invoke(null, null); + } catch (ClassNotFoundException | ClassCastException | NoSuchMethodException + | IllegalAccessException | InvocationTargetException e) { + LOGGER.debug("Unable to invoke Log4jAgent.getConfigurationInfo()", e); + return "No configuration info found"; + } + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/InternalLogWriter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/InternalLogWriter.java index 86dc8bbe5885..1360c11a0d44 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/InternalLogWriter.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/InternalLogWriter.java @@ -95,8 +95,6 @@ public interface InternalLogWriter extends LogWriter, LogWriterI18n { int getLogWriterLevel(); - void setLogWriterLevel(int logWriterLevel); - boolean isSecure(); String getConnectionName(); diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigListener.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigListener.java new file mode 100644 index 000000000000..da785a62751b --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigListener.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +/** + * Listens for logging configuration changes from a {@code LogConfigSupplier}. + */ +public interface LogConfigListener { + + void configChanged(); +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigSupplier.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigSupplier.java index 15e091bf0429..e3ee6e48785b 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigSupplier.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LogConfigSupplier.java @@ -1,22 +1,35 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. */ package org.apache.geode.internal.logging; +import org.apache.geode.internal.statistics.StatisticsConfig; + +/** + * Provides logging configuration and change notification services to {@link LogConfigListener}s. + */ public interface LogConfigSupplier { LogConfig getLogConfig(); + + /** + * {@link StatisticsConfig} is used only to make logging and statistics behave similarly if both + * are configured. It would be nice to break this dependency so we can just use {@link LogConfig}. + */ + StatisticsConfig getStatisticsConfig(); + + void addLogConfigListener(LogConfigListener logConfigListener); + + void removeLogConfigListener(LogConfigListener logConfigListener); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LogFile.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LogFile.java new file mode 100644 index 000000000000..11461cffa147 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LogFile.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import java.io.File; + +/** + * Provides details about the system log file. + */ +public class LogFile implements LogFileDetails { + + private final LogFileDetails logFileDetails; + + public LogFile(final LogFileDetails logFileDetails) { + this.logFileDetails = logFileDetails; + } + + @Override + public File getChildLogFile() { + return logFileDetails.getChildLogFile(); + } + + @Override + public File getLogDir() { + return logFileDetails.getLogDir(); + } + + @Override + public int getMainLogId() { + return logFileDetails.getMainLogId(); + } + + @Override + public boolean useChildLogging() { + return logFileDetails.useChildLogging(); + } +} diff --git a/geode-junit/src/main/java/org/apache/geode/internal/logging/LogServiceIntegrationTestSupport.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LogFileDetails.java old mode 100755 new mode 100644 similarity index 60% rename from geode-junit/src/main/java/org/apache/geode/internal/logging/LogServiceIntegrationTestSupport.java rename to geode-core/src/main/java/org/apache/geode/internal/logging/LogFileDetails.java index 0476f7f1db72..319a39341303 --- a/geode-junit/src/main/java/org/apache/geode/internal/logging/LogServiceIntegrationTestSupport.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LogFileDetails.java @@ -14,19 +14,18 @@ */ package org.apache.geode.internal.logging; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import org.apache.logging.log4j.Level; +/** + * Details about the system log file. + */ +public interface LogFileDetails { + + File getChildLogFile(); + + File getLogDir(); -public class LogServiceIntegrationTestSupport { + int getMainLogId(); - public static void writeConfigFile(final File configFile, final Level level) throws IOException { - final BufferedWriter writer = new BufferedWriter(new FileWriter(configFile)); - writer.write("" + "" + "" - + "" + "" + ""); - writer.close(); - } + boolean useChildLogging(); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LogMessageRegex.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LogMessageRegex.java new file mode 100644 index 000000000000..adacb5834b8a --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LogMessageRegex.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.LogMessageRegex.Group.DATE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.LOG_LEVEL; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.MEMBER_NAME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.MESSAGE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.THREAD_ID; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.THREAD_NAME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.TIME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.TIME_ZONE; + +import java.util.regex.Pattern; + +/** + * Regex with named capture groups that can be used to match Geode log messages. + * + *

+ * Example usage with AssertJ: + * + *

+ * {@literal @}Test
+ * public void logMessageMatches() {}
+ *   String logMessage = "[info 2018/09/24 12:35:59.515 PDT logMessageRegexTest {@literal <}main> tid=0x1] this is a log statement";
+ *   assertThat(logMessage).matches(LogMessageRegex.getRegex());
+ * }
+ * 
+ *

+ * Example usage with named group capturing: + * + *

+ * {@literal @}Test
+ * public void logLevelIsInfo() {
+ *   Matcher matcher = getPattern().matcher(logMessage);
+ *   assertThat(matcher.matches()).isTrue();
+ *   assertThat(matcher.group(LogMessageRegex.Groups.LOG_LEVEL.getName())).isEqualTo("info");
+ * }
+ * 
+ *

+ * Note that a captured threadName will be in the form {@code } and threadId will be in + * the form {@code tid=hexThreadId} where hexThreadId is the threadId in hexadecimal. + */ +public class LogMessageRegex { + + private static final String REGEX = "^\\[" + LOG_LEVEL + " " + DATE + " " + TIME + " " + TIME_ZONE + + " " + MEMBER_NAME + "[\\s]?" + THREAD_NAME + " " + THREAD_ID + "] " + MESSAGE + "$"; + + public static String getRegex() { + return REGEX; + } + + public static Pattern getPattern() { + return Pattern.compile(REGEX); + } + + public enum Group { + LOG_LEVEL(1, "logLevel", "(?[a-z]+)"), + DATE(2, "date", "(?\\d{4}\\/\\d{2}\\/\\d{2})"), + TIME(3, "time", "(?

+ * Returned Logger is wrapped inside an instance of {@link FastLogger} which skips expensive + * filtering, debug and trace handling with a volatile boolean. This optimization is turned on only + * when using the default Geode {@code log4j2.xml} by checking for the existence of this property: + * + *

+ * <Property name="geode-default">true</Property>
+ * 
+ * + *

+ * Returned Logger uses {@link GemFireParameterizedMessageFactory} to create + * {@link GemFireParameterizedMessage} which excludes {@link Region}s from being handled as a + * {@code Map} and {@link EntriesSet} from being handled as a {@code Collection}. Without this + * change, using a {@code Region} or {@code EntriesSet} in a log statement can result in an + * expensive operation or even a hang in the case of a {@code PartitionedRegion}. + * + *

+ * {@code LogService} only uses Log4J2 API so that any logging backend may be used. */ public class LogService extends LogManager { - private static final Logger LOGGER = StatusLogger.getLogger(); - - // This is highest point in the hierarchy for all Geode logging - public static final String ROOT_LOGGER_NAME = ""; - public static final String BASE_LOGGER_NAME = "org.apache.geode"; - public static final String MAIN_LOGGER_NAME = "org.apache.geode"; - public static final String SECURITY_LOGGER_NAME = "org.apache.geode.security"; - - public static final String GEODE_VERBOSE_FILTER = "{GEODE_VERBOSE}"; - public static final String GEMFIRE_VERBOSE_FILTER = "{GEMFIRE_VERBOSE}"; - public static final String DEFAULT_CONFIG = "/log4j2.xml"; - public static final String CLI_CONFIG = "/log4j2-cli.xml"; - - protected static final String STDOUT = "STDOUT"; - - private static final PropertyChangeListener propertyChangeListener = - new PropertyChangeListenerImpl(); - - /** - * Name of variable that is set to "true" in log4j2.xml to indicate that it is the default geode - * config xml. - */ - private static final String GEMFIRE_DEFAULT_PROPERTY = "geode-default"; - - /** - * Protected by static synchronization. Used for removal and adding stdout back in. - */ - private static Appender stdoutAppender; - - static { - init(); - } - private LogService() { // do not instantiate } - private static void init() { - LoggerContext loggerContext = getLoggerContext(BASE_LOGGER_NAME); - loggerContext.removePropertyChangeListener(propertyChangeListener); - loggerContext.addPropertyChangeListener(propertyChangeListener); - loggerContext.reconfigure(); // propertyChangeListener invokes configureFastLoggerDelegating - configureLoggers(false, false); - } - - public static void reconfigure() { - init(); - } - - public static void configureLoggers(final boolean hasLogFile, final boolean hasSecurityLogFile) { - Configurator.getOrCreateLoggerConfig(BASE_LOGGER_NAME, true, false); - Configurator.getOrCreateLoggerConfig(MAIN_LOGGER_NAME, true, hasLogFile); - boolean useMainLoggerForSecurity = !hasSecurityLogFile; - Configurator.getOrCreateLoggerConfig(SECURITY_LOGGER_NAME, useMainLoggerForSecurity, - hasSecurityLogFile); - } - - public static AppenderContext getAppenderContext() { - return new AppenderContext(); - } - - public static AppenderContext getAppenderContext(final String name) { - return new AppenderContext(name); - } - - public static boolean isUsingGemFireDefaultConfig() { - Configuration configuration = getConfiguration(); - - StrSubstitutor strSubstitutor = configuration.getStrSubstitutor(); - StrLookup variableResolver = strSubstitutor.getVariableResolver(); - - String value = variableResolver.lookup(GEMFIRE_DEFAULT_PROPERTY); - - return "true".equals(value); - } - - public static String getConfigurationInfo() { - return getConfiguration().getConfigurationSource().toString(); - } - - /** - * Finds a Log4j configuration file in the current directory. The names of the files to look for - * are the same as those that Log4j would look for on the classpath. - * - * @return A File for the configuration file or null if one isn't found. - */ - public static File findLog4jConfigInCurrentDir() { - return ConfigLocator.findConfigInWorkingDirectory(); - } - /** * Returns a Logger with the name of the calling class. * * @return The Logger for the calling class. */ public static Logger getLogger() { + String name = StackLocator.getInstance().getCallerClass(2).getName(); return new FastLogger( - LogManager.getLogger(getClassName(2), GemFireParameterizedMessageFactory.INSTANCE)); + LogManager.getLogger(name, GemFireParameterizedMessageFactory.INSTANCE)); } public static Logger getLogger(final String name) { @@ -147,6 +70,7 @@ public static Logger getLogger(final String name) { /** * Returns a LogWriterLogger that is decorated with the LogWriter and LogWriterI18n methods. + * *

* This is the bridge to LogWriter and LogWriterI18n that we need to eventually stop using in * phase 1. We will switch over from a shared LogWriterLogger instance to having every GemFire @@ -158,123 +82,4 @@ public static LogWriterLogger createLogWriterLogger(final String name, final String connectionName, final boolean isSecure) { return LogWriterLogger.create(name, connectionName, isSecure); } - - /** - * Return the Log4j Level associated with the int level. - * - * @param intLevel The int value of the Level to return. - * - * @return The Level. - * - * @throws IllegalArgumentException if the Level int is not registered. - */ - public static Level toLevel(final int intLevel) { - for (Level level : Level.values()) { - if (level.intLevel() == intLevel) { - return level; - } - } - - throw new IllegalArgumentException("Unknown int level [" + intLevel + "]."); - } - - /** - * Gets the class name of the caller in the current stack at the given {@code depth}. - * - * @param depth a 0-based index in the current stack. - * - * @return a class name - */ - public static String getClassName(final int depth) { - return new Throwable().getStackTrace()[depth].getClassName(); - } - - public static Configuration getConfiguration() { - return getRootLoggerContext().getConfiguration(); - } - - public static void configureFastLoggerDelegating() { - Configuration configuration = getConfiguration(); - if (Configurator.hasContextWideFilter(configuration) - || Configurator.hasAppenderFilter(configuration) - || Configurator.hasDebugOrLower(configuration) - || Configurator.hasLoggerFilter(configuration) - || Configurator.hasAppenderRefFilter(configuration)) { - FastLogger.setDelegating(true); - } else { - FastLogger.setDelegating(false); - } - } - - public static void setSecurityLogLevel(Level level) { - Configurator.setLevel(SECURITY_LOGGER_NAME, level); - } - - public static Level getBaseLogLevel() { - return Configurator.getLevel(BASE_LOGGER_NAME); - } - - public static void setBaseLogLevel(Level level) { - if (isUsingGemFireDefaultConfig()) { - Configurator.setLevel(ROOT_LOGGER_NAME, level); - } - Configurator.setLevel(BASE_LOGGER_NAME, level); - Configurator.setLevel(MAIN_LOGGER_NAME, level); - } - - private static LoggerContext getLoggerContext(final String name) { - return ((org.apache.logging.log4j.core.Logger) LogManager - .getLogger(name, GemFireParameterizedMessageFactory.INSTANCE)).getContext(); - } - - static LoggerContext getRootLoggerContext() { - return ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).getContext(); - } - - /** - * Removes STDOUT ConsoleAppender from ROOT logger. Only called when using the log4j2-default.xml - * configuration. This is done when creating the LogWriterAppender for log-file. The Appender - * instance is stored in stdoutAppender so it can be restored later using restoreConsoleAppender. - */ - public static synchronized void removeConsoleAppender() { - AppenderContext appenderContext = getAppenderContext(ROOT_LOGGER_NAME); - LoggerConfig loggerConfig = appenderContext.getLoggerConfig(); - Appender stdoutAppender = loggerConfig.getAppenders().get(STDOUT); - if (stdoutAppender != null) { - loggerConfig.removeAppender(STDOUT); - LogService.stdoutAppender = stdoutAppender; - appenderContext.getLoggerContext().updateLoggers(); - } - } - - /** - * Restores STDOUT ConsoleAppender to ROOT logger. Only called when using the log4j2-default.xml - * configuration. This is done when the LogWriterAppender for log-file is destroyed. The Appender - * instance stored in stdoutAppender is used. - */ - public static synchronized void restoreConsoleAppender() { - if (stdoutAppender == null) { - return; - } - AppenderContext appenderContext = getAppenderContext(ROOT_LOGGER_NAME); - LoggerConfig loggerConfig = appenderContext.getLoggerConfig(); - Appender stdoutAppender = loggerConfig.getAppenders().get(STDOUT); - if (stdoutAppender == null) { - loggerConfig.addAppender(LogService.stdoutAppender, Level.ALL, null); - appenderContext.getLoggerContext().updateLoggers(); - } - } - - private static class PropertyChangeListenerImpl implements PropertyChangeListener { - - @Override - public void propertyChange(final PropertyChangeEvent evt) { - LOGGER.debug("LogService responding to a property change event. Property name is {}.", - evt.getPropertyName()); - - if (evt.getPropertyName().equals(LoggerContext.PROPERTY_CONFIG)) { - configureFastLoggerDelegating(); - } - } - } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterFactory.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterFactory.java index 470f85ae2bd2..3badc4c57df7 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterFactory.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterFactory.java @@ -14,84 +14,33 @@ */ package org.apache.geode.internal.logging; -import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; +import static org.apache.geode.internal.logging.Configuration.MAIN_LOGGER_NAME; +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; -import org.apache.geode.distributed.internal.DistributionConfig; -import org.apache.geode.distributed.internal.InternalDistributedSystem; -import org.apache.geode.distributed.internal.InternalLocator; -import org.apache.geode.internal.Banner; -import org.apache.geode.internal.ConfigSource; -import org.apache.geode.internal.logging.log4j.LogMarker; import org.apache.geode.internal.logging.log4j.LogWriterLogger; /** - * Creates LogWriterLogger instances. - * + * Factory for creating {@link LogWriterLogger}s. */ public class LogWriterFactory { - // LOG: RemoteGfManagerAgent and CacheCreation use this when there's no InternalDistributedSystem - public static InternalLogWriter toSecurityLogWriter(final InternalLogWriter logWriter) { - return new SecurityLogWriter(logWriter.getLogWriterLevel(), logWriter); - } - /** * Creates the log writer for a distributed system based on the system's parsed configuration. The * initial banner and messages are also entered into the log by this method. * - * @param isLoner Whether the distributed system is a loner or not - * @param isSecure Whether a logger for security related messages has to be created - * @param config The DistributionConfig for the target distributed system - * @param logConfig if true log the configuration + * @param logConfig geode configuration for the logger + * @param secure indicates if the logger is for security related messages */ - public static InternalLogWriter createLogWriterLogger(final boolean isLoner, - final boolean isSecure, final LogConfig config, final boolean logConfig) { - - // if isSecurity then use "org.apache.geode.security" else use "org.apache.geode" - String name = null; - if (isSecure) { - name = LogService.SECURITY_LOGGER_NAME; - } else { - name = LogService.MAIN_LOGGER_NAME; - } - - // create the LogWriterLogger - final LogWriterLogger logger = - LogService.createLogWriterLogger(name, config.getName(), isSecure); - - if (isSecure) { - logger.setLogWriterLevel(((DistributionConfig) config).getSecurityLogLevel()); - } else { - boolean defaultSource = false; - if (config instanceof DistributionConfig) { - ConfigSource source = ((DistributionConfig) config).getConfigSource(LOG_LEVEL); - if (source == null) { - defaultSource = true; - } - } - if (!defaultSource) { - // LOG: fix bug #51709 by not setting if log-level was not specified - // LOG: let log4j2.xml specify log level which defaults to INFO - logger.setLogWriterLevel(config.getLogLevel()); - } - } - - // log the banner - if (!Boolean.getBoolean(InternalLocator.INHIBIT_DM_BANNER) - && InternalDistributedSystem.getReconnectAttemptCounter() == 0 // avoid filling up logs - // during auto-reconnect - && !isSecure // && !isLoner /* do this on a loner to fix bug 35602 */ - && logConfig) { - logger.info(LogMarker.CONFIG_MARKER, Banner.getString(null)); - } else { - logger.debug("skipping banner - " + InternalLocator.INHIBIT_DM_BANNER + " is set to true"); - } + public static InternalLogWriter createLogWriterLogger(final LogConfig logConfig, + final boolean secure) { + String name = secure ? SECURITY_LOGGER_NAME : MAIN_LOGGER_NAME; + return LogService.createLogWriterLogger(name, logConfig.getName(), secure); + } - // log the config - if (logConfig && !isLoner) { - logger.info(LogMarker.CONFIG_MARKER, "Startup Configuration: {}", - config.toLoggerString()); - } - return logger; + /** + * Wraps the {@code logWriter} within a {@link SecurityLogWriter}. + */ + public static InternalLogWriter toSecurityLogWriter(final InternalLogWriter logWriter) { + return new SecurityLogWriter(logWriter.getLogWriterLevel(), logWriter); } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterLevel.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterLevel.java index 2415f98ec719..d1afceb046da 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterLevel.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LogWriterLevel.java @@ -14,6 +14,27 @@ */ package org.apache.geode.internal.logging; +import org.apache.geode.LogWriter; + +/** + * Levels used for identifying the severity of a {@link LogWriter} event. From least specific to + * most: + *

    + *
  • {@link #ALL} (least specific, all logging)
  • + *
  • {@link #FINEST} (least specific, a lot of logging)
  • + *
  • {@link #FINER}
  • + *
  • {@link #FINE}
  • + *
  • {@link #CONFIG}
  • + *
  • {@link #INFO}
  • + *
  • {@link #WARNING}
  • + *
  • {@link #ERROR}
  • + *
  • {@link #SEVERE} (most specific, a little logging)
  • + *
  • {@link #NONE} (most specific, no logging)
  • + *
+ * + *

+ * Default level in Geode is {@link #INFO}. + */ public enum LogWriterLevel { ALL(InternalLogWriter.ALL_LEVEL), @@ -27,13 +48,22 @@ public enum LogWriterLevel { SEVERE(InternalLogWriter.SEVERE_LEVEL), NONE(InternalLogWriter.NONE_LEVEL); - private final int logWriterLevel; + public static LogWriterLevel find(final int intLevel) { + for (LogWriterLevel logWriterLevel : values()) { + if (logWriterLevel.intLevel == intLevel) { + return logWriterLevel; + } + } + throw new IllegalArgumentException("No LogWriterLevel found for intLevel " + intLevel); + } + + private final int intLevel; - LogWriterLevel(int logWriterLevel) { - this.logWriterLevel = logWriterLevel; + LogWriterLevel(final int intLevel) { + this.intLevel = intLevel; } - public int getLogWriterLevel() { - return logWriterLevel; + public int intLevel() { + return intLevel; } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSession.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSession.java new file mode 100644 index 000000000000..8399c9a9f68c --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSession.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.Configuration.STARTUP_CONFIGURATION; +import static org.apache.geode.internal.logging.SessionContext.State.CREATED; +import static org.apache.geode.internal.logging.SessionContext.State.STARTED; +import static org.apache.geode.internal.logging.SessionContext.State.STOPPED; + +import java.util.Optional; + +import org.apache.logging.log4j.Logger; + +import org.apache.geode.annotations.TestingOnly; +import org.apache.geode.internal.Banner; + +/** + * Configures the logging {@code Configuration} and provides lifecycle to Geode logging. + */ +public class LoggingSession implements SessionContext { + + private static final Logger logger = LogService.getLogger(); + + private final Configuration configuration; + private final LoggingSessionListeners loggingSessionListeners; + + private volatile boolean logBanner; + private volatile boolean logConfiguration; + + private State state = STOPPED; + + public static LoggingSession create() { + return create(Configuration.create(), LoggingSessionListeners.get()); + } + + @TestingOnly + static LoggingSession create(final Configuration configuration, + final LoggingSessionListeners loggingSessionListeners) { + return new LoggingSession(configuration, loggingSessionListeners); + } + + LoggingSession(final Configuration configuration, + final LoggingSessionListeners loggingSessionListeners) { + this.configuration = configuration; + this.loggingSessionListeners = loggingSessionListeners; + } + + public synchronized void createSession(final LogConfigSupplier logConfigSupplier) { + createSession(logConfigSupplier, true, true); + } + + public synchronized void createSession(final LogConfigSupplier logConfigSupplier, + final boolean logBanner, final boolean logConfiguration) { + configuration.initialize(logConfigSupplier); + state = state.changeTo(CREATED); + loggingSessionListeners.createSession(this); + + this.logBanner = logBanner; + this.logConfiguration = logConfiguration; + } + + /** + * Note: nothing checks Boolean.getBoolean(InternalLocator.INHIBIT_DM_BANNER anymore. + */ + public synchronized void startSession() { + state = state.changeTo(STARTED); + loggingSessionListeners.startSession(); + configuration.disableLoggingToStandardOutputIfLoggingToFile(); + + if (logBanner) { + logger.info(Banner.getString(null)); + } + if (logConfiguration) { + String configInfo = configuration.getLogConfigSupplier().getLogConfig().toLoggerString(); + logger.info(STARTUP_CONFIGURATION + configInfo); + } + } + + public synchronized void stopSession() { + configuration.enableLoggingToStandardOutput(); + state = state.changeTo(STOPPED); + loggingSessionListeners.stopSession(); + } + + public synchronized void shutdown() { + configuration.shutdown(); + } + + public Optional getLogFile() { + return loggingSessionListeners.getLogFile(); + } + + @Override + public State getState() { + return state; + } + + @Override + public LogConfigSupplier getLogConfigSupplier() { + return configuration.getLogConfigSupplier(); + } + + @TestingOnly + LoggingSessionListeners getLoggingSessionListeners() { + return loggingSessionListeners; + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListener.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListener.java new file mode 100644 index 000000000000..01defa0aba2a --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListener.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import java.util.Optional; + +/** + * Listens for state changes to a {@code LoggingSession}. + * + *

+ * Listeners include the custom Log4J2 Appenders. Appender actions in response to starting a new + * session: + *

    + *
  • {@code GeodeConsoleAppender} pauses so that logging stops going to STDOUT. + *
  • {@code LogWriterAppender}s (main log and security log) resume so that logging starts + * going to the Geode log files. + *
+ * Appender actions in response to stopping a session: + *
    + *
  • {@code GeodeConsoleAppender} resumes so that logging resumes going to STDOUT. + *
  • {@code LogWriterAppender}s (main log and security log) pause so that logging stops + * going to the Geode log files. + *
+ */ +public interface LoggingSessionListener { + + /** + * Notifies listeners of a new logging session with new {@code LogConfig}. + */ + void createSession(SessionContext sessionContext); + + /** + * Starts the new logging session. + */ + void startSession(); + + /** + * Stops the logging session. + */ + void stopSession(); + + /** + * Optional: provide {@link LogFile} to {@link LoggingSession}. + */ + Optional getLogFile(); +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListeners.java b/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListeners.java new file mode 100644 index 000000000000..f355227052a5 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/LoggingSessionListeners.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import java.util.LinkedHashSet; +import java.util.Optional; +import java.util.Set; + +import org.apache.geode.annotations.TestingOnly; + +/** + * Manages registration of {@link LoggingSessionListener}s and provides notifications to them. + */ +public class LoggingSessionListeners { + + private static final LoggingSessionListeners INSTANCE = new LoggingSessionListeners(); + + public static LoggingSessionListeners get() { + return INSTANCE; + } + + private final Set listeners; + + @TestingOnly + LoggingSessionListeners() { + listeners = new LinkedHashSet<>(); + } + + /** + * Adds the {@code LoggingSessionListener}. + */ + public void addLoggingLifecycleListener(final LoggingSessionListener listener) { + listeners.add(listener); + } + + /** + * Removes the {@code LoggingSessionListener}. + */ + public void removeLoggingLifecycleListener(final LoggingSessionListener listener) { + listeners.remove(listener); + } + + /** + * Removes all currently registered {@code LoggingSessionListener}s. + */ + public void clear() { + listeners.clear(); + } + + /** + * Provides {@code createSession} notification to all registered listeners. + */ + public void createSession(final SessionContext sessionContext) { + for (LoggingSessionListener listener : listeners) { + listener.createSession(sessionContext); + } + } + + /** + * Provides {@code startSession} notification to all registered listeners. + */ + public void startSession() { + for (LoggingSessionListener listener : listeners) { + listener.startSession(); + } + } + + /** + * Provides {@code stopSession} notification to all registered listeners. + */ + public void stopSession() { + for (LoggingSessionListener listener : listeners) { + listener.stopSession(); + } + } + + /** + * Returns the system {@link LogFile} from any {@link LoggingSessionListener} that offers it. + */ + public Optional getLogFile() { + for (LoggingSessionListener listener : listeners) { + if (listener.getLogFile().isPresent()) { + return listener.getLogFile(); + } + } + return Optional.empty(); + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java index 14f9212c4f8e..95559a65f672 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java @@ -21,20 +21,20 @@ import java.io.PrintStream; import java.io.PrintWriter; +import org.apache.geode.LogWriter; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.OSProcess; import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; import org.apache.geode.internal.io.RollingFileHandler; -import org.apache.geode.internal.logging.log4j.AlertAppender; import org.apache.geode.internal.util.LogFileUtils; /** - * Implementation of {@link LogWriterI18n} for distributed system members. It's just like + * Implementation of {@link LogWriter} for distributed system members. It's just like * {@link LocalLogWriter} except it has support for rolling and alerts. * * @since Geode 1.0 */ -public class ManagerLogWriter extends LocalLogWriter { +public class ManagerLogWriter extends LocalLogWriter implements LogFileDetails { private static final String TEST_FILE_SIZE_LIMIT_IN_KB_PROPERTY = DistributionConfig.GEMFIRE_PREFIX + "logging.test.fileSizeLimitInKB"; @@ -62,16 +62,19 @@ public class ManagerLogWriter extends LocalLogWriter { private boolean started; + private final boolean loner; + /** * Creates a writer that logs to printStream. * * @param level only messages greater than or equal to this value will be logged. * @param printStream is the stream that message will be printed to. + * @param loner if the distributed member is not part of a cluster * * @throws IllegalArgumentException if level is not in legal range */ - public ManagerLogWriter(int level, PrintStream printStream) { - this(level, printStream, null); + public ManagerLogWriter(final int level, final PrintStream printStream, final boolean loner) { + this(level, printStream, null, loner); } /** @@ -80,25 +83,32 @@ public ManagerLogWriter(int level, PrintStream printStream) { * @param level only messages greater than or equal to this value will be logged. * @param printStream is the stream that message will be printed to. * @param connectionName Name of the connection associated with this logger + * @param loner if the distributed member is not part of a cluster * * @throws IllegalArgumentException if level is not in legal range * * @since GemFire 3.5 */ - public ManagerLogWriter(int level, PrintStream printStream, String connectionName) { + public ManagerLogWriter(final int level, final PrintStream printStream, + final String connectionName, final boolean loner) { super(level, printStream, connectionName); fileSizeLimitInKB = Boolean.getBoolean(TEST_FILE_SIZE_LIMIT_IN_KB_PROPERTY); rollingFileHandler = new MainWithChildrenRollingFileHandler(); + this.loner = loner; } /** * Sets the config that should be used by this manager to decide how to manage its logging. */ - public void setConfig(LogConfig config) { + public void setConfig(final LogConfig config) { this.config = config; configChanged(); } + public LogConfig getConfig() { + return config; + } + /** * Call when the config changes at runtime. */ @@ -126,18 +136,26 @@ public void configChanged() { } } + @Override public File getChildLogFile() { return activeLogFile; } + @Override public File getLogDir() { return logDir; } + @Override public int getMainLogId() { return mainLogId; } + @Override + public boolean useChildLogging() { + return useChildLogging; + } + private File getNextChildLogFile() { String path = config.getLogFile().getPath(); int extIndex = path.lastIndexOf('.'); @@ -158,10 +176,6 @@ private File getNextChildLogFile() { } } - public boolean useChildLogging() { - return useChildLogging; - } - private long getLogFileSizeLimit() { if (rolling || mainLog) { return Long.MAX_VALUE; @@ -184,7 +198,7 @@ private long getLogDiskSpaceLimit() { return result * (1024 * 1024); } - private String getMetaLogFileName(String baseLogFileName, int mainLogId) { + private String getMetaLogFileName(final String baseLogFileName, final int mainLogId) { String metaLogFile = null; int extIndex = baseLogFileName.lastIndexOf('.'); String ext = ""; @@ -202,7 +216,7 @@ private String getMetaLogFileName(String baseLogFileName, int mainLogId) { return metaLogFile; } - private synchronized void switchLogs(File newLog, boolean newIsMain) { + private synchronized void switchLogs(final File newLog, final boolean newIsMain) { rolling = true; try { try { @@ -244,8 +258,8 @@ private synchronized void switchLogs(File newLog, boolean newIsMain) { File tempLogDir = rollingFileHandler.getParentFile(config.getLogFile()); tempFile = File.createTempFile("mlw", null, tempLogDir); // close the old print writer down before we do the rename - PrintStream tempPrintStream = OSProcess.redirectOutput(tempFile, - AlertAppender.getInstance().isAlertingDisabled()/* See #49492 */); + // do not redirect if loner -- see #49492 + PrintStream tempPrintStream = OSProcess.redirectOutput(tempFile, !loner); PrintWriter oldPrintWriter = setTarget(new PrintWriter(tempPrintStream, true)); if (oldPrintWriter != null) { oldPrintWriter.close(); @@ -265,8 +279,7 @@ private synchronized void switchLogs(File newLog, boolean newIsMain) { activeLogFile = new File(oldName); // Don't redirect sysouts/syserrs to client log file. See #49492. // IMPORTANT: This assumes that only a loner would have sendAlert set to false. - PrintStream printStream = OSProcess.redirectOutput(activeLogFile, - AlertAppender.getInstance().isAlertingDisabled()); + PrintStream printStream = OSProcess.redirectOutput(activeLogFile, !loner); PrintWriter oldPrintWriter = setTarget(new PrintWriter(printStream, true), activeLogFile.length()); if (oldPrintWriter != null) { @@ -312,7 +325,7 @@ public void write(int b) throws IOException { } } - public static File getLogNameForOldMainLog(File log, boolean useOldFile) { + public static File getLogNameForOldMainLog(final File log, final boolean useOldFile) { // this is just searching for the existing logfile name we need to search for meta log file name RollingFileHandler rollingFileHandler = new MainWithChildrenRollingFileHandler(); File dir = rollingFileHandler.getParentFile(log.getAbsoluteFile()); @@ -339,7 +352,7 @@ public static File getLogNameForOldMainLog(File log, boolean useOldFile) { return new File(sb.toString()); } - private void checkDiskSpace(File newLog) { + private void checkDiskSpace(final File newLog) { rollingFileHandler.checkDiskSpace("log", newLog, getLogDiskSpaceLimit(), logDir, mainLogWriter); } @@ -351,7 +364,7 @@ private void rollLogIfFull() { rollLog(true); } - private void rollLog(boolean ifFull) { + private void rollLog(final boolean ifFull) { if (!useChildLogging()) { return; } @@ -393,7 +406,7 @@ private boolean activeLogFull() { } @Override - public void writeFormattedMessage(String message) { + public void writeFormattedMessage(final String message) { rollLogIfFull(); super.writeFormattedMessage(message); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriterFactory.java b/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriterFactory.java new file mode 100644 index 000000000000..d91f9d9d0541 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriterFactory.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.ManagerLogWriter.getLogNameForOldMainLog; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; + +import org.apache.geode.GemFireIOException; +import org.apache.geode.annotations.TestingOnly; +import org.apache.geode.internal.OSProcess; +import org.apache.geode.internal.process.ProcessLauncherContext; +import org.apache.geode.internal.statistics.StatisticsConfig; +import org.apache.geode.internal.util.LogFileUtils; + +/** + * Factory for creating a {@link ManagerLogWriter}. + */ +public class ManagerLogWriterFactory { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + private final LogFileRolloverDetails logFileRolloverDetails; + + private boolean security; + private boolean appendLog; + + public ManagerLogWriterFactory() { + logFileRolloverDetails = new LogFileRolloverDetails(); + } + + public ManagerLogWriterFactory setSecurity(final boolean value) { + security = value; + return this; + } + + public ManagerLogWriterFactory setAppendLog(final boolean value) { + appendLog = value; + return this; + } + + public LogFileRolloverDetails getLogFileRolloverDetails() { + return logFileRolloverDetails; + } + + public ManagerLogWriter create(final LogConfig logConfig, final StatisticsConfig statsConfig) { + File logFile = getLogFile(logConfig); + if (logFile == null || logFile.equals(new File(""))) { + return null; + } + + // if logFile exists attempt to rename it for rolling + if (logFile.exists()) { + boolean useChildLogging = useChildLogging(logConfig); + boolean statArchivesRolling = statArchivesRolling(statsConfig); + + if (!appendLog || useChildLogging || statArchivesRolling) { + File oldMain = + getLogNameForOldMainLog(logFile, security || useChildLogging || statArchivesRolling); + + boolean succeeded = LogFileUtils.renameAggressively(logFile, oldMain); + + if (succeeded) { + logFileRolloverDetails.message = String.format("Renamed old log file to %s.", oldMain); + } else { + logFileRolloverDetails.warning = true; + logFileRolloverDetails.message = + String.format("Could not rename %s to %s.", logFile, oldMain); + } + } + } + + ManagerLogWriter logWriter = newManagerLogWriter(logConfig, createPrintStream(logFile)); + logWriter.setConfig(logConfig); + redirectOutput(logConfig); + return logWriter; + } + + @TestingOnly + File getLogFile(final LogConfig config) { + if (security) { + return config.getSecurityLogFile(); + } else { + return config.getLogFile(); + } + } + + @TestingOnly + int getLogLevel(final LogConfig config) { + if (security) { + return config.getSecurityLogLevel(); + } else { + return config.getLogLevel(); + } + } + + private boolean useChildLogging(final LogConfig config) { + return config.getLogFile() != null + && !config.getLogFile().equals(new File("")) && config.getLogFileSizeLimit() != 0; + } + + private boolean statArchivesRolling(final StatisticsConfig config) { + return config.getStatisticArchiveFile() != null + && !config.getStatisticArchiveFile().equals(new File("")) + && config.getArchiveFileSizeLimit() != 0 && config.getStatisticSamplingEnabled(); + } + + private PrintStream createPrintStream(final File logFile) { + FileOutputStream fos; + try { + fos = new FileOutputStream(logFile, true); + } catch (FileNotFoundException e) { + String message = String.format("Could not open log file %s.", logFile); + throw new GemFireIOException(message, e); + } + return new PrintStream(fos); + } + + private ManagerLogWriter newManagerLogWriter(final LogConfig config, + final PrintStream printStream) { + if (security) { + return new SecurityManagerLogWriter(getLogLevel(config), printStream, config.getName(), + config.isLoner()); + } else { + return new ManagerLogWriter(getLogLevel(config), printStream, config.getName(), + config.isLoner()); + } + } + + private void redirectOutput(final LogConfig config) { + if (ProcessLauncherContext.isRedirectingOutput()) { + try { + OSProcess.redirectOutput(config.getLogFile()); + } catch (IOException e) { + LOGGER.error("Unable to redirect output to {}", config.getLogFile(), e); + } + } + } + + public static class LogFileRolloverDetails { + + private String message; + private boolean warning; + + public String getMessage() { + return message; + } + + public boolean isWarning() { + return warning; + } + + public boolean exists() { + return message != null; + } + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/NullLogFile.java b/geode-core/src/main/java/org/apache/geode/internal/logging/NullLogFile.java new file mode 100644 index 000000000000..2e5e9c73c482 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/NullLogFile.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import java.io.File; + +/** + * {@link LogFile} with default details of null values. + */ +public class NullLogFile extends LogFile { + + private static final NullLogFile INSTANCE = new NullLogFile(); + + public static NullLogFile get() { + return INSTANCE; + } + + public NullLogFile() { + super(new LogFileDetails() { + @Override + public File getChildLogFile() { + return null; + } + + @Override + public File getLogDir() { + return null; + } + + @Override + public int getMainLogId() { + return 0; + } + + @Override + public boolean useChildLogging() { + return false; + } + }); + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/NullLogWriter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/NullLogWriter.java new file mode 100644 index 000000000000..0dfba7848d0e --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/NullLogWriter.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.commons.io.output.NullOutputStream.NULL_OUTPUT_STREAM; + +import java.io.PrintStream; + +/** + * {@link ManagerLogWriter} that does nothing. + */ +public class NullLogWriter extends ManagerLogWriter { + + public NullLogWriter() { + this(LogWriterLevel.NONE.intLevel(), new PrintStream(NULL_OUTPUT_STREAM), true); + } + + public NullLogWriter(final int level, final PrintStream printStream, final boolean loner) { + super(level, printStream, loner); + } + + public NullLogWriter(final int level, final PrintStream printStream, final String connectionName, + final boolean loner) { + super(level, printStream, connectionName, loner); + } + + @Override + public void configChanged() { + // nothing + } + + @Override + public void startupComplete() { + // nothing + } + + @Override + public void shuttingDown() { + // nothing + } + + @Override + public void closingLogFile() { + // nothing + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/NullLoggingSession.java b/geode-core/src/main/java/org/apache/geode/internal/logging/NullLoggingSession.java new file mode 100644 index 000000000000..4611670c6bbf --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/NullLoggingSession.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +/** + * {@link LoggingSession} that does nothing. + */ +public class NullLoggingSession extends LoggingSession { + + public static LoggingSession create() { + return new NullLoggingSession(); + } + + NullLoggingSession() { + super(null, null); + } + + @Override + public void createSession(final LogConfigSupplier logConfigSupplier) { + // nothing + } + + @Override + public void startSession() { + // nothing + } + + @Override + public void stopSession() { + // nothing + } + + @Override + public void shutdown() {} +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/NullProviderAgent.java b/geode-core/src/main/java/org/apache/geode/internal/logging/NullProviderAgent.java new file mode 100644 index 000000000000..55a8017f8883 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/NullProviderAgent.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope; + +/** + * {@link ProviderAgent} that does nothing. + */ +public class NullProviderAgent implements ProviderAgent { + + @Override + public void configure(final LogConfig logConfig, final LogLevelUpdateOccurs logLevelUpdateOccurs, + final LogLevelUpdateScope logLevelUpdateScope) { + // nothing + } + + @Override + public void cleanup() { + // nothing + } + + @Override + public void enableLoggingToStandardOutput() { + // nothing + } + + @Override + public void disableLoggingToStandardOutput() { + // nothing + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/ProviderAgent.java b/geode-core/src/main/java/org/apache/geode/internal/logging/ProviderAgent.java new file mode 100644 index 000000000000..75a2f37f910a --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/ProviderAgent.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope; + +/** + * Provides custom configuration of the logging backend for Geode logging. + */ +public interface ProviderAgent { + + /** + * Updates the logging backend with custom configuration. + */ + void configure(final LogConfig logConfig, final LogLevelUpdateOccurs logLevelUpdateOccurs, + final LogLevelUpdateScope logLevelUpdateScope); + + /** + * Removes any custom configuration from the logging backend. + */ + void cleanup(); + + void enableLoggingToStandardOutput(); + + void disableLoggingToStandardOutput(); +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/PureLogWriter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/PureLogWriter.java index c1b32ec7a418..b24d8f4a65bb 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/PureLogWriter.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/PureLogWriter.java @@ -14,7 +14,6 @@ */ package org.apache.geode.internal.logging; - import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -25,10 +24,11 @@ import java.util.Date; import org.apache.geode.GemFireIOException; +import org.apache.geode.LogWriter; import org.apache.geode.i18n.StringId; /** - * Implementation of {@link org.apache.geode.LogWriter} that will write to a local stream + * Implementation of {@link LogWriter} that will write to a local stream * and only use pure java features. */ public class PureLogWriter extends LogWriterImpl { @@ -113,11 +113,6 @@ public void setLevel(final int level) { this.level = level; } - @Override - public void setLogWriterLevel(final int logWriterLevel) { - setLevel(logWriterLevel); - } - protected String getThreadName() { return Thread.currentThread().getName(); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/SecurityLogWriter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/SecurityLogWriter.java index 56a43d678a42..850c2a8bacea 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/SecurityLogWriter.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/SecurityLogWriter.java @@ -36,7 +36,7 @@ public class SecurityLogWriter extends LogWriterImpl implements InternalLogWrite private final int logLevel; private final InternalLogWriter realLogWriter; - public SecurityLogWriter(int level, InternalLogWriter logWriter) { + public SecurityLogWriter(final int level, final InternalLogWriter logWriter) { logLevel = level; realLogWriter = logWriter; } @@ -46,11 +46,6 @@ public int getLogWriterLevel() { return logLevel; } - @Override - public void setLogWriterLevel(int logWriterLevel) { - throw new UnsupportedOperationException("Unable to change log level after creation"); - } - @Override public boolean isSecure() { return true; @@ -62,7 +57,8 @@ public String getConnectionName() { } @Override - public void put(int messageLevel, StringId messageId, Object[] parameters, Throwable throwable) { + public void put(final int messageLevel, final StringId messageId, final Object[] parameters, + final Throwable throwable) { put(messageLevel, messageId.toLocalizedString(parameters), throwable); } @@ -71,7 +67,7 @@ public void put(int messageLevel, StringId messageId, Object[] parameters, Throw * security related log-lines. */ @Override - public void put(int messageLevel, String message, Throwable throwable) { + public void put(final int messageLevel, final String message, final Throwable throwable) { realLogWriter.put(messageLevel, new StringBuilder(SECURITY_PREFIX) .append(levelToString(messageLevel)).append(" ").append(message).toString(), throwable); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/SessionContext.java b/geode-core/src/main/java/org/apache/geode/internal/logging/SessionContext.java new file mode 100644 index 000000000000..0a3d8c2c098e --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/SessionContext.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +public interface SessionContext { + + State getState(); + + LogConfigSupplier getLogConfigSupplier(); + + enum State { + CREATED, + STARTED, + STOPPED; + + State changeTo(final State newState) { + switch (newState) { + case CREATED: + if (this != STOPPED) { + throw new IllegalStateException("Session must not exist before creating"); + } + return CREATED; + case STARTED: + if (this != CREATED) { + throw new IllegalStateException("Session must be created before starting"); + } + return STARTED; + case STOPPED: + if (this != STARTED) { + throw new IllegalStateException("Session must be started before stopping"); + } + } + return STOPPED; + } + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Configurator.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Configurator.java deleted file mode 100755 index 96c60fc7ec81..000000000000 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Configurator.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.logging.log4j; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.AppenderRef; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.filter.AbstractFilterable; - -import org.apache.geode.internal.logging.LogService; - -/** - * Utility methods to programmatically alter the configuration of Log4J2. Used by LogService and - * tests. - */ -public class Configurator { - - public static void shutdown() { - final LoggerContext context = - ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()).getContext(); - context.stop(); - org.apache.logging.log4j.core.config.Configurator.shutdown(context); - } - - public static void setLevel(String name, Level level) { - LoggerContext context = (LoggerContext) LogManager.getContext(false); - LoggerConfig logConfig = getLoggerConfig(name); - - logConfig.setLevel(level); - context.updateLoggers(); - - if (level.isLessSpecificThan(Level.DEBUG)) { - LogService.configureFastLoggerDelegating(); - } - } - - public static Level getLevel(String name) { - LoggerConfig logConfig = getOrCreateLoggerConfig(name); - return logConfig.getLevel(); - } - - public static LoggerConfig getOrCreateLoggerConfig(String name) { - LoggerContext context = (LoggerContext) LogManager.getContext(false); - Configuration config = context.getConfiguration(); - LoggerConfig logConfig = config.getLoggerConfig(name); - boolean update = false; - if (!logConfig.getName().equals(name)) { - List appenderRefs = logConfig.getAppenderRefs(); - Map properties = logConfig.getProperties(); - Set props = properties == null ? null : properties.keySet(); - logConfig = LoggerConfig.createLogger(String.valueOf(logConfig.isAdditive()), - logConfig.getLevel(), name, String.valueOf(logConfig.isIncludeLocation()), - appenderRefs == null ? null : appenderRefs.toArray(new AppenderRef[appenderRefs.size()]), - props == null ? null : props.toArray(new Property[props.size()]), config, null); - config.addLogger(name, logConfig); - update = true; - } - if (update) { - context.updateLoggers(); - } - return logConfig; - } - - public static LoggerConfig getOrCreateLoggerConfig(String name, boolean additive, - boolean forceAdditivity) { - LoggerContext context = (LoggerContext) LogManager.getContext(false); - Configuration config = context.getConfiguration(); - LoggerConfig logConfig = config.getLoggerConfig(name); - boolean update = false; - if (!logConfig.getName().equals(name)) { - List appenderRefs = logConfig.getAppenderRefs(); - Map properties = logConfig.getProperties(); - Set props = properties == null ? null : properties.keySet(); - logConfig = LoggerConfig.createLogger(String.valueOf(additive), logConfig.getLevel(), name, - String.valueOf(logConfig.isIncludeLocation()), - appenderRefs == null ? null : appenderRefs.toArray(new AppenderRef[appenderRefs.size()]), - props == null ? null : props.toArray(new Property[props.size()]), config, null); - config.addLogger(name, logConfig); - update = true; - } - if (forceAdditivity && logConfig.isAdditive() != additive) { - logConfig.setAdditive(additive); - update = true; - } - if (update) { - context.updateLoggers(); - } - return logConfig; - } - - public static LoggerConfig getLoggerConfig(final String name) { - LoggerContext context = (LoggerContext) LogManager.getContext(false); - Configuration config = context.getConfiguration(); - LoggerConfig logConfig = config.getLoggerConfig(name); - if (!logConfig.getName().equals(name)) { - throw new IllegalStateException("LoggerConfig does not exist for " + name); - } - return logConfig; - } - - public static boolean hasContextWideFilter(final Configuration config) { - return config.hasFilter(); - } - - public static String getConfigurationSourceLocation(final Configuration config) { - return config.getConfigurationSource().getLocation(); - } - - public static boolean hasAppenderFilter(final Configuration config) { - for (Appender appender : config.getAppenders().values()) { - if (appender instanceof AbstractFilterable) { - if (((AbstractFilterable) appender).hasFilter()) { - return true; - } - } - } - return false; - } - - public static boolean hasDebugOrLower(final Configuration config) { - for (LoggerConfig loggerConfig : config.getLoggers().values()) { - boolean isDebugOrLower = loggerConfig.getLevel().isLessSpecificThan(Level.DEBUG); - if (isDebugOrLower) { - return true; - } - } - return false; - } - - public static boolean hasLoggerFilter(final Configuration config) { - for (LoggerConfig loggerConfig : config.getLoggers().values()) { - boolean isRoot = loggerConfig.getName().equals(""); - boolean isGemFire = loggerConfig.getName().startsWith(LogService.BASE_LOGGER_NAME); - boolean hasFilter = loggerConfig.hasFilter(); - boolean isGemFireVerboseFilter = - hasFilter && (LogService.GEODE_VERBOSE_FILTER.equals(loggerConfig.getFilter().toString()) - || LogService.GEMFIRE_VERBOSE_FILTER.equals(loggerConfig.getFilter().toString())); - - if (isRoot || isGemFire) { - // check for Logger Filter - if (hasFilter && !isGemFireVerboseFilter) { - return true; - } - } - } - return false; - } - - public static boolean hasAppenderRefFilter(final Configuration config) { - for (LoggerConfig loggerConfig : config.getLoggers().values()) { - boolean isRoot = loggerConfig.getName().equals(""); - boolean isGemFire = loggerConfig.getName().startsWith(LogService.BASE_LOGGER_NAME); - - if (isRoot || isGemFire) { - // check for AppenderRef Filter - for (AppenderRef appenderRef : loggerConfig.getAppenderRefs()) { - if (appenderRef.getFilter() != null) { - return true; - } - } - } - } - return false; - } -} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppender.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppender.java new file mode 100644 index 000000000000..7d785872fbe9 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/GeodeConsoleAppender.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.internal.logging.log4j; + +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Core; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender; +import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.appender.ConsoleAppender.Target; +import org.apache.logging.log4j.core.appender.ManagerFactory; +import org.apache.logging.log4j.core.appender.OutputStreamManager; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; +import org.apache.logging.log4j.core.util.NullOutputStream; + +import org.apache.geode.annotations.TestingOnly; + +/** + * Wraps {@link ConsoleAppender} with additions defined in {@link PausableAppender} and + * {@link DebuggableAppender}. + */ +@Plugin(name = GeodeConsoleAppender.PLUGIN_NAME, category = Core.CATEGORY_NAME, + elementType = Appender.ELEMENT_TYPE, printObject = true) +@SuppressWarnings("unused") +public class GeodeConsoleAppender extends AbstractOutputStreamAppender + implements PausableAppender, DebuggableAppender { + + public static final String PLUGIN_NAME = "GeodeConsole"; + + private static final boolean START_PAUSED_BY_DEFAULT = false; + private static final Target DEFAULT_TARGET = Target.SYSTEM_OUT; + private static final AtomicInteger COUNT = new AtomicInteger(); + private static final GeodeConsoleManagerFactory MANAGER_FACTORY = + new GeodeConsoleManagerFactory(); + + private final ConsoleAppender delegate; + private final boolean debug; + private final List events; + + private volatile boolean paused; + + protected GeodeConsoleAppender(final String name, + final Layout layout, + final Filter filter, + final OutputStreamManager manager, + final ConsoleAppender delegate) { + this(name, layout, filter, manager, true, START_PAUSED_BY_DEFAULT, false, delegate); + } + + protected GeodeConsoleAppender(final String name, + final Layout layout, + final Filter filter, + final OutputStreamManager manager, + final boolean ignoreExceptions, + final boolean startPaused, + final boolean debug, + final ConsoleAppender delegate) { + super(name, layout, filter, ignoreExceptions, true, manager); + this.delegate = delegate; + this.debug = debug; + if (debug) { + events = Collections.synchronizedList(new ArrayList<>()); + } else { + events = Collections.emptyList(); + } + paused = startPaused; + } + + public static GeodeConsoleAppender createDefaultAppenderForLayout( + final Layout layout) { + // this method cannot use the builder class without introducing an infinite loop due to + // DefaultConfiguration + return new GeodeConsoleAppender(PLUGIN_NAME + "-" + COUNT.incrementAndGet(), layout, null, + getDefaultManager(DEFAULT_TARGET, false, false, layout), true, false, false, + ConsoleAppender.createDefaultAppenderForLayout(layout)); + } + + @PluginBuilderFactory + public static > B newBuilder() { + return new Builder().asBuilder(); + } + + /** + * Builds GeodeConsoleAppender instances. + * + * @param The type to build + */ + public static class Builder> extends AbstractOutputStreamAppender.Builder + implements org.apache.logging.log4j.core.util.Builder { + + @PluginBuilderAttribute + @Required + private Target target = DEFAULT_TARGET; + + @PluginBuilderAttribute + private boolean follow; + + @PluginBuilderAttribute + private boolean direct; + + @PluginBuilderAttribute + private boolean startPaused = START_PAUSED_BY_DEFAULT; + + @PluginBuilderAttribute + private boolean debug; + + public B setTarget(final Target aTarget) { + target = aTarget; + return asBuilder(); + } + + public B setFollow(final boolean shouldFollow) { + follow = shouldFollow; + return asBuilder(); + } + + public B setDirect(final boolean shouldDirect) { + direct = shouldDirect; + return asBuilder(); + } + + public B setStartPaused(final boolean shouldStartPaused) { + startPaused = shouldStartPaused; + return asBuilder(); + } + + public boolean isStartPaused() { + return debug; + } + + public B setDebug(final boolean shouldDebug) { + debug = shouldDebug; + return asBuilder(); + } + + public boolean isDebug() { + return debug; + } + + @Override + public GeodeConsoleAppender build() { + ConsoleAppender.Builder delegate = new ConsoleAppender.Builder(); + // AbstractAppender + delegate.withFilter(getFilter()); + delegate.withName(getName() + "_DELEGATE"); + delegate.withIgnoreExceptions(isIgnoreExceptions()); + delegate.withLayout(getLayout()); + // AbstractOutputStreamAppender + delegate.withImmediateFlush(isImmediateFlush()); + delegate.withBufferedIo(isBufferedIo()); + delegate.withBufferSize(getBufferSize()); + // ConsoleAppender + delegate.setTarget(target); + delegate.setFollow(follow); + delegate.setDirect(direct); + + Layout layout = getOrCreateLayout(target.getDefaultCharset()); + return new GeodeConsoleAppender(getName(), layout, + getFilter(), getManager(target, follow, direct, layout), + isIgnoreExceptions(), startPaused, debug, delegate.build()); + } + } + + @Override + public void append(final LogEvent event) { + if (isPaused()) { + return; + } + delegate.append(event); + if (debug) { + events.add(event); + } + } + + @Override + public void start() { + LOGGER.info("Starting {}.", this); + delegate.start(); + super.start(); + } + + @Override + public void stop() { + LOGGER.info("Stopping {}.", this); + delegate.stop(); + super.stop(); + } + + @Override + public void pause() { + LOGGER.debug("Pausing {}.", this); + paused = true; + } + + @Override + public void resume() { + LOGGER.debug("Resuming {}.", this); + paused = false; + } + + @Override + public boolean isPaused() { + return paused; + } + + @Override + public void clearLogEvents() { + events.clear(); + } + + @Override + public List getLogEvents() { + return events; + } + + @Override + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()) + ":" + getName() + + " {paused=" + paused + ", debug=" + debug + ", delegate=" + delegate + "}"; + } + + @TestingOnly + ConsoleAppender getDelegate() { + return delegate; + } + + private static OutputStreamManager getDefaultManager(final Target target, final boolean follow, + final boolean direct, final Layout layout) { + + OutputStream os = NullOutputStream.getInstance(); + String managerName = target.name() + '.' + follow + '.' + direct + "-" + COUNT.get(); + return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), + MANAGER_FACTORY); + } + + private static OutputStreamManager getManager(final Target target, final boolean follow, + final boolean direct, final Layout layout) { + OutputStream os = NullOutputStream.getInstance(); + String managerName = "null." + target.name() + '.' + follow + '.' + direct; + return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), + MANAGER_FACTORY); + } + + private static class FactoryData { + private final OutputStream os; + private final String name; + private final Layout layout; + + public FactoryData(final OutputStream os, final String type, + final Layout layout) { + this.os = os; + name = type; + this.layout = layout; + } + } + + private static class AccessibleOutputStreamManager extends OutputStreamManager { + + protected AccessibleOutputStreamManager(final OutputStream os, final String streamName, + final Layout layout, final boolean writeHeader) { + super(os, streamName, layout, writeHeader); + } + + protected AccessibleOutputStreamManager(final OutputStream os, final String streamName, + final Layout layout, + final boolean writeHeader, final int bufferSize) { + super(os, streamName, layout, writeHeader, bufferSize); + } + } + + private static class GeodeConsoleManagerFactory implements + ManagerFactory { + + @Override + public OutputStreamManager createManager(final String name, final FactoryData data) { + return new AccessibleOutputStreamManager(data.os, data.name, data.layout, true); + } + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Log4jAgent.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Log4jAgent.java new file mode 100644 index 000000000000..776e2c3a44b8 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/Log4jAgent.java @@ -0,0 +1,300 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.internal.logging.Configuration.GEODE_LOGGER_PREFIX; +import static org.apache.geode.internal.logging.Configuration.MAIN_LOGGER_NAME; +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; +import static org.apache.geode.internal.logging.log4j.LogWriterLevelConverter.toLevel; + +import java.util.Collection; +import java.util.HashSet; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.AppenderRef; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.filter.AbstractFilterable; +import org.apache.logging.log4j.core.lookup.StrLookup; +import org.apache.logging.log4j.core.lookup.StrSubstitutor; + +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope; +import org.apache.geode.internal.logging.LogConfig; +import org.apache.geode.internal.logging.LogWriterLevel; +import org.apache.geode.internal.logging.ProviderAgent; + +/** + * Log4J 2 implementation of {@link ProviderAgent}. + */ +public class Log4jAgent implements ProviderAgent { + + static final String GEODE_CONSOLE_APPENDER_NAME = "STDOUT"; + static final String LOGWRITER_APPENDER_NAME = "LOGWRITER"; + static final String SECURITY_LOGWRITER_APPENDER_NAME = "SECURITYLOGWRITER"; + static final String ALERT_APPENDER_NAME = "ALERT"; + + private static final String GEODE_VERBOSE_FILTER = "{GEODE_VERBOSE}"; + private static final String GEMFIRE_VERBOSE_FILTER = "{GEMFIRE_VERBOSE}"; + + /** + * Name of variable that is set to "true" in log4j2.xml to indicate that it is the default geode + * config xml. + */ + private static final String GEODE_DEFAULT_PROPERTY = "geode-default"; + + public static void updateLogLevel(final Level level, final LoggerConfig... loggerConfigs) { + for (LoggerConfig loggerConfig : loggerConfigs) { + loggerConfig.setLevel(level); + } + getRootLoggerContext().updateLoggers(); + } + + public static LoggerConfig getLoggerConfig(final org.apache.logging.log4j.Logger logger) { + return ((Logger) logger).get(); + } + + public static String getConfigurationInfo() { + return getConfiguration().getConfigurationSource().toString(); + } + + static boolean isUsingGemFireDefaultConfig() { + Configuration configuration = getConfiguration(); + + StrSubstitutor strSubstitutor = configuration.getStrSubstitutor(); + StrLookup variableResolver = strSubstitutor.getVariableResolver(); + + String value = variableResolver.lookup(GEODE_DEFAULT_PROPERTY); + + return "true".equals(value); + } + + private static LoggerContext getRootLoggerContext() { + return ((Logger) LogManager.getRootLogger()).getContext(); + } + + private static Configuration getConfiguration() { + return getRootLoggerContext().getConfiguration(); + } + + private boolean configuredSecurityAppenders; + + public Log4jAgent() { + // nothing + } + + @Override + public void configure(final LogConfig logConfig, final LogLevelUpdateOccurs logLevelUpdateOccurs, + final LogLevelUpdateScope logLevelUpdateScope) { + if (shouldUpdateLogLevels(logLevelUpdateOccurs)) { + Level loggerLevel = toLevel(LogWriterLevel.find(logConfig.getLogLevel())); + updateLogLevel(loggerLevel, getLoggerConfig(MAIN_LOGGER_NAME)); + + Level securityLoggerLevel = toLevel(LogWriterLevel.find(logConfig.getSecurityLogLevel())); + updateLogLevel(securityLoggerLevel, getLoggerConfig(SECURITY_LOGGER_NAME)); + + if (!LogConfig.hasSecurityLogFile(logConfig)) { + configuredSecurityAppenders = + configureSecurityAppenders(SECURITY_LOGGER_NAME, securityLoggerLevel); + } + } + + if (shouldUpdateLogLevels(logLevelUpdateOccurs)) { + updateLogLevel(logConfig, logLevelUpdateScope); + } + + configureFastLoggerDelegating(); + } + + private boolean shouldUpdateLogLevels(final LogLevelUpdateOccurs logLevelUpdateOccurs) { + return logLevelUpdateOccurs.always() || + logLevelUpdateOccurs.onlyWhenUsingDefaultConfig() && isUsingGemFireDefaultConfig(); + } + + @Override + public void cleanup() { + if (configuredSecurityAppenders) { + Configuration log4jConfiguration = getRootLoggerContext().getConfiguration(); + LoggerConfig loggerConfig = log4jConfiguration.getLoggerConfig(SECURITY_LOGGER_NAME); + + loggerConfig.removeAppender(GEODE_CONSOLE_APPENDER_NAME); + loggerConfig.removeAppender(LOGWRITER_APPENDER_NAME); + + loggerConfig.setAdditive(false); + getRootLoggerContext().updateLoggers(); + } + } + + @Override + public void enableLoggingToStandardOutput() { + Configuration log4jConfiguration = getRootLoggerContext().getConfiguration(); + Appender appender = log4jConfiguration.getAppender(GEODE_CONSOLE_APPENDER_NAME); + if (GeodeConsoleAppender.class.isInstance(appender)) { + GeodeConsoleAppender geodeConsoleAppender = (GeodeConsoleAppender) appender; + geodeConsoleAppender.resume(); + } + } + + @Override + public void disableLoggingToStandardOutput() { + Configuration log4jConfiguration = getRootLoggerContext().getConfiguration(); + Appender appender = log4jConfiguration.getAppender(GEODE_CONSOLE_APPENDER_NAME); + if (GeodeConsoleAppender.class.isInstance(appender)) { + GeodeConsoleAppender geodeConsoleAppender = (GeodeConsoleAppender) appender; + geodeConsoleAppender.pause(); + } + } + + private void updateLogLevel(final LogConfig logConfig, + final LogLevelUpdateScope logLevelUpdateScope) { + Level level = toLevel(LogWriterLevel.find(logConfig.getLogLevel())); + + Configuration configuration = + getRootLoggerContext().getConfiguration(); + + Collection loggerConfigs = new HashSet<>(); + + for (LoggerConfig loggerConfig : configuration.getLoggers().values()) { + switch (logLevelUpdateScope) { + case ALL_LOGGERS: + loggerConfigs.add(loggerConfig); + break; + case GEODE_AND_SECURITY_LOGGERS: + if (loggerConfig.getName().startsWith(GEODE_LOGGER_PREFIX)) { + loggerConfigs.add(loggerConfig); + } + break; + case GEODE_AND_APPLICATION_LOGGERS: + if (!loggerConfig.getName().equals(SECURITY_LOGGER_NAME)) { + loggerConfigs.add(loggerConfig); + } + break; + case GEODE_LOGGERS: + if (loggerConfig.getName().startsWith(GEODE_LOGGER_PREFIX) && + !loggerConfig.getName().equals(SECURITY_LOGGER_NAME)) { + loggerConfigs.add(loggerConfig); + } + } + } + + updateLogLevel(level, loggerConfigs.toArray(new LoggerConfig[0])); + } + + private boolean configureSecurityAppenders(final String name, final Level level) { + Configuration log4jConfiguration = getRootLoggerContext().getConfiguration(); + LoggerConfig loggerConfig = log4jConfiguration.getLoggerConfig(name); + + if (!loggerConfig.getName().equals(SECURITY_LOGGER_NAME)) { + return false; + } + + Appender stdoutAppender = log4jConfiguration.getAppender(GEODE_CONSOLE_APPENDER_NAME); + Appender mainLogWriterAppender = log4jConfiguration.getAppender(LOGWRITER_APPENDER_NAME); + + if (stdoutAppender != null) { + loggerConfig.addAppender(stdoutAppender, level, null); + } + if (mainLogWriterAppender != null) { + loggerConfig.addAppender(mainLogWriterAppender, level, null); + } + + loggerConfig.setAdditive(true); + + getRootLoggerContext().updateLoggers(); + + return true; + } + + private LoggerConfig getLoggerConfig(final String name) { + Configuration log4jConfiguration = getRootLoggerContext().getConfiguration(); + return log4jConfiguration.getLoggerConfig(name); + } + + private void configureFastLoggerDelegating() { + Configuration configuration = getConfiguration(); + if (hasContextWideFilter(configuration) || hasAppenderFilter(configuration) + || hasDebugOrLower(configuration) || hasLoggerFilter(configuration) + || hasAppenderRefFilter(configuration)) { + FastLogger.setDelegating(true); + } else { + FastLogger.setDelegating(false); + } + } + + private boolean hasContextWideFilter(final Configuration config) { + return config.hasFilter(); + } + + private boolean hasAppenderFilter(final Configuration config) { + for (Appender appender : config.getAppenders().values()) { + if (appender instanceof AbstractFilterable) { + if (((AbstractFilterable) appender).hasFilter()) { + return true; + } + } + } + return false; + } + + private boolean hasDebugOrLower(final Configuration config) { + for (LoggerConfig loggerConfig : config.getLoggers().values()) { + boolean isDebugOrLower = loggerConfig.getLevel().isLessSpecificThan(Level.DEBUG); + if (isDebugOrLower) { + return true; + } + } + return false; + } + + private boolean hasLoggerFilter(final Configuration config) { + for (LoggerConfig loggerConfig : config.getLoggers().values()) { + boolean isRoot = loggerConfig.getName().equals(""); + boolean isGemFire = loggerConfig.getName().startsWith(GEODE_LOGGER_PREFIX); + boolean hasFilter = loggerConfig.hasFilter(); + boolean isGemFireVerboseFilter = + hasFilter && (GEODE_VERBOSE_FILTER.equals(loggerConfig.getFilter().toString()) + || GEMFIRE_VERBOSE_FILTER.equals(loggerConfig.getFilter().toString())); + + if (isRoot || isGemFire) { + // check for Logger Filter + if (hasFilter && !isGemFireVerboseFilter) { + return true; + } + } + } + return false; + } + + private boolean hasAppenderRefFilter(final Configuration config) { + for (LoggerConfig loggerConfig : config.getLoggers().values()) { + boolean isRoot = loggerConfig.getName().equals(""); + boolean isGemFire = loggerConfig.getName().startsWith(GEODE_LOGGER_PREFIX); + + if (isRoot || isGemFire) { + // check for AppenderRef Filter + for (AppenderRef appenderRef : loggerConfig.getAppenderRefs()) { + if (appenderRef.getFilter() != null) { + return true; + } + } + } + } + return false; + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogLevel.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogLevel.java index b6e96bd28c82..45c0ebee4890 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogLevel.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogLevel.java @@ -21,148 +21,106 @@ import org.apache.logging.log4j.Level; -import org.apache.geode.internal.logging.InternalLogWriter; +import org.apache.geode.internal.logging.LogWriterLevel; /** - * This class provides utility methods to hold all valid log4j levels and legacy geode log levels - * and the mapping between the two level hierarchy. + * Provides lookup of any string representation of a logging level to Log4J2 {@code Level} or + * {@code LogWriterLevel} int value. */ public class LogLevel { - private static Map LEVELS = new HashMap<>(); - private static Map S2I = new HashMap<>(); - private static Map I2S = new HashMap<>(); + private static final Map ANY_NAME_TO_LEVEL = new HashMap<>(); + private static final Map ANY_NAME_TO_LOGWRITERLEVEL = new HashMap<>(); static { - // logwriter int level to log4j level string - I2S.put(InternalLogWriter.NONE_LEVEL, "OFF"); - I2S.put(InternalLogWriter.SEVERE_LEVEL, "FATAL"); - I2S.put(InternalLogWriter.ERROR_LEVEL, "ERROR"); - I2S.put(InternalLogWriter.WARNING_LEVEL, "WARN"); - I2S.put(InternalLogWriter.INFO_LEVEL, "INFO"); - I2S.put(InternalLogWriter.CONFIG_LEVEL, "INFO"); - I2S.put(InternalLogWriter.FINE_LEVEL, "DEBUG"); - I2S.put(InternalLogWriter.FINER_LEVEL, "TRACE"); - I2S.put(InternalLogWriter.FINEST_LEVEL, "TRACE"); - I2S.put(InternalLogWriter.ALL_LEVEL, "ALL"); - - // logwriter strings to integer - S2I.put("NONE", InternalLogWriter.NONE_LEVEL); - S2I.put("SEVERE", InternalLogWriter.SEVERE_LEVEL); - S2I.put("ERROR", InternalLogWriter.ERROR_LEVEL); - S2I.put("WARNING", InternalLogWriter.WARNING_LEVEL); - S2I.put("INFO", InternalLogWriter.INFO_LEVEL); - S2I.put("CONFIG", InternalLogWriter.CONFIG_LEVEL); - S2I.put("FINE", InternalLogWriter.FINE_LEVEL); - S2I.put("FINER", InternalLogWriter.FINER_LEVEL); - S2I.put("FINEST", InternalLogWriter.FINEST_LEVEL); - S2I.put("ALL", InternalLogWriter.ALL_LEVEL); - - // additional log4j strings to integer - S2I.put("OFF", InternalLogWriter.NONE_LEVEL); - S2I.put("FATAL", InternalLogWriter.SEVERE_LEVEL); - S2I.put("WARN", InternalLogWriter.WARNING_LEVEL); - S2I.put("DEBUG", InternalLogWriter.FINE_LEVEL); - S2I.put("TRACE", InternalLogWriter.FINEST_LEVEL); + // LogWriterLevel name to LogWriterLevel + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.NONE.name(), LogWriterLevel.NONE); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.SEVERE.name(), LogWriterLevel.SEVERE); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.ERROR.name(), LogWriterLevel.ERROR); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.WARNING.name(), LogWriterLevel.WARNING); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.INFO.name(), LogWriterLevel.INFO); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.CONFIG.name(), LogWriterLevel.CONFIG); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.FINE.name(), LogWriterLevel.FINE); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.FINER.name(), LogWriterLevel.FINER); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.FINEST.name(), LogWriterLevel.FINEST); + ANY_NAME_TO_LOGWRITERLEVEL.put(LogWriterLevel.ALL.name(), LogWriterLevel.ALL); + + // additional Log4J2 names to LogWriterLevel + ANY_NAME_TO_LOGWRITERLEVEL.put(Level.OFF.name(), LogWriterLevel.NONE); + ANY_NAME_TO_LOGWRITERLEVEL.put(Level.FATAL.name(), LogWriterLevel.SEVERE); + ANY_NAME_TO_LOGWRITERLEVEL.put(Level.WARN.name(), LogWriterLevel.WARNING); + ANY_NAME_TO_LOGWRITERLEVEL.put(Level.DEBUG.name(), LogWriterLevel.FINE); + ANY_NAME_TO_LOGWRITERLEVEL.put(Level.TRACE.name(), LogWriterLevel.FINEST); // put all the log4j levels in the map first Arrays.stream(Level.values()).forEach(level -> { - LEVELS.put(level.name(), level); + ANY_NAME_TO_LEVEL.put(level.name(), level); }); // map all the other logwriter level to log4j levels - LEVELS.put("SEVERE", getLog4jLevel(InternalLogWriter.SEVERE_LEVEL)); - LEVELS.put("WARNING", getLog4jLevel(InternalLogWriter.WARNING_LEVEL)); - LEVELS.put("CONFIG", getLog4jLevel(InternalLogWriter.CONFIG_LEVEL)); - LEVELS.put("FINE", getLog4jLevel(InternalLogWriter.FINE_LEVEL)); - LEVELS.put("FINER", getLog4jLevel(InternalLogWriter.FINER_LEVEL)); - LEVELS.put("FINEST", getLog4jLevel(InternalLogWriter.FINEST_LEVEL)); - LEVELS.put("NONE", getLog4jLevel(InternalLogWriter.NONE_LEVEL)); + ANY_NAME_TO_LEVEL.put(LogWriterLevel.SEVERE.name(), + LogWriterLevelConverter.toLevel(LogWriterLevel.find(LogWriterLevel.SEVERE.intLevel()))); + ANY_NAME_TO_LEVEL.put(LogWriterLevel.WARNING.name(), + LogWriterLevelConverter.toLevel(LogWriterLevel.find(LogWriterLevel.WARNING.intLevel()))); + ANY_NAME_TO_LEVEL.put(LogWriterLevel.CONFIG.name(), + LogWriterLevelConverter.toLevel(LogWriterLevel.find(LogWriterLevel.CONFIG.intLevel()))); + ANY_NAME_TO_LEVEL.put(LogWriterLevel.FINE.name(), + LogWriterLevelConverter.toLevel(LogWriterLevel.find(LogWriterLevel.FINE.intLevel()))); + ANY_NAME_TO_LEVEL.put(LogWriterLevel.FINER.name(), + LogWriterLevelConverter.toLevel(LogWriterLevel.find(LogWriterLevel.FINER.intLevel()))); + ANY_NAME_TO_LEVEL.put(LogWriterLevel.FINEST.name(), + LogWriterLevelConverter.toLevel(LogWriterLevel.find(LogWriterLevel.FINEST.intLevel()))); + ANY_NAME_TO_LEVEL.put(LogWriterLevel.NONE.name(), + LogWriterLevelConverter.toLevel(LogWriterLevel.find(LogWriterLevel.NONE.intLevel()))); } /** - * resolve the log4j level from any log statement in the log file. + * Convert any string representation of a logging level to a Log4J2 {@code Level}. Returns + * {@code Level.OFF} if invalid. * - * @param level either legacy level string or log4j level string - * @return log4j level. Level.OFF is invalid string + *

+ * resolve the log4j level from any log statement in the log file. */ - public static Level resolveLevel(final String level) { - Level log4jLevel = LEVELS.get(level.toUpperCase()); + public static Level resolveLevel(final String anyLevelName) { + Level log4jLevel = ANY_NAME_TO_LEVEL.get(anyLevelName.toUpperCase()); // make sure any unrecognizable log level is assigned a most specific level return log4jLevel == null ? Level.OFF : log4jLevel; } /** - * get Log4j Level from either legacy level string or log4j level string - * - * @param level either legacy level string or log4j level string - * @return log4j level. null if invalid level string - */ - public static Level getLevel(String level) { - return LEVELS.get(level.toUpperCase()); - } - - /** - * convert log4j level to logwriter code + * Convert any string representation of a logging level to a Log4J2 {@code Level}. Returns null + * if invalid. * - * @param log4jLevel log4j level object - * @return legacy logwriter code + *

+ * get Log4j Level from either legacy level string or log4j level string */ - public static int getLogWriterLevel(final Level log4jLevel) { - Integer result = S2I.get(log4jLevel.name()); - - if (result == null) - throw new IllegalArgumentException("Unknown Log4J level [" + log4jLevel + "]."); - - return result; + public static Level getLevel(String anyLevelName) { + return ANY_NAME_TO_LEVEL.get(anyLevelName.toUpperCase()); } /** - * convert legacy logwriter code to log4j level + * Convert any string representation of a logging level to a {@code LogWriterLevel} int value. * - * @param logWriterLevel logwriter code - * @return log4j level - */ - public static Level getLog4jLevel(final int logWriterLevel) { - String log4jLevel = I2S.get(logWriterLevel); - if (log4jLevel == null) - throw new IllegalArgumentException("Unknown LogWriter level [" + logWriterLevel + "]."); - return Level.getLevel(log4jLevel); - } - - /** + *

* convert a string to logwriter code, either log4j level or logwriter string, or a level-xxx - * - * @param levelName a string of level name - * @return logwriter code */ - public static int getLogWriterLevel(final String levelName) { - if (levelName == null) { + public static int getLogWriterLevel(final String anyLevelName) { + if (anyLevelName == null) { throw new IllegalArgumentException("LevelName cannot be null"); } - Integer level = S2I.get(levelName.toUpperCase()); - if (level != null) - return level; + if (ANY_NAME_TO_LOGWRITERLEVEL.get(anyLevelName.toUpperCase()) != null) { + return ANY_NAME_TO_LOGWRITERLEVEL.get(anyLevelName.toUpperCase()).intLevel(); + } - if (levelName.startsWith("level-")) { - String levelValue = levelName.substring("level-".length()); + if (anyLevelName.toLowerCase().startsWith("level-")) { + String levelValue = anyLevelName.toLowerCase().substring("level-".length()); return Integer.parseInt(levelValue); } String values = Arrays.stream(Level.values()).sorted().map(Level::name).collect(Collectors.joining(", ")); throw new IllegalArgumentException( - "Unknown log-level \"" + levelName + "\". Valid levels are: " + values + "."); - } - - /** - * convert a legacy logwriter code to log4j level string - * - * @param logWriterLevel integer code - * @return log4j level string - */ - public static String getLog4jLevelAsString(final int logWriterLevel) { - return getLog4jLevel(logWriterLevel).name().toLowerCase(); + "Unknown log-level \"" + anyLevelName + "\". Valid levels are: " + values + "."); } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppender.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppender.java index bbb4937ff4fd..cd2301d4cff9 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppender.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppender.java @@ -14,203 +14,358 @@ */ package org.apache.geode.internal.logging.log4j; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; +import static java.lang.Boolean.FALSE; -import org.apache.logging.log4j.Level; +import java.io.Serializable; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Core; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.AbstractAppender; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; import org.apache.geode.internal.logging.LogConfig; -import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.LogConfigListener; +import org.apache.geode.internal.logging.LogConfigSupplier; +import org.apache.geode.internal.logging.LogFile; +import org.apache.geode.internal.logging.LoggingSessionListener; +import org.apache.geode.internal.logging.LoggingSessionListeners; import org.apache.geode.internal.logging.ManagerLogWriter; -import org.apache.geode.internal.logging.PureLogWriter; +import org.apache.geode.internal.logging.ManagerLogWriterFactory; +import org.apache.geode.internal.logging.ManagerLogWriterFactory.LogFileRolloverDetails; +import org.apache.geode.internal.logging.NullLogWriter; +import org.apache.geode.internal.logging.SessionContext; +import org.apache.geode.internal.statistics.StatisticsConfig; -/** - * A Log4j Appender which will copy all output to a LogWriter. - * - */ -public class LogWriterAppender extends AbstractAppender implements PropertyChangeListener { - private static final org.apache.logging.log4j.Logger logger = LogService.getLogger(); +@Plugin(name = LogWriterAppender.PLUGIN_NAME, category = Core.CATEGORY_NAME, + elementType = Appender.ELEMENT_TYPE, printObject = true) +@SuppressWarnings("unused") +public class LogWriterAppender extends AbstractAppender + implements PausableAppender, DebuggableAppender, LoggingSessionListener, LogConfigListener { - /** Is this thread in the process of appending? */ - private static final ThreadLocal appending = new ThreadLocal() { - @Override - protected Boolean initialValue() { - return Boolean.FALSE; - } - }; + public static final String PLUGIN_NAME = "GeodeLogWriter"; - private final PureLogWriter logWriter; - private final FileOutputStream fos; // TODO:LOG:CLEANUP: why do we track this outside - // ManagerLogWriter? doesn't rolling invalidate it? + private static final boolean START_PAUSED_BY_DEFAULT = true; - private final AppenderContext[] appenderContexts; - private final String appenderName; - private final String logWriterLoggerName; + /** + * True if this thread is in the process of appending. + */ + private static final ThreadLocal APPENDING = ThreadLocal.withInitial(() -> FALSE); - private LogWriterAppender(final AppenderContext[] appenderContexts, final String name, - final PureLogWriter logWriter, final FileOutputStream fos) { - super(LogWriterAppender.class.getName() + "-" + name, null, - PatternLayout.createDefaultLayout()); - this.appenderContexts = appenderContexts; - this.appenderName = LogWriterAppender.class.getName() + "-" + name; - this.logWriterLoggerName = name; - this.logWriter = logWriter; - this.fos = fos; - } + private final String eagerMemberName; + private volatile String lazyMemberName; + private final MemberNameSupplier memberNameSupplier; /** - * Used by LogWriterAppenders and tests to create a new instance. - * - * @return The new instance. + * appendLog used to be controlled by undocumented system property gemfire.append-log */ - static LogWriterAppender create(final AppenderContext[] contexts, final String name, - final PureLogWriter logWriter, final FileOutputStream fos) { - LogWriterAppender appender = new LogWriterAppender(contexts, name, logWriter, fos); - for (AppenderContext context : appender.appenderContexts) { - context.getLoggerContext().addPropertyChangeListener(appender); - } - appender.start(); - for (AppenderContext context : appender.appenderContexts) { - context.getLoggerConfig().addAppender(appender, Level.ALL, null); - } - return appender; + private final boolean appendLog; + private final boolean security; + private final boolean debug; + private final List events; + private final LoggingSessionListeners loggingSessionListeners; + + private volatile ManagerLogWriter logWriter; + private volatile LogConfigSupplier logConfigSupplier; + private volatile LogFileRolloverDetails logFileRolloverDetails; + private volatile boolean paused; + + protected LogWriterAppender(final String name, + final Layout layout, + final Filter filter, + final ManagerLogWriter logWriter) { + this(name, layout, filter, MemberNamePatternConverter.INSTANCE.getMemberNameSupplier(), null, + true, false, START_PAUSED_BY_DEFAULT, false, LoggingSessionListeners.get()); } - @Override - public void append(final LogEvent event) { - // If already appending then don't send to avoid infinite recursion - if ((appending.get())) { - return; + protected LogWriterAppender(final String name, + final Layout layout, + final Filter filter, + final MemberNameSupplier memberNameSupplier, + final String eagerMemberName, + final boolean appendLog, + final boolean security, + final boolean startPaused, + final boolean debug, + final LoggingSessionListeners loggingSessionListeners) { + super(name, filter, layout); + this.memberNameSupplier = memberNameSupplier; + if (eagerMemberName != null) { + memberNameSupplier.set(eagerMemberName); } - appending.set(Boolean.TRUE); - try { - this.logWriter.put(LogLevel.getLogWriterLevel(event.getLevel()), - event.getMessage().getFormattedMessage(), event.getThrown()); - } finally { - appending.set(Boolean.FALSE); + this.eagerMemberName = eagerMemberName; + this.appendLog = appendLog; + this.security = security; + this.debug = debug; + if (debug) { + events = Collections.synchronizedList(new ArrayList<>()); + } else { + events = Collections.emptyList(); } + this.loggingSessionListeners = loggingSessionListeners; + paused = startPaused; } - @Override - public synchronized void propertyChange(final PropertyChangeEvent evt) { - if (logger.isDebugEnabled()) { - logger.debug("Responding to a property change event. Property name is {}.", - evt.getPropertyName()); - } - if (evt.getPropertyName().equals(LoggerContext.PROPERTY_CONFIG)) { - for (AppenderContext context : this.appenderContexts) { - LoggerConfig loggerConfig = context.getLoggerConfig(); - if (!loggerConfig.getAppenders().containsKey(this.appenderName)) { - loggerConfig.addAppender(this, Level.ALL, null); - } - } - } + @PluginBuilderFactory + public static > B newBuilder() { + return new LogWriterAppender.Builder().asBuilder(); } /** - * Stop the appender and remove it from the Log4j configuration. + * Builds LogWriterAppender instances. + * + * @param The type to build */ - protected void destroy() { // called 1st during disconnect - // add stdout appender to MAIN_LOGGER_NAME only if isUsingGemFireDefaultConfig -- see #51819 - if (LogService.MAIN_LOGGER_NAME.equals(this.logWriterLoggerName) - && LogService.isUsingGemFireDefaultConfig()) { - LogService.restoreConsoleAppender(); + public static class Builder> extends AbstractAppender.Builder + implements org.apache.logging.log4j.core.util.Builder { + + @PluginBuilderAttribute + private String memberName; + + @PluginBuilderAttribute + private boolean security; + + @PluginBuilderAttribute + private boolean appendLog = true; + + @PluginBuilderAttribute + private boolean startPaused = START_PAUSED_BY_DEFAULT; + + @PluginBuilderAttribute + private boolean debug; + + // GEODE-5785: add file permissions support similar to FileAppender + + public B withMemberName(final String memberName) { + this.memberName = memberName; + return asBuilder(); } - for (AppenderContext context : this.appenderContexts) { - context.getLoggerContext().removePropertyChangeListener(this); - context.getLoggerConfig().removeAppender(appenderName); + + public String getMemberName() { + return memberName; } - for (AppenderContext context : this.appenderContexts) { // do this second as log4j 2.6+ will - // re-add - context.getLoggerContext().updateLoggers(); + + public B setSecurity(final boolean security) { + this.security = security; + return asBuilder(); } - stop(); - cleanUp(); // 3rd - if (logger.isDebugEnabled()) { - logger.debug("A LogWriterAppender has been destroyed and cleanup is finished."); + + public boolean isSecurity() { + return security; } - } - private void cleanUp() { // was closingLogFile() -- called from destroy() as the final step - if (this.logWriter instanceof ManagerLogWriter) { - ((ManagerLogWriter) this.logWriter).closingLogFile(); + public B setAppendLog(final boolean shouldAppendLog) { + appendLog = shouldAppendLog; + return asBuilder(); } - if (this.fos != null) { - try { - this.fos.close(); - } catch (IOException ignore) { - } + + public boolean isAppendLog() { + return appendLog; + } + + public B setStartPaused(final boolean shouldStartPaused) { + startPaused = shouldStartPaused; + return asBuilder(); + } + + public boolean isStartPaused() { + return debug; + } + + public B setDebug(final boolean shouldDebug) { + debug = shouldDebug; + return asBuilder(); + } + + public boolean isDebug() { + return debug; + } + + @Override + public LogWriterAppender build() { + Layout layout = getOrCreateLayout(); + return new LogWriterAppender(getName(), layout, getFilter(), + MemberNamePatternConverter.INSTANCE.getMemberNameSupplier(), memberName, appendLog, + security, startPaused, debug, LoggingSessionListeners.get()); } } @Override - public void stop() { - try { - if (this.logWriter instanceof ManagerLogWriter) { - ((ManagerLogWriter) this.logWriter).shuttingDown(); - } - } catch (RuntimeException e) { - logger.warn("RuntimeException encountered while shuttingDown LogWriterAppender", e); + public void append(final LogEvent event) { + if (isPaused()) { + return; } + doAppendIfNotAppending(event); + } + + @Override + public void start() { + LOGGER.info("Starting {}.", this); + LOGGER.debug("Adding {} to {}.", this, loggingSessionListeners); + loggingSessionListeners.addLoggingLifecycleListener(this); + super.start(); + } + + @Override + public void stop() { + LOGGER.info("Stopping {}.", this); + // stop LogEvents from coming to this appender super.stop(); + + // clean up + loggingSessionListeners.removeLoggingLifecycleListener(this); + stopSession(); + + LOGGER.info("{} has stopped.", this); } - protected void startupComplete() { - if (this.logWriter instanceof ManagerLogWriter) { - ((ManagerLogWriter) this.logWriter).startupComplete(); - } + @Override + public void pause() { + LOGGER.debug("Pausing {}.", this); + paused = true; } - protected void setConfig(final LogConfig cfg) { - if (this.logWriter instanceof ManagerLogWriter) { - ((ManagerLogWriter) this.logWriter).setConfig(cfg); - } + @Override + public void resume() { + LOGGER.debug("Resuming {}.", this); + paused = false; } - public File getChildLogFile() { - if (this.logWriter instanceof ManagerLogWriter) { - return ((ManagerLogWriter) this.logWriter).getChildLogFile(); - } else { - return null; - } + @Override + public boolean isPaused() { + return paused; } - public File getLogDir() { - if (this.logWriter instanceof ManagerLogWriter) { - return ((ManagerLogWriter) this.logWriter).getLogDir(); - } else { - return null; + @Override + public void clearLogEvents() { + events.clear(); + } + + @Override + public List getLogEvents() { + return events; + } + + @Override + public synchronized void createSession(final SessionContext sessionContext) { + logConfigSupplier = sessionContext.getLogConfigSupplier(); + + LOGGER.info("Creating session in {} with {}.", this, logConfigSupplier); + + logConfigSupplier.addLogConfigListener(this); + + LogConfig logConfig = logConfigSupplier.getLogConfig(); + if (eagerMemberName == null && lazyMemberName == null) { + String memberName = logConfig.getName(); + memberNameSupplier.set(memberName); + lazyMemberName = memberName; } + + StatisticsConfig statisticsConfig = logConfigSupplier.getStatisticsConfig(); + ManagerLogWriterFactory managerLogWriterFactory = new ManagerLogWriterFactory() + .setSecurity(security).setAppendLog(appendLog); + + logWriter = managerLogWriterFactory.create(logConfig, statisticsConfig); + + if (logWriter == null) { + logWriter = new NullLogWriter(); + } + + logFileRolloverDetails = managerLogWriterFactory.getLogFileRolloverDetails(); } - public int getMainLogId() { - if (this.logWriter instanceof ManagerLogWriter) { - return ((ManagerLogWriter) this.logWriter).getMainLogId(); - } else { - return -1; + @Override + public synchronized void startSession() { + LOGGER.info("Starting session in {}.", this); + + logWriter.startupComplete(); + + resume(); + + logRolloverDetails(logFileRolloverDetails); + + logFileRolloverDetails = null; + logConfigSupplier = null; + } + + @Override + public synchronized void stopSession() { + LOGGER.info("Stopping session in {}.", this); + logWriter.shuttingDown(); + pause(); + logWriter.closingLogFile(); + } + + @Override + public Optional getLogFile() { + return Optional.of(new LogFile(logWriter)); + } + + @Override + public void configChanged() { + logWriter.configChanged(); + } + + @Override + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()) + ":" + getName() + + " {eagerMemberName=" + eagerMemberName + ", lazyMemberName=" + lazyMemberName + + "appendLog=" + appendLog + ", security=" + security + ", paused=" + paused + + ", loggingSessionListeners=" + loggingSessionListeners + ", logWriter=" + logWriter + + ", debug=" + debug + "}"; + } + + ManagerLogWriter getLogWriter() { + return logWriter; + } + + private void doAppendIfNotAppending(final LogEvent event) { + if (APPENDING.get()) { + // If already appending then don't send to avoid infinite recursion + return; + } + APPENDING.set(Boolean.TRUE); + try { + ManagerLogWriter currentLogWriter = logWriter; + if (currentLogWriter == null || currentLogWriter instanceof NullLogWriter) { + return; + } + doAppendToLogWriter(currentLogWriter, event); + } finally { + APPENDING.set(FALSE); } } - public boolean useChildLogging() { - if (this.logWriter instanceof ManagerLogWriter) { - return ((ManagerLogWriter) this.logWriter).useChildLogging(); - } else { - return false; + private void doAppendToLogWriter(final ManagerLogWriter logWriter, final LogEvent event) { + byte[] bytes = getLayout().toByteArray(event); + if (bytes != null && bytes.length > 0) { + // TODO:KIRK:PERF: creating new String - change to event.getMessage().getFormattedMessage()? + logWriter.writeFormattedMessage(new String(bytes, Charset.defaultCharset())); + } + if (debug) { + events.add(event); } } - protected void configChanged() { - if (this.logWriter instanceof ManagerLogWriter) { - ((ManagerLogWriter) this.logWriter).configChanged(); + private void logRolloverDetails(final LogFileRolloverDetails logFileRolloverDetails) { + // log the first msg about renaming logFile for rolling if it pre-existed + if (logFileRolloverDetails.exists()) { + if (logFileRolloverDetails.isWarning()) { + LogManager.getLogger().warn(logFileRolloverDetails.getMessage()); + } else { + LogManager.getLogger().info(logFileRolloverDetails.getMessage()); + } } } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppenders.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppenders.java deleted file mode 100644 index e6e7c4d21271..000000000000 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterAppenders.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.logging.log4j; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.geode.GemFireIOException; -import org.apache.geode.distributed.internal.DistributionConfig; -import org.apache.geode.internal.OSProcess; -import org.apache.geode.internal.logging.InternalLogWriter; -import org.apache.geode.internal.logging.LogConfig; -import org.apache.geode.internal.logging.LogService; -import org.apache.geode.internal.logging.ManagerLogWriter; -import org.apache.geode.internal.logging.SecurityManagerLogWriter; -import org.apache.geode.internal.process.ProcessLauncherContext; -import org.apache.geode.internal.util.LogFileUtils; - -/** - * Holds on to one or many instances of LogWriterAppender and provides convenience methods for - * controlling their lifecycles. - * - */ -public class LogWriterAppenders { - public static final String APPEND_TO_LOG_FILE = DistributionConfig.GEMFIRE_PREFIX + "append-log"; - private static final boolean ALLOW_REDIRECT = true; - - public enum Identifier { - MAIN(false), SECURITY(true); - private final boolean isSecure; - - Identifier(final boolean isSecure) { - this.isSecure = isSecure; - } - - public boolean isSecure() { - return this.isSecure; - } - } - - private static Map appenders = - new HashMap(); - private static Map references = - new HashMap(); - - /** - * Returns the named LogWriterAppender or null if it does not exist. - */ - public static synchronized LogWriterAppender getAppender(final Identifier id) { - return appenders.get(id); - } - - /** - * Returns the named LogWriterAppender or creates it if necessary. - */ - public static synchronized LogWriterAppender getOrCreateAppender(final Identifier id, - final boolean appendToFile, final boolean isLoner, final LogConfig config, - final boolean logConfig) { - LogWriterAppender appender = appenders.get(id); - if (appender == null) { - appender = createLogWriterAppender(appendToFile, isLoner, id.isSecure(), config, logConfig); - appenders.put(id, appender); - references.put(id, new AtomicInteger(1)); - } else { - appender.setConfig(config); - references.get(id).incrementAndGet(); - } - return appender; - } - - /** - * Returns the named LogWriterAppender or creates it if necessary. - */ - public static LogWriterAppender getOrCreateAppender(final Identifier id, final boolean isLoner, - final LogConfig config, final boolean logConfig) { - final boolean appendToFile = Boolean.getBoolean(APPEND_TO_LOG_FILE); - return getOrCreateAppender(id, appendToFile, isLoner, config, logConfig); - } - - /** - * Creates the log writer appender for a distributed system based on the system's parsed - * configuration. The initial banner and messages are also entered into the log by this method. - * - * @param isLoner Whether the distributed system is a loner or not - * @param isSecurity Whether a log for security related messages has to be created - * @param config The DistributionConfig for the target distributed system - * @param logConfig if true log the configuration - * @throws GemFireIOException if the log file can't be opened for writing - */ - static LogWriterAppender createLogWriterAppender(final boolean appendToFile, - final boolean isLoner, final boolean isSecurity, final LogConfig config, - final boolean logConfig) { - - final boolean isDistributionConfig = config instanceof DistributionConfig; - final DistributionConfig dsConfig = isDistributionConfig ? (DistributionConfig) config : null; - File logFile = config.getLogFile(); - String firstMsg = null; - boolean firstMsgWarning = false; - - AlertAppender.getInstance().setAlertingDisabled(isLoner); - - // security-log-file is specified in DistributionConfig - if (isSecurity) { - if (isDistributionConfig) { - File tmpLogFile = dsConfig.getSecurityLogFile(); - if (tmpLogFile != null && !tmpLogFile.equals(new File(""))) { - logFile = tmpLogFile; - } - } else { - throw new IllegalArgumentException("DistributionConfig is expected for SecurityLogWriter"); - } - } - - // log-file is NOT specified in DistributionConfig - if (logFile == null || logFile.equals(new File(""))) { - // out = System.out; - return null; - } - - // log-file is specified in DistributionConfig - - // if logFile exists attempt to rename it for rolling - if (logFile.exists()) { - final boolean useChildLogging = config.getLogFile() != null - && !config.getLogFile().equals(new File("")) && config.getLogFileSizeLimit() != 0; - final boolean statArchivesRolling = - isDistributionConfig && dsConfig.getStatisticArchiveFile() != null - && !dsConfig.getStatisticArchiveFile().equals(new File("")) - && dsConfig.getArchiveFileSizeLimit() != 0 && dsConfig.getStatisticSamplingEnabled(); - - if (!appendToFile || useChildLogging || statArchivesRolling) { // check useChildLogging for - // bug 50659 - final File oldMain = ManagerLogWriter.getLogNameForOldMainLog(logFile, - isSecurity || useChildLogging || statArchivesRolling); - final boolean succeeded = LogFileUtils.renameAggressively(logFile, oldMain); - - if (succeeded) { - firstMsg = String.format("Renamed old log file to %s.", - oldMain); - } else { - firstMsgWarning = true; - firstMsg = String.format("Could not rename %s to %s.", - logFile, oldMain); - } - } - } - - // create a FileOutputStream to the logFile - FileOutputStream fos; - try { - fos = new FileOutputStream(logFile, true); - } catch (FileNotFoundException ex) { - String s = String.format("Could not open log file %s.", - logFile); - throw new GemFireIOException(s, ex); - } - final PrintStream out = new PrintStream(fos); - - // create the ManagerLogWriter that LogWriterAppender will wrap - ManagerLogWriter mlw = null; - String logWriterLoggerName = null; - if (isSecurity) { - mlw = new SecurityManagerLogWriter(dsConfig.getSecurityLogLevel(), out, config.getName()); - logWriterLoggerName = LogService.SECURITY_LOGGER_NAME; - } else { - mlw = new ManagerLogWriter(config.getLogLevel(), out, config.getName()); - logWriterLoggerName = LogService.MAIN_LOGGER_NAME; - } - - mlw.setConfig(config); - // if (mlw.infoEnabled()) { -- skip here and instead do this in LogWriterFactory when creating - // the LogWriterLogger - // if (!isLoner /* do this on a loner to fix bug 35602 */ - // || !Boolean.getBoolean(InternalLocator.INHIBIT_DM_BANNER)) { - // mlw.info(Banner.getString(null)); - // } - // } - - AppenderContext[] appenderContext = new AppenderContext[1]; - if (isSecurity) { - appenderContext[0] = LogService.getAppenderContext(LogService.SECURITY_LOGGER_NAME); - } else { - appenderContext[0] = LogService.getAppenderContext(); // ROOT or - // gemfire.logging.appenders.LOGGER - } - - // create the LogWriterAppender that delegates to ManagerLogWriter; - final LogWriterAppender appender = - LogWriterAppender.create(appenderContext, logWriterLoggerName, mlw, fos); - - // remove stdout appender from MAIN_LOGGER_NAME only if isUsingGemFireDefaultConfig -- see - // #51819 - if (!isSecurity && LogService.MAIN_LOGGER_NAME.equals(logWriterLoggerName) - && LogService.isUsingGemFireDefaultConfig()) { - LogService.removeConsoleAppender(); - } - - // log the first msg about renaming logFile for rolling if it pre-existed - final InternalLogWriter logWriter = mlw; - if (firstMsg != null) { - if (firstMsgWarning) { - logWriter.warning(firstMsg); - } else { - logWriter.info(firstMsg); - } - } - - // log the config - if (logConfig) { - if (!isLoner) { - // LOG:CONFIG: changed from config to info - logWriter.info(String.format("Startup Configuration: %s", - config.toLoggerString())); - } - } - - // LOG: do NOT allow redirectOutput - if (ALLOW_REDIRECT) { - // fix #46493 by moving redirectOutput invocation here - if (ProcessLauncherContext.isRedirectingOutput()) { - try { - OSProcess.redirectOutput(config.getLogFile()); - } catch (IOException e) { - logWriter.error(e); - // throw new GemFireIOException("Unable to redirect output to " + config.getLogFile(), e); - } - } - } - - return appender; - } - - public static synchronized void startupComplete(final Identifier id) { - LogWriterAppender appender = appenders.get(id); - if (appender != null) { - appender.startupComplete(); - } - } - - public static synchronized void destroy(final Identifier id) { - LogWriterAppender appender = appenders.get(id); - if (appender == null) { - return; - } - AtomicInteger count = references.get(id); - if (count == null) { - throw new IllegalStateException("Count is null for " + id); - } - if (count.get() < 0) { - throw new IllegalStateException( - "Count is non-positive integer for " + id + ": " + count.get()); - } - if (count.decrementAndGet() > 0) { - return; - } else { - appenders.remove(id); - references.remove(id); - appender.destroy(); - } - } - - public static synchronized void stop(final Identifier id) { - LogWriterAppender appender = appenders.get(id); - if (appender != null) { - appender.stop(); - } - } - - public static synchronized void configChanged(final Identifier id) { - LogWriterAppender appender = appenders.get(id); - if (appender != null) { - appender.configChanged(); - } - } -} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverter.java new file mode 100644 index 000000000000..0e0b15434c2b --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverter.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.internal.logging.LogWriterLevel.ALL; +import static org.apache.geode.internal.logging.LogWriterLevel.ERROR; +import static org.apache.geode.internal.logging.LogWriterLevel.FINE; +import static org.apache.geode.internal.logging.LogWriterLevel.FINEST; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.internal.logging.LogWriterLevel.NONE; +import static org.apache.geode.internal.logging.LogWriterLevel.SEVERE; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; + +import org.apache.logging.log4j.Level; + +import org.apache.geode.internal.logging.LogWriterLevel; + +/** + * Converts between {@link LogWriterLevel}s and Log4J2 {@code Level}s. + * + *

+ * Implementation note: switch and if-else structures perform better than using a HashMap for this + * which matters the most if used for every log statement. + */ +public class LogWriterLevelConverter { + + /** + * Converts from a {@link LogWriterLevel} to a Log4J2 {@code Level}. + * + * @throws IllegalArgumentException if there is no matching Log4J2 Level + */ + public static Level toLevel(final LogWriterLevel logWriterLevel) { + switch (logWriterLevel) { + case ALL: + return Level.ALL; + case SEVERE: + return Level.FATAL; + case ERROR: + return Level.ERROR; + case WARNING: + return Level.WARN; + case INFO: + return Level.INFO; + case CONFIG: + return Level.INFO; + case FINE: + return Level.DEBUG; + case FINER: + return Level.TRACE; + case FINEST: + return Level.TRACE; + case NONE: + return Level.OFF; + } + + throw new IllegalArgumentException("No matching Log4J2 Level for " + logWriterLevel + "."); + } + + /** + * Converts from a Log4J2 {@code Level} to a {@link LogWriterLevel}. + * + * @throws IllegalArgumentException if there is no matching Alert + */ + public static LogWriterLevel fromLevel(final Level level) { + if (level == Level.ALL) { + return ALL; + } else if (level == Level.FATAL) { + return SEVERE; + } else if (level == Level.ERROR) { + return ERROR; + } else if (level == Level.WARN) { + return WARNING; + } else if (level == Level.INFO) { + return INFO; + } else if (level == Level.DEBUG) { + return FINE; + } else if (level == Level.TRACE) { + return FINEST; + } else if (level == Level.OFF) { + return NONE; + } + + throw new IllegalArgumentException("No matching AlertLevel for Log4J2 Level " + level + "."); + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLogger.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLogger.java index d0cde082d347..d69536c23488 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLogger.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/LogWriterLogger.java @@ -30,7 +30,7 @@ import org.apache.geode.i18n.StringId; import org.apache.geode.internal.logging.GemFireHandler; import org.apache.geode.internal.logging.InternalLogWriter; -import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.LogWriterLevel; import org.apache.geode.internal.logging.log4j.message.GemFireParameterizedMessageFactory; /** @@ -87,25 +87,6 @@ public static LogWriterLogger create(final Logger logger) { return new LogWriterLogger(logger, null, false); } - public void setLevel(final Level level) { - if (getLevel().isLessSpecificThan(Level.DEBUG) || level.isLessSpecificThan(Level.DEBUG)) { - debug("Changing level for Logger '{}' from {} to {}", loggerName, getLevel(), level); - } - - if (LogService.MAIN_LOGGER_NAME.equals(loggerName)) { - LogService.setBaseLogLevel(level); - } else if (LogService.SECURITY_LOGGER_NAME.equals(loggerName)) { - LogService.setSecurityLogLevel(level); - } else { - Configurator.setLevel(loggerName, level); - } - } - - @Override - public void setLogWriterLevel(final int logWriterLevel) { - setLevel(LogLevel.getLog4jLevel(logWriterLevel)); - } - /** * Logs a message with the specific Marker at the {@code Level.TRACE} level. * @@ -1379,7 +1360,7 @@ public void severe(final String message, final Throwable throwable) { } public void log(int logWriterLevel, final String message, final Throwable throwable) { - Level level = LogLevel.getLog4jLevel(logWriterLevel); + Level level = LogWriterLevelConverter.toLevel(LogWriterLevel.find(logWriterLevel)); logWrapper.logIfEnabled(loggerName, level, null, message, throwable); } diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverter.java new file mode 100644 index 000000000000..317854340fef --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverter.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.pattern.ConverterKeys; +import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; + +/** + * Formats the event member name. + */ +@Plugin(name = "MemberNamePatternConverter", category = "Converter") +@ConverterKeys("memberName") +public class MemberNamePatternConverter extends LogEventPatternConverter { + /** + * Singleton. + */ + static final MemberNamePatternConverter INSTANCE = new MemberNamePatternConverter(); + + private final MemberNameSupplier memberNameSupplier; + + /** + * Private constructor. + */ + private MemberNamePatternConverter() { + super("MemberName", "memberName"); + memberNameSupplier = new MemberNameSupplier(); + } + + /** + * Obtains an instance of MemberNamePatternConverter. + * + * @param options options, currently ignored, may be null. + * @return instance of MemberNamePatternConverter. + */ + public static MemberNamePatternConverter newInstance(final String[] options) { + return INSTANCE; + } + + /** + * {@inheritDoc} + */ + @Override + public void format(final LogEvent event, final StringBuilder toAppendTo) { + toAppendTo.append(memberNameSupplier.get()); + } + + MemberNameSupplier getMemberNameSupplier() { + return memberNameSupplier; + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNameSupplier.java b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNameSupplier.java new file mode 100644 index 000000000000..71e2bfdb4e66 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/log4j/MemberNameSupplier.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +public class MemberNameSupplier implements Supplier { + + private static final AtomicReference memberName = new AtomicReference<>(""); + + public void set(String newValue) { + memberName.set(newValue); + } + + @Override + public String get() { + return memberName.get(); + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/security/IntegratedSecurityService.java b/geode-core/src/main/java/org/apache/geode/internal/security/IntegratedSecurityService.java index 96a1f9cf2608..787d5b4b842f 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/security/IntegratedSecurityService.java +++ b/geode-core/src/main/java/org/apache/geode/internal/security/IntegratedSecurityService.java @@ -14,6 +14,8 @@ */ package org.apache.geode.internal.security; +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; + import java.io.IOException; import java.security.AccessController; import java.util.Properties; @@ -53,7 +55,7 @@ * Security service with SecurityManager and an optional PostProcessor. */ public class IntegratedSecurityService implements SecurityService { - private static Logger logger = LogService.getLogger(LogService.SECURITY_LOGGER_NAME); + private static Logger logger = LogService.getLogger(SECURITY_LOGGER_NAME); public static final String CREDENTIALS_SESSION_ATTRIBUTE = "credentials"; private final PostProcessor postProcessor; diff --git a/geode-core/src/main/java/org/apache/geode/internal/security/shiro/SecurityManagerProvider.java b/geode-core/src/main/java/org/apache/geode/internal/security/shiro/SecurityManagerProvider.java index ad8e66e0c5b5..a6732ddccb56 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/security/shiro/SecurityManagerProvider.java +++ b/geode-core/src/main/java/org/apache/geode/internal/security/shiro/SecurityManagerProvider.java @@ -14,6 +14,8 @@ */ package org.apache.geode.internal.security.shiro; +import static org.apache.geode.internal.logging.Configuration.SECURITY_LOGGER_NAME; + import org.apache.logging.log4j.Logger; import org.apache.shiro.SecurityUtils; import org.apache.shiro.config.Ini; @@ -27,7 +29,7 @@ import org.apache.geode.security.SecurityManager; public class SecurityManagerProvider { - private static Logger logger = LogService.getLogger(LogService.SECURITY_LOGGER_NAME); + private static Logger logger = LogService.getLogger(SECURITY_LOGGER_NAME); private org.apache.shiro.mgt.SecurityManager shiroManager; private SecurityManager securityManager; diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/GemFireStatSampler.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/GemFireStatSampler.java index 76da84c40902..9a949cb83574 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/GemFireStatSampler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/GemFireStatSampler.java @@ -33,6 +33,7 @@ import org.apache.geode.internal.PureJavaMode; import org.apache.geode.internal.admin.ListenerIdMap; import org.apache.geode.internal.admin.remote.StatListenerMessage; +import org.apache.geode.internal.logging.LogFile; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LogMarker; import org.apache.geode.internal.statistics.platform.OsStatisticsFactory; @@ -42,7 +43,6 @@ * GemFireStatSampler adds listeners and rolling archives to HostStatSampler. *

* The StatisticsManager is implemented by DistributedSystem. - * */ public class GemFireStatSampler extends HostStatSampler { @@ -70,6 +70,11 @@ public GemFireStatSampler(InternalDistributedSystem con) { this.con = con; } + public GemFireStatSampler(InternalDistributedSystem con, LogFile logFile) { + super(con.getCancelCriterion(), new StatSamplerStats(con, con.getId()), logFile); + this.con = con; + } + /** * Returns the ProcessStats for this Java VM. Note that null will be * returned if operating statistics are disabled. diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java index 4ca1b683f651..390747ec20d9 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java @@ -17,6 +17,7 @@ import java.io.File; import java.net.UnknownHostException; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; @@ -28,6 +29,7 @@ import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.NanoTimer; import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; +import org.apache.geode.internal.logging.LogFile; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LoggingThread; import org.apache.geode.internal.logging.log4j.LogMarker; @@ -91,18 +93,31 @@ public abstract class HostStatSampler private final NanoTimer timer; + private final LogFile logFile; + protected HostStatSampler(CancelCriterion stopper, StatSamplerStats samplerStats) { this(stopper, samplerStats, new NanoTimer()); } protected HostStatSampler(CancelCriterion stopper, StatSamplerStats samplerStats, NanoTimer timer) { + this(stopper, samplerStats, timer, null); + } + + protected HostStatSampler(CancelCriterion stopper, StatSamplerStats samplerStats, + LogFile logFile) { + this(stopper, samplerStats, new NanoTimer(), logFile); + } + + protected HostStatSampler(CancelCriterion stopper, StatSamplerStats samplerStats, NanoTimer timer, + LogFile logFile) { this.stopper = stopper; this.statSamplerInitializedLatch = new StoppableCountDownLatch(this.stopper, 1); this.samplerStats = samplerStats; this.fileSizeLimitInKB = Boolean.getBoolean(TEST_FILE_SIZE_LIMIT_IN_KB_PROPERTY); this.callbackSampler = new CallbackSampler(stopper, samplerStats); this.timer = timer; + this.logFile = logFile; } public StatSamplerStats getStatSamplerStats() { @@ -153,6 +168,11 @@ public String getSystemDirectoryPath() { } } + @Override + public Optional getLogFile() { + return Optional.ofNullable(logFile); + } + @Override public boolean waitForSample(long timeout) throws InterruptedException { final long endTime = System.currentTimeMillis() + timeout; diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java index 309dc90e4c35..8142eb55b971 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java @@ -27,10 +27,9 @@ import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.io.RollingFileHandler; import org.apache.geode.internal.logging.InternalLogWriter; +import org.apache.geode.internal.logging.LogFile; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LogMarker; -import org.apache.geode.internal.logging.log4j.LogWriterAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; import org.apache.geode.internal.logging.log4j.LogWriterLogger; /** @@ -434,13 +433,13 @@ File getRollingArchiveName(File archive, boolean archiveClosed) { // leave mainArchiveId as is. Bump archiveId. } else { archiveDir = archive.getAbsoluteFile().getParentFile(); - LogWriterAppender lwa = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); boolean mainArchiveIdCalculated = false; - if (lwa != null) { - File logDir = lwa.getLogDir(); + if (config.getLogFile().isPresent()) { + LogFile logFile = config.getLogFile().get(); + File logDir = logFile.getLogDir(); if (archiveDir.equals(logDir)) { - mainArchiveId = lwa.getMainLogId(); - if (mainArchiveId > 1 && lwa.useChildLogging()) { + mainArchiveId = logFile.getMainLogId(); + if (mainArchiveId > 1 && logFile.useChildLogging()) { mainArchiveId--; } mainArchiveIdCalculated = true; @@ -527,12 +526,12 @@ void initMainArchiveId(File archive) { return; } archiveDir = archive.getAbsoluteFile().getParentFile(); - LogWriterAppender lwa = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); boolean mainArchiveIdCalculated = false; - if (lwa != null) { - File logDir = lwa.getLogDir(); + if (config.getLogFile().isPresent()) { + LogFile logFile = config.getLogFile().get(); + File logDir = logFile.getLogDir(); if (archiveDir.equals(logDir)) { - mainArchiveId = lwa.getMainLogId(); + mainArchiveId = logFile.getMainLogId(); mainArchiveIdCalculated = true; } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandlerConfig.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandlerConfig.java index aa43435f087c..25abe8e507c5 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandlerConfig.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandlerConfig.java @@ -15,15 +15,22 @@ package org.apache.geode.internal.statistics; import java.io.File; +import java.util.Optional; + +import org.apache.geode.internal.logging.LogFile; /** * Defines the contract enabling the {@link StatArchiveHandler} to retrieve configuration details * (some of which may change at runtime). - *

+ * + *

* Implemented by {@link HostStatSampler}. * + *

+ * Note: This interface changes the return types of file limit properties from int to long so that + * the Stat Sampler tests can change the units from MB to KB. + * * @since GemFire 7.0 - * @see org.apache.geode.distributed.internal.RuntimeDistributionConfigImpl */ public interface StatArchiveHandlerConfig { @@ -61,4 +68,9 @@ public interface StatArchiveHandlerConfig { * Returns a description of the product that the stats are on */ String getProductDescription(); + + /** + * Returns the log file to provide info about main id and child id. + */ + Optional getLogFile(); } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java b/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java index 8b86ecca27a8..dc3e60a15a44 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java @@ -73,11 +73,10 @@ import org.apache.geode.internal.cache.PartitionedRegionStats; import org.apache.geode.internal.cache.control.ResourceManagerStats; import org.apache.geode.internal.cache.execute.FunctionServiceStats; +import org.apache.geode.internal.logging.LogFile; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.LoggingThread; import org.apache.geode.internal.logging.log4j.LogMarker; -import org.apache.geode.internal.logging.log4j.LogWriterAppender; -import org.apache.geode.internal.logging.log4j.LogWriterAppenders; import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.offheap.MemoryAllocator; import org.apache.geode.internal.offheap.OffHeapMemoryStats; @@ -914,9 +913,9 @@ public String fetchLog(int numLines) { try { InternalDistributedSystem sys = system; - LogWriterAppender lwa = LogWriterAppenders.getAppender(LogWriterAppenders.Identifier.MAIN); - if (lwa != null) { - childTail = BeanUtilFuncs.tailSystemLog(lwa.getChildLogFile(), numLines); + if (sys.getLogFile().isPresent()) { + LogFile logFile = sys.getLogFile().get(); + childTail = BeanUtilFuncs.tailSystemLog(logFile.getChildLogFile(), numLines); mainTail = BeanUtilFuncs.tailSystemLog(sys.getConfig(), numLines); if (mainTail == null) { mainTail = diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DiskStoreCommandsUtils.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DiskStoreCommandsUtils.java index ab09a35d4625..618fb1afd64c 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DiskStoreCommandsUtils.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DiskStoreCommandsUtils.java @@ -25,6 +25,7 @@ import org.apache.geode.distributed.DistributedMember; import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.internal.logging.Configuration; import org.apache.geode.internal.logging.LogService; import org.apache.geode.management.internal.cli.CliUtil; @@ -33,7 +34,7 @@ class DiskStoreCommandsUtils { static void configureLogging(final List commandList) { String configFilePropertyValue = System.getProperty(CONFIGURATION_FILE_PROPERTY); if (StringUtils.isBlank(configFilePropertyValue)) { - URL configUrl = LogService.class.getResource(LogService.CLI_CONFIG); + URL configUrl = LogService.class.getResource(Configuration.CLI_CONFIG); configFilePropertyValue = configUrl.toString(); } commandList.add("-D" + CONFIGURATION_FILE_PROPERTY + "=" + configFilePropertyValue); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunction.java index 540890c3d9bc..62a1830a0122 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunction.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ChangeLogLevelFunction.java @@ -22,40 +22,38 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; -import org.apache.geode.cache.Cache; import org.apache.geode.cache.execute.FunctionContext; import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.internal.cache.InternalCache; import org.apache.geode.internal.cache.execute.InternalFunction; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LogLevel; import org.apache.geode.internal.logging.log4j.LogMarker; -import org.apache.geode.internal.logging.log4j.LogWriterLogger; - /** - * * Class for change log level function * - * since 8.0 - * + * @since 8.0 */ - public class ChangeLogLevelFunction implements InternalFunction { private static final Logger logger = LogService.getLogger(); + private static final long serialVersionUID = 1L; public static final String ID = ChangeLogLevelFunction.class.getName(); - private static final long serialVersionUID = 1L; @Override public void execute(FunctionContext context) { - Cache cache = context.getCache(); - Map result = new HashMap(); + InternalCache cache = (InternalCache) context.getCache(); + Map result = new HashMap<>(); try { - LogWriterLogger logwriterLogger = (LogWriterLogger) cache.getLogger(); Object[] args = (Object[]) context.getArguments(); - final String logLevel = (String) args[0]; + String logLevel = (String) args[0]; + Level log4jLevel = LogLevel.getLevel(logLevel); - logwriterLogger.setLevel(log4jLevel); + int logWriterLevel = LogLevel.getLogWriterLevel(logLevel); + + cache.getInternalDistributedSystem().getConfig().setLogLevel(logWriterLevel); + System.setProperty(DistributionConfig.GEMFIRE_PREFIX + LOG_LEVEL, logLevel); logger.info(LogMarker.CONFIG_MARKER, "GFSH Changed log level to {}", log4jLevel); result.put(cache.getDistributedSystem().getDistributedMember().getId(), @@ -72,8 +70,7 @@ public void execute(FunctionContext context) { @Override public String getId() { - return ChangeLogLevelFunction.ID; - + return ID; } @Override @@ -91,5 +88,4 @@ public boolean optimizeForWrite() { public boolean isHA() { return false; } - } diff --git a/geode-core/src/main/resources/log4j2-cli.xml b/geode-core/src/main/resources/log4j2-cli.xml index 9597f99521f5..ace46782532d 100644 --- a/geode-core/src/main/resources/log4j2-cli.xml +++ b/geode-core/src/main/resources/log4j2-cli.xml @@ -15,7 +15,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n diff --git a/geode-core/src/main/resources/log4j2.xml b/geode-core/src/main/resources/log4j2.xml index e44c3e5caa28..7f6bfdff50c2 100755 --- a/geode-core/src/main/resources/log4j2.xml +++ b/geode-core/src/main/resources/log4j2.xml @@ -15,15 +15,22 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n true - + - + + + + + + + + @@ -32,10 +39,15 @@ + + + + + diff --git a/geode-core/src/main/resources/org/apache/geode/internal/logging/log4j/log4j2-legacy.xml b/geode-core/src/main/resources/org/apache/geode/internal/logging/log4j/log4j2-legacy.xml index d5691a1b30e7..914acc591cfd 100644 --- a/geode-core/src/main/resources/org/apache/geode/internal/logging/log4j/log4j2-legacy.xml +++ b/geode-core/src/main/resources/org/apache/geode/internal/logging/log4j/log4j2-legacy.xml @@ -1,5 +1,5 @@ - + [%level{FATAL=severe,ERROR=error,WARN=warning,INFO=info,DEBUG=fine,TRACE=finest} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n diff --git a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt index 3c5669b1de09..e73b2028e19a 100644 --- a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt +++ b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt @@ -377,7 +377,6 @@ org/apache/geode/internal/hll/CardinalityMergeException,false org/apache/geode/internal/jta/TransactionManagerImpl,true,5033392316185449821,globalTransactionMap:java/util/Map,gtxSet:java/util/SortedSet,isActive:boolean,transactionMap:java/util/Map org/apache/geode/internal/jta/TransactionManagerImpl$GlobalTransactionComparator,false org/apache/geode/internal/jta/UserTransactionImpl,true,2994652455204901910,storedTimeOut:int,tm:javax/transaction/TransactionManager -org/apache/geode/internal/logging/LogWriterLevel,false,logWriterLevel:int org/apache/geode/internal/memcached/Command,false org/apache/geode/internal/memcached/Command$1,false,processor:org/apache/geode/internal/memcached/CommandProcessor org/apache/geode/internal/memcached/Command$10,false,processor:org/apache/geode/internal/memcached/CommandProcessor diff --git a/geode-core/src/test/java/org/apache/geode/internal/BannerTest.java b/geode-core/src/test/java/org/apache/geode/internal/BannerTest.java new file mode 100644 index 000000000000..56e0b65af2ba --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/BannerTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link Banner} and {@link Banner.BannerHeader}. + */ +@Category(LoggingTest.class) +public class BannerTest { + + private String banner; + + @Before + public void setUp() { + banner = Banner.getString(null); + } + + @Test + public void moreThanZeroBannerHeaderValues() { + assertThat(Banner.BannerHeader.values().length).isGreaterThan(0); + } + + @Test + public void moreThanZeroBannerHeaderDisplayValues() { + assertThat(Banner.BannerHeader.displayValues().length).isGreaterThan(0); + } + + @Test + public void displayValuesReturnsDisplayValueForEveryBannerHeader() { + for (Banner.BannerHeader bannerHeader : Banner.BannerHeader.values()) { + assertThat(Banner.BannerHeader.displayValues()).contains(bannerHeader.displayValue()); + } + } + + @Test + public void bannerContainsEveryBannerHeader() { + assertThat(banner).contains(Banner.BannerHeader.displayValues()); + } +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/ConfigurationTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/ConfigurationTest.java new file mode 100644 index 000000000000..be6f94437b75 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/ConfigurationTest.java @@ -0,0 +1,382 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.Configuration.LOG_LEVEL_UPDATE_OCCURS_PROPERTY; +import static org.apache.geode.internal.logging.Configuration.LOG_LEVEL_UPDATE_SCOPE_PROPERTY; +import static org.apache.geode.internal.logging.Configuration.PROVIDER_AGENT_NAME_PROPERTY; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; + +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateOccurs; +import org.apache.geode.internal.logging.Configuration.LogLevelUpdateScope; +import org.apache.geode.internal.logging.log4j.Log4jAgent; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link Configuration}. + */ +@Category(LoggingTest.class) +public class ConfigurationTest { + + private ProviderAgent providerAgent; + private LogConfig logConfig; + private LogConfigSupplier logConfigSupplier; + private Configuration configuration; + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + @Before + public void setUp() { + providerAgent = mock(ProviderAgent.class); + logConfig = mock(LogConfig.class); + logConfigSupplier = mockLogConfigSupplier(); + configuration = Configuration.create(providerAgent); + } + + @Test + public void logConfigSupplierIsNullByDefault() { + assertThat(configuration.getLogConfigSupplier()).isNull(); + } + + @Test + public void initializeSetsLogConfigSupplier() { + configuration.initialize(logConfigSupplier); + + assertThat(configuration.getLogConfigSupplier()).isSameAs(logConfigSupplier); + } + + @Test + public void initializeAddsSelfAsListenerToLogConfigSupplier() { + configuration.initialize(logConfigSupplier); + + verify(logConfigSupplier).addLogConfigListener(eq(configuration)); + } + + @Test + public void initializeReplacesLogConfigSupplier() { + LogConfigSupplier logConfigSupplier1 = mockLogConfigSupplier(); + LogConfigSupplier logConfigSupplier2 = mockLogConfigSupplier(); + LogConfigSupplier logConfigSupplier3 = mockLogConfigSupplier(); + + configuration.initialize(logConfigSupplier1); + configuration.initialize(logConfigSupplier2); + configuration.initialize(logConfigSupplier3); + + assertThat(configuration.getLogConfigSupplier()).isSameAs(logConfigSupplier3); + } + + @Test + public void initializeAddsSelfAsListenerOnlyOnceToEachLogConfigSupplier() { + LogConfigSupplier logConfigSupplier1 = mockLogConfigSupplier(); + LogConfigSupplier logConfigSupplier2 = mockLogConfigSupplier(); + LogConfigSupplier logConfigSupplier3 = mockLogConfigSupplier(); + + configuration.initialize(logConfigSupplier1); + configuration.initialize(logConfigSupplier2); + configuration.initialize(logConfigSupplier3); + + verify(logConfigSupplier1).addLogConfigListener(eq(configuration)); + verify(logConfigSupplier2).addLogConfigListener(eq(configuration)); + verify(logConfigSupplier3).addLogConfigListener(eq(configuration)); + } + + @Test + public void initializeWithNullThrowsIllegalArgumentException() { + assertThatThrownBy(() -> configuration.initialize(null)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void initializeConfiguresProviderAgent() { + configuration.initialize(logConfigSupplier); + + verify(providerAgent).configure(eq(logConfig), isA(LogLevelUpdateOccurs.class), isA( + LogLevelUpdateScope.class)); + } + + @Test + public void configChangedWithoutLogConfigSupplierThrowsIllegalStateException() { + assertThatThrownBy(() -> configuration.configChanged()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void configChangedReconfiguresProviderAgent() { + configuration.initialize(logConfigSupplier); + + configuration.configChanged(); + + verify(providerAgent, times(2)).configure(eq(logConfig), isA(LogLevelUpdateOccurs.class), + isA(LogLevelUpdateScope.class)); + } + + @Test + public void shutdownRemovesCurrentLogConfigSupplier() { + configuration.initialize(logConfigSupplier); + configuration.shutdown(); + + assertThat(configuration.getLogConfigSupplier()).isNull(); + } + + @Test + public void shutdownRemovesSelfAsListenerFromCurrentLogConfigSupplier() { + configuration.initialize(logConfigSupplier); + configuration.shutdown(); + + verify(logConfigSupplier).removeLogConfigListener(eq(configuration)); + } + + @Test + public void shutdownDoesNothingWithoutCurrentLogConfigSupplier() { + configuration.shutdown(); + + verifyNoMoreInteractions(logConfigSupplier); + } + + @Test + public void getLogLevelUpdateOccurs_defaultsTo_ONLY_WHEN_USING_DEFAULT_CONFIG() { + assertThat(Configuration.getLogLevelUpdateOccurs()) + .isEqualTo(LogLevelUpdateOccurs.ONLY_WHEN_USING_DEFAULT_CONFIG); + } + + @Test + public void getLogLevelUpdateOccurs_usesSystemPropertySetTo_ONLY_WHEN_USING_DEFAULT_CONFIG() { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, + LogLevelUpdateOccurs.ONLY_WHEN_USING_DEFAULT_CONFIG.name()); + + assertThat(Configuration.getLogLevelUpdateOccurs()) + .isEqualTo(LogLevelUpdateOccurs.ONLY_WHEN_USING_DEFAULT_CONFIG); + } + + @Test + public void getLogLevelUpdateOccurs_usesSystemPropertySetTo_ALWAYS() { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, LogLevelUpdateOccurs.ALWAYS.name()); + + assertThat(Configuration.getLogLevelUpdateOccurs()).isEqualTo(LogLevelUpdateOccurs.ALWAYS); + } + + @Test + public void getLogLevelUpdateOccurs_usesSystemPropertySetTo_NEVER() { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, LogLevelUpdateOccurs.NEVER.name()); + + assertThat(Configuration.getLogLevelUpdateOccurs()).isEqualTo(LogLevelUpdateOccurs.NEVER); + } + + @Test + public void getLogLevelUpdateOccurs_usesSystemPropertySetTo_only_when_using_default_config() { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, + LogLevelUpdateOccurs.ONLY_WHEN_USING_DEFAULT_CONFIG.name().toLowerCase()); + + assertThat(Configuration.getLogLevelUpdateOccurs()) + .isEqualTo(LogLevelUpdateOccurs.ONLY_WHEN_USING_DEFAULT_CONFIG); + } + + @Test + public void getLogLevelUpdateOccurs_usesSystemPropertySetTo_always() { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, + LogLevelUpdateOccurs.ALWAYS.name().toLowerCase()); + + assertThat(Configuration.getLogLevelUpdateOccurs()).isEqualTo(LogLevelUpdateOccurs.ALWAYS); + } + + @Test + public void getLogLevelUpdateOccurs_usesSystemPropertySetTo_never() { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, + LogLevelUpdateOccurs.NEVER.name().toLowerCase()); + + assertThat(Configuration.getLogLevelUpdateOccurs()).isEqualTo(LogLevelUpdateOccurs.NEVER); + } + + @Test + public void getLogLevelUpdateOccurs_usesDefaultWhenSystemPropertySetTo_gibberish() { + System.setProperty(LOG_LEVEL_UPDATE_OCCURS_PROPERTY, "gibberish"); + + assertThat(Configuration.getLogLevelUpdateOccurs()) + .isEqualTo(LogLevelUpdateOccurs.ONLY_WHEN_USING_DEFAULT_CONFIG); + } + + @Test + public void getLogLevelUpdateScope_defaultsTo_GEODE_LOGGERS() { + assertThat(Configuration.getLogLevelUpdateScope()).isEqualTo(LogLevelUpdateScope.GEODE_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_GEODE_LOGGERS() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, LogLevelUpdateScope.GEODE_LOGGERS.name()); + + assertThat(Configuration.getLogLevelUpdateScope()).isEqualTo(LogLevelUpdateScope.GEODE_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_GEODE_AND_SECURITY_LOGGERS() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, + LogLevelUpdateScope.GEODE_AND_SECURITY_LOGGERS.name()); + + assertThat(Configuration.getLogLevelUpdateScope()) + .isEqualTo(LogLevelUpdateScope.GEODE_AND_SECURITY_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_GEODE_AND_APPLICATION_LOGGERS() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, + LogLevelUpdateScope.GEODE_AND_APPLICATION_LOGGERS.name()); + + assertThat(Configuration.getLogLevelUpdateScope()) + .isEqualTo(LogLevelUpdateScope.GEODE_AND_APPLICATION_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_ALL_LOGGERS() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, LogLevelUpdateScope.ALL_LOGGERS.name()); + + assertThat(Configuration.getLogLevelUpdateScope()).isEqualTo(LogLevelUpdateScope.ALL_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_geode_loggers() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, + LogLevelUpdateScope.GEODE_LOGGERS.name().toLowerCase()); + + assertThat(Configuration.getLogLevelUpdateScope()).isEqualTo(LogLevelUpdateScope.GEODE_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_geode_and_security_loggers() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, + LogLevelUpdateScope.GEODE_AND_SECURITY_LOGGERS.name().toLowerCase()); + + assertThat(Configuration.getLogLevelUpdateScope()) + .isEqualTo(LogLevelUpdateScope.GEODE_AND_SECURITY_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_geode_and_application_loggers() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, + LogLevelUpdateScope.GEODE_AND_APPLICATION_LOGGERS.name().toLowerCase()); + + assertThat(Configuration.getLogLevelUpdateScope()) + .isEqualTo(LogLevelUpdateScope.GEODE_AND_APPLICATION_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesSystemPropertySetTo_all_loggers() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, + LogLevelUpdateScope.ALL_LOGGERS.name().toLowerCase()); + + assertThat(Configuration.getLogLevelUpdateScope()).isEqualTo(LogLevelUpdateScope.ALL_LOGGERS); + } + + @Test + public void getLogLevelUpdateScope_usesDefaultWhenSystemPropertySetTo_gibberish() { + System.setProperty(LOG_LEVEL_UPDATE_SCOPE_PROPERTY, "gibberish"); + + assertThat(Configuration.getLogLevelUpdateScope()).isEqualTo(LogLevelUpdateScope.GEODE_LOGGERS); + } + + @Test + public void createProviderAgent_defaultsTo_Log4jAgent() { + assertThat(Configuration.createProviderAgent()).isInstanceOf(Log4jAgent.class); + } + + @Test + public void createProviderAgent_usesSystemPropertySetTo_Log4jAgent() { + System.setProperty(PROVIDER_AGENT_NAME_PROPERTY, Log4jAgent.class.getName()); + + assertThat(Configuration.createProviderAgent()).isInstanceOf(Log4jAgent.class); + } + + @Test + public void createProviderAgent_usesSystemPropertySetTo_NullProviderAgent() { + System.setProperty(PROVIDER_AGENT_NAME_PROPERTY, NullProviderAgent.class.getName()); + + assertThat(Configuration.createProviderAgent()).isInstanceOf(NullProviderAgent.class); + } + + @Test + public void createProviderAgent_usesSystemPropertySetTo_SimpleProviderAgent() { + System.setProperty(PROVIDER_AGENT_NAME_PROPERTY, SimpleProviderAgent.class.getName()); + + assertThat(Configuration.createProviderAgent()).isInstanceOf(SimpleProviderAgent.class); + } + + @Test + public void createProviderAgent_usesNullProviderAgent_whenClassNotFoundException() { + System.setProperty(PROVIDER_AGENT_NAME_PROPERTY, SimpleProviderAgent.class.getSimpleName()); + + assertThat(Configuration.createProviderAgent()).isInstanceOf(NullProviderAgent.class); + } + + @Test + public void createProviderAgent_usesNullProviderAgent_whenClassCastException() { + System.setProperty(PROVIDER_AGENT_NAME_PROPERTY, NotProviderAgent.class.getName()); + + assertThat(Configuration.createProviderAgent()).isInstanceOf(NullProviderAgent.class); + } + + private LogConfigSupplier mockLogConfigSupplier() { + LogConfigSupplier logConfigSupplier = mock(LogConfigSupplier.class); + + when(logConfigSupplier.getLogConfig()).thenReturn(logConfig); + when(logConfig.getLogLevel()).thenReturn(INFO.intLevel()); + when(logConfig.getSecurityLogLevel()).thenReturn(INFO.intLevel()); + + return logConfigSupplier; + } + + public static class SimpleProviderAgent implements ProviderAgent { + + @Override + public void configure(LogConfig logConfig, + LogLevelUpdateOccurs logLevelUpdateOccurs, + LogLevelUpdateScope logLevelUpdateScope) { + // nothing + } + + @Override + public void cleanup() { + // nothing + } + + @Override + public void enableLoggingToStandardOutput() { + // nothing + } + + @Override + public void disableLoggingToStandardOutput() { + // nothing + } + } + + public static class NotProviderAgent { + + } +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexMatchesStartupConfigurationTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexMatchesStartupConfigurationTest.java new file mode 100644 index 000000000000..00dcb699db9f --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexMatchesStartupConfigurationTest.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.LogMessageRegex.Group.DATE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.LOG_LEVEL; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.MEMBER_NAME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.MESSAGE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.THREAD_ID; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.THREAD_NAME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.TIME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.TIME_ZONE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.values; +import static org.apache.geode.internal.logging.LogMessageRegex.getPattern; +import static org.apache.geode.internal.logging.LogMessageRegex.getRegex; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link LogMessageRegex} matching startup configuration with optional + * {@code memberName} missing. + * + *

+ * Example log message containing startup configuration: + * + *

+ * [info 2018/10/19 16:03:18.069 PDT 
tid=0x1] Startup Configuration: ### GemFire Properties defined with api ### + *
+ */ +@Category(LoggingTest.class) +public class LogMessageRegexMatchesStartupConfigurationTest { + + private final String logLevel = "info"; + private final String date = "2018/10/19"; + private final String time = "16:03:18.069"; + private final String timeZone = "PDT"; + private final String memberName = ""; + private final String threadName = "
"; + private final String threadId = "tid=0x1"; + private final String message = + "Startup Configuration: ### GemFire Properties defined with api ###"; + + private String logLine; + + @Before + public void setUp() { + logLine = "[" + logLevel + " " + date + " " + time + " " + timeZone + " " + memberName + + threadName + " " + threadId + "] " + message; + } + + @Test + public void regexMatchesStartupConfigurationLogLine() { + assertThat(logLine).matches(getRegex()); + } + + @Test + public void patternMatcherMatchesStartupConfigurationLogLine() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void patternMatcherGroupZeroMatchesStartupConfigurationLogLine() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(0)).isEqualTo(logLine); + } + + @Test + public void patternMatcherGroupCountEqualsGroupsLength() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.groupCount()).isEqualTo(values().length); + } + + @Test + public void logLevelGroupIndexCapturesStartupConfigurationLogLevel() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(LOG_LEVEL.getIndex())).isEqualTo(logLevel); + } + + @Test + public void dateGroupIndexCapturesStartupConfigurationDate() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(DATE.getIndex())).isEqualTo(date); + } + + @Test + public void timeGroupIndexCapturesStartupConfigurationTime() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME.getIndex())).isEqualTo(time); + } + + @Test + public void timeZoneGroupIndexCapturesStartupConfigurationTimeZone() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME_ZONE.getIndex())).isEqualTo(timeZone); + } + + @Test + public void logLevelGroupNameCapturesStartupConfigurationLogLevel() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(LOG_LEVEL.getName())).isEqualTo(logLevel); + } + + @Test + public void dateGroupNameCapturesStartupConfigurationDate() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(DATE.getName())).isEqualTo(date); + } + + @Test + public void timeGroupNameCapturesStartupConfigurationTime() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME.getName())).isEqualTo(time); + } + + @Test + public void timeZoneGroupNameCapturesStartupConfigurationTimeZone() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME_ZONE.getName())).isEqualTo(timeZone); + } + + @Test + public void memberNameGroupNameCapturesStartupConfigurationMemberName() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(MEMBER_NAME.getName())).isEqualTo(memberName); + } + + @Test + public void threadNameGroupNameCapturesStartupConfigurationThreadName() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(THREAD_NAME.getName())).isEqualTo(threadName); + } + + @Test + public void threadIdGroupNameCapturesStartupConfigurationThreadId() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(THREAD_ID.getName())).isEqualTo(threadId); + } + + @Test + public void messageGroupNameCapturesStartupConfigurationMessage() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(MESSAGE.getName())).isEqualTo(message); + } + + @Test + public void logLevelRegexMatchesStartupConfigurationLogLevel() { + Matcher matcher = Pattern.compile(LOG_LEVEL.getRegex()).matcher(logLevel); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void dateRegexMatchesStartupConfigurationDate() { + Matcher matcher = Pattern.compile(DATE.getRegex()).matcher(date); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void timeRegexMatchesStartupConfigurationTime() { + Matcher matcher = Pattern.compile(TIME.getRegex()).matcher(time); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void timeZoneRegexMatchesStartupConfigurationTimeZone() { + Matcher matcher = Pattern.compile(TIME_ZONE.getRegex()).matcher(timeZone); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void memberNameRegexMatchesStartupConfigurationMemberName() { + Matcher matcher = Pattern.compile(MEMBER_NAME.getRegex()).matcher(memberName); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void threadNameRegexMatchesStartupConfigurationThreadName() { + Matcher matcher = Pattern.compile(THREAD_NAME.getRegex()).matcher(threadName); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void threadIdRegexMatchesStartupConfigurationThreadId() { + Matcher matcher = Pattern.compile(THREAD_ID.getRegex()).matcher(threadId); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void messageRegexMatchesStartupConfigurationMessage() { + Matcher matcher = Pattern.compile(MESSAGE.getRegex()).matcher(message); + assertThat(matcher.matches()).isTrue(); + } +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexTest.java new file mode 100644 index 000000000000..5c77a52ea7cc --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/LogMessageRegexTest.java @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.LogMessageRegex.Group.DATE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.LOG_LEVEL; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.MEMBER_NAME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.MESSAGE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.THREAD_ID; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.THREAD_NAME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.TIME; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.TIME_ZONE; +import static org.apache.geode.internal.logging.LogMessageRegex.Group.values; +import static org.apache.geode.internal.logging.LogMessageRegex.getPattern; +import static org.apache.geode.internal.logging.LogMessageRegex.getRegex; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link LogMessageRegex}. + */ +@Category(LoggingTest.class) +public class LogMessageRegexTest { + + private final String logLevel = "info"; + private final String date = "2018/09/24"; + private final String time = "12:35:59.515"; + private final String timeZone = "PDT"; + private final String memberName = "logMessageRegexTest"; + private final String threadName = "
"; + private final String threadId = "tid=0x1"; + private final String message = "this is a log statement"; + + private String logLine; + + @Before + public void setUp() { + logLine = "[" + logLevel + " " + date + " " + time + " " + timeZone + " " + memberName + " " + + threadName + " " + threadId + "] " + message; + } + + @Test + public void regexMatchesLogLine() { + assertThat(logLine).matches(getRegex()); + } + + @Test + public void patternMatcherMatchesLogLine() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void patternMatcherGroupZeroMatchesLogLine() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(0)).isEqualTo(logLine); + } + + @Test + public void patternMatcherGroupCountEqualsGroupsLength() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.groupCount()).isEqualTo(values().length); + } + + @Test + public void logLevelGroupIndexCapturesLogLevel() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(LOG_LEVEL.getIndex())).isEqualTo(logLevel); + } + + @Test + public void dateGroupIndexCapturesDate() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(DATE.getIndex())).isEqualTo(date); + } + + @Test + public void timeGroupIndexCapturesTime() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME.getIndex())).isEqualTo(time); + } + + @Test + public void timeZoneGroupIndexCapturesTimeZone() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME_ZONE.getIndex())).isEqualTo(timeZone); + } + + @Test + public void logLevelGroupNameCapturesLogLevel() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(LOG_LEVEL.getName())).isEqualTo(logLevel); + } + + @Test + public void dateGroupNameCapturesDate() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(DATE.getName())).isEqualTo(date); + } + + @Test + public void timeGroupNameCapturesTime() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME.getName())).isEqualTo(time); + } + + @Test + public void timeZoneGroupNameCapturesTimeZone() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(TIME_ZONE.getName())).isEqualTo(timeZone); + } + + @Test + public void memberNameGroupNameCapturesMemberName() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(MEMBER_NAME.getName())).isEqualTo(memberName); + } + + @Test + public void threadNameGroupNameCapturesThreadName() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(THREAD_NAME.getName())).isEqualTo(threadName); + } + + @Test + public void threadIdGroupNameCapturesThreadId() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(THREAD_ID.getName())).isEqualTo(threadId); + } + + @Test + public void messageGroupNameCapturesMessage() { + Matcher matcher = getPattern().matcher(logLine); + assertThat(matcher.matches()).isTrue(); + assertThat(matcher.group(MESSAGE.getName())).isEqualTo(message); + } + + @Test + public void logLevelRegexMatchesLogLevel() { + Matcher matcher = Pattern.compile(LOG_LEVEL.getRegex()).matcher(logLevel); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void dateRegexMatchesDate() { + Matcher matcher = Pattern.compile(DATE.getRegex()).matcher(date); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void timeRegexMatchesTime() { + Matcher matcher = Pattern.compile(TIME.getRegex()).matcher(time); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void timeZoneRegexMatchesTimeZone() { + Matcher matcher = Pattern.compile(TIME_ZONE.getRegex()).matcher(timeZone); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void memberNameRegexMatchesMemberName() { + Matcher matcher = Pattern.compile(MEMBER_NAME.getRegex()).matcher(memberName); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void threadNameRegexMatchesThreadName() { + Matcher matcher = Pattern.compile(THREAD_NAME.getRegex()).matcher(threadName); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void threadIdRegexMatchesThreadId() { + Matcher matcher = Pattern.compile(THREAD_ID.getRegex()).matcher(threadId); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void messageRegexMatchesMessage() { + Matcher matcher = Pattern.compile(MESSAGE.getRegex()).matcher(message); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void memberNameRegexMatchesMissingMemberName() { + Matcher matcher = Pattern.compile(MEMBER_NAME.getRegex()).matcher(""); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void memberNameRegexMatchesMemberNameWithNoSpaces() { + Matcher matcher = Pattern.compile(MEMBER_NAME.getRegex()).matcher(""); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void memberNameRegexMatchesMemberNameWithOneSpace() { + Matcher matcher = Pattern.compile(MEMBER_NAME.getRegex()).matcher("hello world"); + assertThat(matcher.matches()).isTrue(); + } + + @Test + public void memberNameRegexMatchesMemberNameWithMultipleSpaces() { + Matcher matcher = Pattern.compile(MEMBER_NAME.getRegex()).matcher("this is a name"); + assertThat(matcher.matches()).isTrue(); + } +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/LogServiceTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/LogServiceTest.java index 1e7e8b012c70..e8ca28cad01c 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/logging/LogServiceTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/LogServiceTest.java @@ -14,97 +14,118 @@ */ package org.apache.geode.internal.logging; -import static junitparams.JUnitParamsRunner.$; import static org.assertj.core.api.Assertions.assertThat; -import java.net.URL; - -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; -import org.apache.logging.log4j.Level; -import org.junit.Before; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.message.MessageFactory; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; +import org.junit.rules.TestName; -import org.apache.geode.internal.ClassPathLoader; -import org.apache.geode.internal.logging.log4j.AppenderContext; +import org.apache.geode.LogWriter; +import org.apache.geode.internal.logging.log4j.FastLogger; +import org.apache.geode.internal.logging.log4j.LogWriterLogger; +import org.apache.geode.internal.logging.log4j.message.GemFireParameterizedMessageFactory; import org.apache.geode.test.junit.categories.LoggingTest; /** - * Unit tests for LogService + * Unit tests for {@link LogService}. */ -@RunWith(JUnitParamsRunner.class) @Category(LoggingTest.class) public class LogServiceTest { - private URL defaultConfigUrl; - private URL cliConfigUrl; + private static final String APPLICATION_LOGGER_NAME = "com.application"; @Rule - public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + public TestName testName = new TestName(); + + @Test + public void getLoggerReturnsFastLogger() { + assertThat(LogService.getLogger()).isInstanceOf(FastLogger.class); + } + + @Test + public void getLoggerReturnsLoggerWithCallerClassName() { + assertThat(LogService.getLogger().getName()).isEqualTo(getClass().getName()); + } + + @Test + public void getLoggerReturnsLoggerWithGeodeMessageFactory() { + Logger logger = LogService.getLogger(); + + MessageFactory messageFactory = logger.getMessageFactory(); + assertThat(messageFactory).isInstanceOf(GemFireParameterizedMessageFactory.class); + } - @Before - public void setUp() { - defaultConfigUrl = LogService.class.getResource(LogService.DEFAULT_CONFIG); - cliConfigUrl = LogService.class.getResource(LogService.CLI_CONFIG); + @Test + public void getLoggerNameReturnsLoggerWithSpecifiedName() { + assertThat(LogService.getLogger(APPLICATION_LOGGER_NAME).getName()) + .isEqualTo(APPLICATION_LOGGER_NAME); } @Test - public void getAppenderContextShouldHaveEmptyName() { - final AppenderContext appenderContext = LogService.getAppenderContext(); + public void getLoggerNameReturnsLoggerWithGeodeMessageFactory() { + Logger logger = LogService.getLogger(APPLICATION_LOGGER_NAME); - assertThat(appenderContext.getName()).isEmpty(); + MessageFactory messageFactory = logger.getMessageFactory(); + assertThat(messageFactory).isInstanceOf(GemFireParameterizedMessageFactory.class); } @Test - public void getAppenderContextWithNameShouldHaveName() { - final String name = "someName"; - final AppenderContext appenderContext = LogService.getAppenderContext(name); + public void createLogWriterLoggerReturnsFastLogger() { + LogWriterLogger logWriterLogger = + LogService.createLogWriterLogger(getClass().getName(), testName.getMethodName(), false); - assertThat(appenderContext.getName()).isEqualTo(name); + assertThat(logWriterLogger).isInstanceOf(FastLogger.class); } @Test - @Parameters(method = "getToLevelParameters") - public void toLevelShouldReturnMatchingLog4jLevel(final int intLevel, final Level level) { - assertThat(LogService.toLevel(intLevel)).isSameAs(level); + public void createLogWriterLoggerReturnsLogWriter() { + LogWriterLogger logWriterLogger = + LogService.createLogWriterLogger(getClass().getName(), testName.getMethodName(), false); + + assertThat(logWriterLogger).isInstanceOf(LogWriter.class); } @Test - public void cliConfigLoadsAsResource() { - assertThat(cliConfigUrl).isNotNull(); - assertThat(cliConfigUrl.toString()).contains(LogService.CLI_CONFIG); + public void createLogWriterLoggerReturnsLoggerWithSpecifiedName() { + LogWriterLogger logWriterLogger = + LogService.createLogWriterLogger(getClass().getName(), testName.getMethodName(), false); + + assertThat(logWriterLogger.getName()).isEqualTo(getClass().getName()); } @Test - public void defaultConfigLoadsAsResource() { - assertThat(defaultConfigUrl).isNotNull(); - assertThat(defaultConfigUrl.toString()).contains(LogService.DEFAULT_CONFIG); + public void createLogWriterLoggerReturnsLoggerWithSpecifiedConnectionName() { + LogWriterLogger logWriterLogger = + LogService.createLogWriterLogger(getClass().getName(), testName.getMethodName(), false); + + assertThat(logWriterLogger.getConnectionName()).isEqualTo(testName.getMethodName()); } @Test - public void defaultConfigShouldBeLoadableAsResource() { - final URL configUrlFromLogService = LogService.class.getResource(LogService.DEFAULT_CONFIG); - final URL configUrlFromClassLoader = - getClass().getClassLoader().getResource(LogService.DEFAULT_CONFIG.substring(1)); - final URL configUrlFromClassPathLoader = - ClassPathLoader.getLatest().getResource(LogService.DEFAULT_CONFIG.substring(1)); - - assertThat(configUrlFromLogService).isNotNull(); - assertThat(configUrlFromClassLoader).isNotNull(); - assertThat(configUrlFromClassPathLoader).isNotNull(); - assertThat(configUrlFromLogService).isEqualTo(configUrlFromClassLoader) - .isEqualTo(configUrlFromClassPathLoader); + public void createLogWriterLoggerReturnsLoggerWithGeodeMessageFactory() { + LogWriterLogger logWriterLogger = + LogService.createLogWriterLogger(getClass().getName(), testName.getMethodName(), false); + + MessageFactory messageFactory = logWriterLogger.getMessageFactory(); + assertThat(messageFactory).isInstanceOf(GemFireParameterizedMessageFactory.class); } - @SuppressWarnings("unused") - private static Object[] getToLevelParameters() { - return $(new Object[] {0, Level.OFF}, new Object[] {100, Level.FATAL}, - new Object[] {200, Level.ERROR}, new Object[] {300, Level.WARN}, - new Object[] {400, Level.INFO}, new Object[] {500, Level.DEBUG}, - new Object[] {600, Level.TRACE}, new Object[] {Integer.MAX_VALUE, Level.ALL}); + @Test + public void createLogWriterLoggerWithSecureFalseReturnsSecureLogWriter() { + LogWriterLogger logWriterLogger = + LogService.createLogWriterLogger(getClass().getName(), testName.getMethodName(), false); + + assertThat(logWriterLogger.isSecure()).isFalse(); + } + + @Test + public void createLogWriterLoggerWithSecureTrueReturnsSecureLogWriter() { + LogWriterLogger logWriterLogger = + LogService.createLogWriterLogger(getClass().getName(), testName.getMethodName(), true); + + assertThat(logWriterLogger.isSecure()).isTrue(); } } diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/LogWriterLevelTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/LogWriterLevelTest.java index 1bede46e038f..85befabafa56 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/logging/LogWriterLevelTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/LogWriterLevelTest.java @@ -14,25 +14,92 @@ */ package org.apache.geode.internal.logging; +import static org.apache.geode.internal.logging.LogWriterLevel.ALL; +import static org.apache.geode.internal.logging.LogWriterLevel.CONFIG; +import static org.apache.geode.internal.logging.LogWriterLevel.ERROR; +import static org.apache.geode.internal.logging.LogWriterLevel.FINE; +import static org.apache.geode.internal.logging.LogWriterLevel.FINER; +import static org.apache.geode.internal.logging.LogWriterLevel.FINEST; +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.apache.geode.internal.logging.LogWriterLevel.NONE; +import static org.apache.geode.internal.logging.LogWriterLevel.SEVERE; +import static org.apache.geode.internal.logging.LogWriterLevel.WARNING; +import static org.apache.geode.internal.logging.LogWriterLevel.find; import static org.assertj.core.api.Assertions.assertThat; import java.io.Serializable; import org.apache.commons.lang3.SerializationUtils; import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link LogWriterLevel}. + */ +@Category(LoggingTest.class) public class LogWriterLevelTest { @Test public void isSerializable() { - assertThat(LogWriterLevel.ALL).isInstanceOf(Serializable.class); + assertThat(ALL).isInstanceOf(Serializable.class); } @Test public void serializes() { - LogWriterLevel logLevel = (LogWriterLevel) SerializationUtils.clone(LogWriterLevel.ALL); + LogWriterLevel logLevel = (LogWriterLevel) SerializationUtils.clone(ALL); + + assertThat(logLevel).isEqualTo(ALL).isSameAs(ALL); + } + + @Test + public void findNONE() { + assertThat(find(NONE.intLevel())).isEqualTo(NONE); + } + + @Test + public void findSEVERE() { + assertThat(find(SEVERE.intLevel())).isEqualTo(SEVERE); + } + + @Test + public void findERROR() { + assertThat(find(ERROR.intLevel())).isEqualTo(ERROR); + } - assertThat(logLevel).isEqualTo(LogWriterLevel.ALL).isSameAs(LogWriterLevel.ALL); + @Test + public void findWARNING() { + assertThat(find(WARNING.intLevel())).isEqualTo(WARNING); } + @Test + public void findINFO() { + assertThat(find(INFO.intLevel())).isEqualTo(INFO); + } + + @Test + public void findCONFIG() { + assertThat(find(CONFIG.intLevel())).isEqualTo(CONFIG); + } + + @Test + public void findFINE() { + assertThat(find(FINE.intLevel())).isEqualTo(FINE); + } + + @Test + public void findFINER() { + assertThat(find(FINER.intLevel())).isEqualTo(FINER); + } + + @Test + public void findFINEST() { + assertThat(find(FINEST.intLevel())).isEqualTo(FINEST); + } + + @Test + public void findALL() { + assertThat(find(ALL.intLevel())).isEqualTo(ALL); + } } diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/LoggingSessionTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/LoggingSessionTest.java new file mode 100644 index 000000000000..22e88c5d2543 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/LoggingSessionTest.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.LogWriterLevel.INFO; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.File; + +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.mockito.InOrder; + +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link LoggingSession}. + */ +@Category(LoggingTest.class) +public class LoggingSessionTest { + + private LoggingSessionListeners loggingSessionListeners; + private LogConfigSupplier logConfigSupplier; + private Configuration configuration; + + private LoggingSession loggingSession; + + @Before + public void setUp() { + loggingSessionListeners = spy(new LoggingSessionListeners()); + logConfigSupplier = spy(LogConfigSupplier.class); + configuration = spy(Configuration.create()); + LogConfig config = mock(LogConfig.class); + + when(logConfigSupplier.getLogConfig()).thenReturn(config); + when(config.getLogFile()).thenReturn(new File("")); + when(config.getLogLevel()).thenReturn(INFO.intLevel()); + when(config.getSecurityLogLevel()).thenReturn(INFO.intLevel()); + + loggingSession = LoggingSession.create(configuration, loggingSessionListeners); + } + + @Test + public void createUsesLoggingSessionListenersGetByDefault() { + loggingSession = LoggingSession.create(); + + assertThat(loggingSession.getLoggingSessionListeners()) + .isEqualTo(LoggingSessionListeners.get()); + } + + @Test + public void createSessionInitializesConfiguration() { + loggingSession.createSession(logConfigSupplier); + + verify(configuration).initialize(eq(logConfigSupplier)); + } + + @Test + public void createSessionInvokesConfigChangedOnConfiguration() { + loggingSession.createSession(logConfigSupplier); + + verify(configuration).configChanged(); + } + + @Test + public void createSessionPublishesConfiguration() { + loggingSession.createSession(logConfigSupplier); + loggingSession.startSession(); + + verify(configuration).initialize(eq(logConfigSupplier)); + verify(configuration).configChanged(); + } + + @Test + public void createSessionPublishesConfigBeforeCreatingLoggingSession() { + loggingSession.createSession(logConfigSupplier); + + InOrder inOrder = inOrder(configuration, loggingSessionListeners); + inOrder.verify(configuration).initialize(eq(logConfigSupplier)); + inOrder.verify(configuration).configChanged(); + inOrder.verify(loggingSessionListeners).createSession(eq(loggingSession)); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void createSessionChangesStateToCREATED() { + loggingSession.createSession(logConfigSupplier); + + assertThat(loggingSession.getState()).isSameAs(LoggingSession.State.CREATED); + } + + @Test + public void createSessionNotifiesLoggingSessionListeners() { + loggingSession.createSession(logConfigSupplier); + + verify(loggingSessionListeners).createSession(eq(loggingSession)); + } + + @Test + public void createSessionThrowsIfSessionAlreadyCreated() { + loggingSession.createSession(logConfigSupplier); + + assertThatThrownBy(() -> loggingSession.createSession(logConfigSupplier)) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void createSessionThrowsIfSessionAlreadyStarted() { + loggingSession.createSession(logConfigSupplier); + loggingSession.startSession(); + + assertThatThrownBy(() -> loggingSession.createSession(logConfigSupplier)) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void startSessionNotifiesListeners() { + loggingSession.createSession(logConfigSupplier); + + loggingSession.startSession(); + + verify(loggingSessionListeners).startSession(); + } + + @Test + public void startSessionThrowsIfSessionNotCreated() { + assertThatThrownBy(() -> loggingSession.startSession()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void startSessionThrowsIfSessionStopped() { + loggingSession.createSession(logConfigSupplier); + loggingSession.startSession(); + loggingSession.stopSession(); + + assertThatThrownBy(() -> loggingSession.startSession()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void startSessionThrowsIfSessionAlreadyStarted() { + loggingSession.createSession(logConfigSupplier); + loggingSession.startSession(); + + assertThatThrownBy(() -> loggingSession.startSession()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void stopSessionNotifiesListeners() { + loggingSession.createSession(logConfigSupplier); + loggingSession.startSession(); + + loggingSession.stopSession(); + + verify(loggingSessionListeners).stopSession(); + } + + @Test + public void stopSessionThrowsIfSessionNotCreated() { + assertThatThrownBy(() -> loggingSession.stopSession()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void stopSessionThrowsIfSessionNotStarted() { + loggingSession.createSession(logConfigSupplier); + + assertThatThrownBy(() -> loggingSession.stopSession()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void stopSessionThrowsIfSessionAlreadyStopped() { + loggingSession.createSession(logConfigSupplier); + loggingSession.startSession(); + loggingSession.stopSession(); + + assertThatThrownBy(() -> loggingSession.stopSession()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void shutdownInvokesConfigurationShutdown() { + loggingSession.shutdown(); + + verify(configuration).shutdown(); + } + + @Test + public void shutdownCleansUpConfiguration() { + loggingSession.createSession(logConfigSupplier); + + loggingSession.shutdown(); + + verify(configuration).shutdown(); + } +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/ManagerLogWriterTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/ManagerLogWriterTest.java new file mode 100644 index 000000000000..8f3a229f6257 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/ManagerLogWriterTest.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging; + +import static org.apache.geode.internal.logging.InternalLogWriter.CONFIG_LEVEL; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.PrintStream; + +import org.apache.logging.log4j.core.util.NullOutputStream; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link ManagerLogWriter}. + */ +@Category(LoggingTest.class) +public class ManagerLogWriterTest { + + @Test + public void logWriterLevelIsPassedIntoConstructor() { + ManagerLogWriter logWriter = + new ManagerLogWriter(CONFIG_LEVEL, new PrintStream(NullOutputStream.getInstance()), true); + + assertThat(logWriter.getLogWriterLevel()).isEqualTo(CONFIG_LEVEL); + } +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogLevelTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogLevelTest.java index 9b515fc1fd81..70819abee22b 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogLevelTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogLevelTest.java @@ -24,11 +24,14 @@ import org.apache.geode.internal.logging.LogWriterLevel; import org.apache.geode.test.junit.categories.LoggingTest; +/** + * Unit tests for {@link LogLevel}. + */ @Category(LoggingTest.class) public class LogLevelTest { @Test - public void getLevel_log4J2LevelName_returnsLevel() { + public void getLevel_levelName_returnsLevel() { assertThat(LogLevel.getLevel(Level.OFF.name())).isEqualTo(Level.OFF); assertThat(LogLevel.getLevel(Level.FATAL.name())).isEqualTo(Level.FATAL); assertThat(LogLevel.getLevel(Level.ERROR.name())).isEqualTo(Level.ERROR); @@ -40,7 +43,7 @@ public void getLevel_log4J2LevelName_returnsLevel() { } @Test - public void getLevel_log4J2LevelName_toLowerCase_returnsLevel() { + public void getLevel_levelName_toLowerCase_returnsLevel() { assertThat(LogLevel.getLevel(Level.OFF.name().toLowerCase())).isEqualTo(Level.OFF); assertThat(LogLevel.getLevel(Level.FATAL.name().toLowerCase())).isEqualTo(Level.FATAL); assertThat(LogLevel.getLevel(Level.ERROR.name().toLowerCase())).isEqualTo(Level.ERROR); @@ -52,7 +55,7 @@ public void getLevel_log4J2LevelName_toLowerCase_returnsLevel() { } @Test - public void getLevel_log4J2LevelName_toUpperCase_returnsLevel() { + public void getLevel_levelName_toUpperCase_returnsLevel() { assertThat(LogLevel.getLevel(Level.OFF.name().toUpperCase())).isEqualTo(Level.OFF); assertThat(LogLevel.getLevel(Level.FATAL.name().toUpperCase())).isEqualTo(Level.FATAL); assertThat(LogLevel.getLevel(Level.ERROR.name().toUpperCase())).isEqualTo(Level.ERROR); @@ -117,7 +120,7 @@ public void getLevel_nonLevel_returnsNull() { } @Test - public void resolveLevel_log4J2LevelName_returnsLevel() { + public void resolveLevel_levelName_returnsLevel() { assertThat(LogLevel.resolveLevel(Level.OFF.name())).isEqualTo(Level.OFF); assertThat(LogLevel.resolveLevel(Level.FATAL.name())).isEqualTo(Level.FATAL); assertThat(LogLevel.resolveLevel(Level.ERROR.name())).isEqualTo(Level.ERROR); @@ -129,7 +132,7 @@ public void resolveLevel_log4J2LevelName_returnsLevel() { } @Test - public void resolveLevel_log4J2LevelName_toLowerCase_returnsLevel() { + public void resolveLevel_levelName_toLowerCase_returnsLevel() { assertThat(LogLevel.resolveLevel(Level.OFF.name().toLowerCase())).isEqualTo(Level.OFF); assertThat(LogLevel.resolveLevel(Level.FATAL.name().toLowerCase())).isEqualTo(Level.FATAL); assertThat(LogLevel.resolveLevel(Level.ERROR.name().toLowerCase())).isEqualTo(Level.ERROR); @@ -141,7 +144,7 @@ public void resolveLevel_log4J2LevelName_toLowerCase_returnsLevel() { } @Test - public void resolveLevel_log4J2LevelName_toUpperCase_returnsLevel() { + public void resolveLevel_levelName_toUpperCase_returnsLevel() { assertThat(LogLevel.resolveLevel(Level.OFF.name().toUpperCase())).isEqualTo(Level.OFF); assertThat(LogLevel.resolveLevel(Level.FATAL.name().toUpperCase())).isEqualTo(Level.FATAL); assertThat(LogLevel.resolveLevel(Level.ERROR.name().toUpperCase())).isEqualTo(Level.ERROR); @@ -218,185 +221,135 @@ public void resolveLevel_nonLevel_returnsOff() { } @Test - public void getLog4jLevel_logWriterLevel_returnsLevel() { - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.NONE.getLogWriterLevel())) - .isEqualTo(Level.OFF); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.SEVERE.getLogWriterLevel())) - .isEqualTo(Level.FATAL); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.ERROR.getLogWriterLevel())) - .isEqualTo(Level.ERROR); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.WARNING.getLogWriterLevel())) - .isEqualTo(Level.WARN); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.INFO.getLogWriterLevel())) - .isEqualTo(Level.INFO); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.CONFIG.getLogWriterLevel())) - .isEqualTo(Level.INFO); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.FINE.getLogWriterLevel())) - .isEqualTo(Level.DEBUG); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.FINER.getLogWriterLevel())) - .isEqualTo(Level.TRACE); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.FINEST.getLogWriterLevel())) - .isEqualTo(Level.TRACE); - assertThat(LogLevel.getLog4jLevel(LogWriterLevel.ALL.getLogWriterLevel())).isEqualTo(Level.ALL); - } - - @Test - public void getLog4jLevel_nonLevel_throwsIllegalArgumentException() { - assertThatThrownBy(() -> LogLevel.getLog4jLevel(123123123)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Unknown LogWriter level"); - } - - @Test - public void getLogWriterLevel_log4j2Level_returnsLogWriterLevelValue() { - assertThat(LogLevel.getLogWriterLevel(Level.OFF)) - .isEqualTo(LogWriterLevel.NONE.getLogWriterLevel()); - assertThat(LogLevel.getLogWriterLevel(Level.FATAL)) - .isEqualTo(LogWriterLevel.SEVERE.getLogWriterLevel()); - assertThat(LogLevel.getLogWriterLevel(Level.ERROR)) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); - assertThat(LogLevel.getLogWriterLevel(Level.WARN)) - .isEqualTo(LogWriterLevel.WARNING.getLogWriterLevel()); - assertThat(LogLevel.getLogWriterLevel(Level.INFO)) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); - assertThat(LogLevel.getLogWriterLevel(Level.DEBUG)) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); - assertThat(LogLevel.getLogWriterLevel(Level.TRACE)) - .isEqualTo(LogWriterLevel.FINEST.getLogWriterLevel()); - assertThat(LogLevel.getLogWriterLevel(Level.ALL)) - .isEqualTo(LogWriterLevel.ALL.getLogWriterLevel()); - } - - @Test - public void getLogWriterLevel_log4j2LevelName_returnsLogWriterLevelValue() { + public void getLogWriterLevel_levelName_returnsLogWriterLevelValue() { assertThat(LogLevel.getLogWriterLevel(Level.OFF.name())) - .isEqualTo(LogWriterLevel.NONE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.NONE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.FATAL.name())) - .isEqualTo(LogWriterLevel.SEVERE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.SEVERE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.ERROR.name())) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ERROR.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.WARN.name())) - .isEqualTo(LogWriterLevel.WARNING.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.WARNING.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.INFO.name())) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.INFO.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.DEBUG.name())) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.TRACE.name())) - .isEqualTo(LogWriterLevel.FINEST.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINEST.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.ALL.name())) - .isEqualTo(LogWriterLevel.ALL.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ALL.intLevel()); } @Test - public void getLogWriterLevel_log4j2LevelName_toLowerCase_returnsLogWriterLevelValue() { + public void getLogWriterLevel_levelName_toLowerCase_returnsLogWriterLevelValue() { assertThat(LogLevel.getLogWriterLevel(Level.OFF.name().toLowerCase())) - .isEqualTo(LogWriterLevel.NONE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.NONE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.FATAL.name().toLowerCase())) - .isEqualTo(LogWriterLevel.SEVERE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.SEVERE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.ERROR.name().toLowerCase())) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ERROR.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.WARN.name().toLowerCase())) - .isEqualTo(LogWriterLevel.WARNING.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.WARNING.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.INFO.name().toLowerCase())) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.INFO.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.DEBUG.name().toLowerCase())) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.TRACE.name().toLowerCase())) - .isEqualTo(LogWriterLevel.FINEST.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINEST.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.ALL.name().toLowerCase())) - .isEqualTo(LogWriterLevel.ALL.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ALL.intLevel()); } @Test - public void getLogWriterLevel_log4j2LevelName_toUpperCase_returnsLogWriterLevelValue() { + public void getLogWriterLevel_levelName_toUpperCase_returnsLogWriterLevelValue() { assertThat(LogLevel.getLogWriterLevel(Level.OFF.name().toUpperCase())) - .isEqualTo(LogWriterLevel.NONE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.NONE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.FATAL.name().toUpperCase())) - .isEqualTo(LogWriterLevel.SEVERE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.SEVERE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.ERROR.name().toUpperCase())) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ERROR.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.WARN.name().toUpperCase())) - .isEqualTo(LogWriterLevel.WARNING.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.WARNING.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.INFO.name().toUpperCase())) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.INFO.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.DEBUG.name().toUpperCase())) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINE.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.TRACE.name().toUpperCase())) - .isEqualTo(LogWriterLevel.FINEST.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINEST.intLevel()); assertThat(LogLevel.getLogWriterLevel(Level.ALL.name().toUpperCase())) - .isEqualTo(LogWriterLevel.ALL.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ALL.intLevel()); } @Test public void getLogWriterLevel_logWriterLevelName_returnsLogWriterLevelValue() { assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.NONE.name())) - .isEqualTo(LogWriterLevel.NONE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.NONE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.SEVERE.name())) - .isEqualTo(LogWriterLevel.SEVERE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.SEVERE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.ERROR.name())) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ERROR.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.WARNING.name())) - .isEqualTo(LogWriterLevel.WARNING.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.WARNING.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.CONFIG.name())) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.CONFIG.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.INFO.name())) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.INFO.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINE.name())) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINER.name())) - .isEqualTo(LogWriterLevel.FINER.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINER.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINEST.name())) - .isEqualTo(LogWriterLevel.FINEST.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINEST.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.ALL.name())) - .isEqualTo(LogWriterLevel.ALL.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ALL.intLevel()); } @Test public void getLogWriterLevel_logWriterLevelName_toLowerCase_returnsLogWriterLevelValue() { assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.NONE.name().toLowerCase())) - .isEqualTo(LogWriterLevel.NONE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.NONE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.SEVERE.name().toLowerCase())) - .isEqualTo(LogWriterLevel.SEVERE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.SEVERE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.ERROR.name().toLowerCase())) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ERROR.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.WARNING.name().toLowerCase())) - .isEqualTo(LogWriterLevel.WARNING.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.WARNING.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.INFO.name().toLowerCase())) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.INFO.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.CONFIG.name().toLowerCase())) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.CONFIG.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINE.name().toLowerCase())) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINER.name().toLowerCase())) - .isEqualTo(LogWriterLevel.FINER.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINER.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINEST.name().toLowerCase())) - .isEqualTo(LogWriterLevel.FINEST.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINEST.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.ALL.name().toLowerCase())) - .isEqualTo(LogWriterLevel.ALL.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ALL.intLevel()); } @Test public void getLogWriterLevel_logWriterLevelName_toUpperCase_returnsLogWriterLevelValue() { assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.NONE.name().toUpperCase())) - .isEqualTo(LogWriterLevel.NONE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.NONE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.SEVERE.name().toUpperCase())) - .isEqualTo(LogWriterLevel.SEVERE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.SEVERE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.ERROR.name().toUpperCase())) - .isEqualTo(LogWriterLevel.ERROR.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ERROR.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.WARNING.name().toUpperCase())) - .isEqualTo(LogWriterLevel.WARNING.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.WARNING.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.INFO.name().toUpperCase())) - .isEqualTo(LogWriterLevel.INFO.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.INFO.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.CONFIG.name().toUpperCase())) - .isEqualTo(LogWriterLevel.CONFIG.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.CONFIG.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINE.name().toUpperCase())) - .isEqualTo(LogWriterLevel.FINE.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINE.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINER.name().toUpperCase())) - .isEqualTo(LogWriterLevel.FINER.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINER.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.FINEST.name().toUpperCase())) - .isEqualTo(LogWriterLevel.FINEST.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.FINEST.intLevel()); assertThat(LogLevel.getLogWriterLevel(LogWriterLevel.ALL.name().toUpperCase())) - .isEqualTo(LogWriterLevel.ALL.getLogWriterLevel()); + .isEqualTo(LogWriterLevel.ALL.intLevel()); } @Test @@ -421,8 +374,6 @@ public void getLogWriterLevel_null_throwsIllegalArgumentException() { @Test public void getLogWriterLevel_test_returns() { assertThatThrownBy(() -> LogLevel.getLogWriterLevel("test")) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage( - "Unknown log-level \"test\". Valid levels are: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL."); + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverterTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverterTest.java new file mode 100644 index 000000000000..2c1109bdbb70 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/LogWriterLevelConverterTest.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.apache.geode.internal.logging.log4j.LogWriterLevelConverter.fromLevel; +import static org.apache.geode.internal.logging.log4j.LogWriterLevelConverter.toLevel; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.apache.logging.log4j.Level; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.internal.logging.LogWriterLevel; +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link LogWriterLevelConverter}. + */ +@Category(LoggingTest.class) +public class LogWriterLevelConverterTest { + + @Test + public void toLevel_LogWriterLevelAll_returnsLevelAll() { + assertThat(toLevel(LogWriterLevel.ALL)).isEqualTo(Level.ALL); + } + + @Test + public void toLevel_LogWriterLevelSevere_returnsLevelFatal() { + assertThat(toLevel(LogWriterLevel.SEVERE)).isEqualTo(Level.FATAL); + } + + @Test + public void toLevel_LogWriterLevelError_returnsLevelFatal() { + assertThat(toLevel(LogWriterLevel.ERROR)).isEqualTo(Level.ERROR); + } + + @Test + public void toLevel_LogWriterLevelWarning_returnsLevelFatal() { + assertThat(toLevel(LogWriterLevel.WARNING)).isEqualTo(Level.WARN); + } + + @Test + public void toLevel_LogWriterLevelInfo_returnsLevelInfo() { + assertThat(toLevel(LogWriterLevel.INFO)).isEqualTo(Level.INFO); + } + + @Test + public void toLevel_LogWriterLevelConfig_returnsLevelInfo() { + assertThat(toLevel(LogWriterLevel.CONFIG)).isEqualTo(Level.INFO); + } + + @Test + public void toLevel_LogWriterLevelFine_returnsLevelInfo() { + assertThat(toLevel(LogWriterLevel.FINE)).isEqualTo(Level.DEBUG); + } + + @Test + public void toLevel_LogWriterLevelFiner_returnsLevelInfo() { + assertThat(toLevel(LogWriterLevel.FINER)).isEqualTo(Level.TRACE); + } + + @Test + public void toLevel_LogWriterLevelFinest_returnsLevelInfo() { + assertThat(toLevel(LogWriterLevel.FINEST)).isEqualTo(Level.TRACE); + } + + @Test + public void toLevel_LogWriterLevelOff_returnsLevelFatal() { + assertThat(toLevel(LogWriterLevel.NONE)).isEqualTo(Level.OFF); + } + + @Test + public void toLogWriterLevel_LevelAll_returnsLogWriterLevelAll() { + assertThat(fromLevel(Level.ALL)).isEqualTo(LogWriterLevel.ALL); + } + + @Test + public void toLogWriterLevel_LevelFatal_returnsLogWriterLevelSevere() { + assertThat(fromLevel(Level.FATAL)).isEqualTo(LogWriterLevel.SEVERE); + } + + @Test + public void toLogWriterLevel_LevelError_returnsLogWriterLevelError() { + assertThat(fromLevel(Level.ERROR)).isEqualTo(LogWriterLevel.ERROR); + } + + @Test + public void toLogWriterLevel_LevelWarn_returnsLogWriterLevelWarning() { + assertThat(fromLevel(Level.WARN)).isEqualTo(LogWriterLevel.WARNING); + } + + @Test + public void toLogWriterLevel_LevelInfo_returnsLogWriterLevelInfo() { + assertThat(fromLevel(Level.INFO)).isEqualTo(LogWriterLevel.INFO); + } + + @Test + public void toLogWriterLevel_LevelDebug_returnsLogWriterLevelFine() { + assertThat(fromLevel(Level.DEBUG)).isEqualTo(LogWriterLevel.FINE); + } + + @Test + public void toLogWriterLevel_LevelTrace_returnsLogWriterLevelFinest() { + assertThat(fromLevel(Level.TRACE)).isEqualTo(LogWriterLevel.FINEST); + } + + @Test + public void toLogWriterLevel_LevelOff_returnsLogWriterLevelNone() { + assertThat(fromLevel(Level.OFF)).isEqualTo(LogWriterLevel.NONE); + } + + @Test + public void getLog4jLevel_nonLevel_throwsIllegalArgumentException() { + assertThatThrownBy(() -> toLevel(LogWriterLevel.find(123123123))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("No LogWriterLevel found for intLevel 123123123"); + } + +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverterTest.java b/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverterTest.java new file mode 100644 index 000000000000..27049d1e32a0 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/logging/log4j/MemberNamePatternConverterTest.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.logging.log4j; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TestName; + +import org.apache.geode.test.junit.categories.LoggingTest; + +/** + * Unit tests for {@link MemberNamePatternConverter}. + */ +@Category(LoggingTest.class) +public class MemberNamePatternConverterTest { + + private MemberNamePatternConverter converter; + private MemberNameSupplier supplier; + private String name; + private StringBuilder toAppendTo; + + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() { + converter = MemberNamePatternConverter.INSTANCE; + supplier = converter.getMemberNameSupplier(); + name = testName.getMethodName(); + toAppendTo = new StringBuilder(); + } + + @Test + public void appendsMemberName() { + supplier.set(name); + + converter.format(null, toAppendTo); + + assertThat(toAppendTo.toString()).isEqualTo(name); + } +} diff --git a/geode-core/src/test/resources/org/apache/geode/test/golden/log4j2-test.xml b/geode-core/src/test/resources/org/apache/geode/test/golden/log4j2-test.xml index b7bf618c6626..32eac1a7bf44 100755 --- a/geode-core/src/test/resources/org/apache/geode/test/golden/log4j2-test.xml +++ b/geode-core/src/test/resources/org/apache/geode/test/golden/log4j2-test.xml @@ -15,7 +15,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + [%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%hexTid] %message%n%throwable%n diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/LogWriterUtils.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/LogWriterUtils.java index e48048a9e5bf..d0f15a818ad9 100755 --- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/LogWriterUtils.java +++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/LogWriterUtils.java @@ -81,8 +81,8 @@ public static LogWriter createLogWriter(final Properties properties) { DistributedTestUtils.addHydraProperties(nonDefault); DistributionConfig dc = new DistributionConfigImpl(nonDefault); - LogWriter logger = LogWriterFactory.createLogWriterLogger(false/* isLoner */, - false/* isSecurityLog */, dc, false); + LogWriter logger = LogWriterFactory.createLogWriterLogger(/* isLoner */ + dc, false/* isSecurityLog */); // if config was non-null, then these will be added to it... nonDefault.put(DistributionConfig.LOG_WRITER_NAME, logger); diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java index b1de161d33f5..45bb9a36f247 100644 --- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java +++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java @@ -62,7 +62,7 @@ import org.apache.geode.distributed.internal.InternalLocator; import org.apache.geode.distributed.internal.membership.gms.membership.GMSJoinLeave; import org.apache.geode.internal.AvailablePortHelper; -import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.Configuration; import org.apache.geode.test.dunit.DUnitEnv; import org.apache.geode.test.dunit.Host; import org.apache.geode.test.dunit.SerializableCallable; @@ -288,8 +288,9 @@ private static void addSuspectFileAppender(final String workspaceDir) { final String suspectFilename = new File(workspaceDir, SUSPECT_FILENAME).getAbsolutePath(); final LoggerContext appenderContext = - ((org.apache.logging.log4j.core.Logger) LogManager.getLogger(LogService.BASE_LOGGER_NAME)) - .getContext(); + ((org.apache.logging.log4j.core.Logger) LogManager + .getLogger(Configuration.MAIN_LOGGER_NAME)) + .getContext(); final PatternLayout layout = PatternLayout.createLayout( "[%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%tid] %message%n%throwable%n", @@ -301,7 +302,7 @@ private static void addSuspectFileAppender(final String workspaceDir) { fileAppender.start(); LoggerConfig loggerConfig = - appenderContext.getConfiguration().getLoggerConfig(LogService.BASE_LOGGER_NAME); + appenderContext.getConfiguration().getLoggerConfig(Configuration.MAIN_LOGGER_NAME); loggerConfig.addAppender(fileAppender, Level.INFO, null); } diff --git a/geode-junit/src/main/java/org/apache/geode/internal/logging/TestLogWriterFactory.java b/geode-junit/src/main/java/org/apache/geode/internal/logging/TestLogWriterFactory.java index c687a8715e11..f19783755a38 100644 --- a/geode-junit/src/main/java/org/apache/geode/internal/logging/TestLogWriterFactory.java +++ b/geode-junit/src/main/java/org/apache/geode/internal/logging/TestLogWriterFactory.java @@ -89,9 +89,10 @@ public static LogWriter createLogWriter(final boolean appendToFile, final boolea } if (isSecurityLog) { - mlw = new SecurityManagerLogWriter(config.getSecurityLogLevel(), out, config.getName()); + mlw = + new SecurityManagerLogWriter(config.getSecurityLogLevel(), out, config.getName(), true); } else { - mlw = new ManagerLogWriter(config.getLogLevel(), out, config.getName()); + mlw = new ManagerLogWriter(config.getLogLevel(), out, config.getName(), true); } ((ManagerLogWriter) mlw).setConfig(config); } diff --git a/geode-dunit/src/main/java/org/apache/geode/management/MXBeanAwaitility.java b/geode-junit/src/main/java/org/apache/geode/management/MXBeanAwaitility.java similarity index 100% rename from geode-dunit/src/main/java/org/apache/geode/management/MXBeanAwaitility.java rename to geode-junit/src/main/java/org/apache/geode/management/MXBeanAwaitility.java diff --git a/geode-junit/src/main/java/org/apache/geode/test/junit/rules/accessible/AccessibleTemporaryFolder.java b/geode-junit/src/main/java/org/apache/geode/test/junit/rules/accessible/AccessibleTemporaryFolder.java new file mode 100644 index 000000000000..d602f16c30db --- /dev/null +++ b/geode-junit/src/main/java/org/apache/geode/test/junit/rules/accessible/AccessibleTemporaryFolder.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.geode.test.junit.rules.accessible; + +import org.junit.rules.TemporaryFolder; + +/** + * Subclass TemporaryFolder in order to invoke protected methods from different package. + */ +public class AccessibleTemporaryFolder extends TemporaryFolder { + + @Override + public void before() throws Throwable { + super.before(); + } + + @Override + public void after() { + super.after(); + } +}