You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by da...@apache.org on 2026/10/06 17:11:07 UTC
(jackrabbit-oak) 01/01: OAK-12439: restart reconfigured oak-run logging contexts
This is an automated email from the ASF dual-hosted git repository.
rishabhdaim pushed a commit to branch issue/OAK-12439
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit a15c37e80d855fa9ef79adebc138e9a885c28c39
Author: rishabhdaim <ri...@gmail.com>
AuthorDate: Tue Oct 6 22:40:33 2026 +0530
OAK-12439: restart reconfigured oak-run logging contexts
---
.../oak/run/commons/LoggingInitializer.java | 3 +
.../oak/run/commons/LoggingInitializerTest.java | 161 +++++++++++++++++++++
.../src/test/resources/logback-lifecycle.xml | 27 ++++
3 files changed, 191 insertions(+)
diff --git a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/run/commons/LoggingInitializer.java b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/run/commons/LoggingInitializer.java
index e3239fe808..845c792d6d 100644
--- a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/run/commons/LoggingInitializer.java
+++ b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/run/commons/LoggingInitializer.java
@@ -100,6 +100,9 @@ public class LoggingInitializer {
context.reset();
}
configurator.doConfigure(config);
+ if (!context.isStarted()) {
+ context.start();
+ }
} catch (JoranException je) {
// StatusPrinter will handle this
}
diff --git a/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/run/commons/LoggingInitializerTest.java b/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/run/commons/LoggingInitializerTest.java
new file mode 100644
index 0000000000..478e12cae8
--- /dev/null
+++ b/oak-run-commons/src/test/java/org/apache/jackrabbit/oak/run/commons/LoggingInitializerTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.jackrabbit.oak.run.commons;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ScheduledFuture;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.classic.util.ContextInitializer;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.model.Model;
+import ch.qos.logback.core.model.ModelUtil;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tests for {@link LoggingInitializer}.
+ */
+public class LoggingInitializerTest {
+ @Rule
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
+
+ private LoggerContext context;
+ private Model originalConfiguration;
+ private boolean originallyStarted;
+ private String originalWorkDir;
+ private String originalConfigFile;
+
+ @Before
+ public void saveLoggingConfiguration() {
+ context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ originallyStarted = context.isStarted();
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(context);
+ originalConfiguration = configurator.recallSafeConfiguration();
+ originalWorkDir = System.getProperty("oak.workDir");
+ originalConfigFile = System.getProperty(ContextInitializer.CONFIG_FILE_PROPERTY);
+ System.clearProperty(ContextInitializer.CONFIG_FILE_PROPERTY);
+ context.reset();
+ context.start();
+ }
+
+ @After
+ public void restoreLoggingConfiguration() throws Exception {
+ // reset also cancels scanners if a failed initialization left the context stopped.
+ context.reset();
+ restoreProperty("oak.workDir", originalWorkDir);
+ restoreProperty(ContextInitializer.CONFIG_FILE_PROPERTY, originalConfigFile);
+ if (originalConfiguration != null) {
+ ModelUtil.resetForReuse(originalConfiguration);
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(context);
+ configurator.processModel(originalConfiguration);
+ configurator.registerSafeConfiguration(originalConfiguration);
+ } else {
+ new ContextInitializer(context).autoConfig();
+ }
+ context.start();
+ if (!originallyStarted) {
+ context.stop();
+ }
+ }
+
+ @Test
+ public void reinitializationStartsStoppedContext() throws Exception {
+ new LoggingInitializer(temporaryFolder.newFolder(), "lifecycle").init();
+ LoggingInitializer.shutdownLogging();
+ Assert.assertFalse(context.isStarted());
+
+ new LoggingInitializer(temporaryFolder.newFolder(), "lifecycle").init();
+ Assert.assertTrue(context.isStarted());
+ }
+
+ @Test
+ public void repeatedShutdownStopsAppendersAndScanners() throws Exception {
+ for (int i = 0; i < 2; i++) {
+ File workDir = temporaryFolder.newFolder();
+ new LoggingInitializer(workDir, "lifecycle").init();
+ Appender<ILoggingEvent> appender = context.getLogger(Logger.ROOT_LOGGER_NAME).getAppender("file");
+ Assert.assertNotNull(appender);
+ Assert.assertTrue(appender.isStarted());
+ Assert.assertTrue(new File(workDir, "lifecycle.log").isFile());
+ List<ScheduledFuture<?>> scanners = new ArrayList<>(context.getCopyOfScheduledFutures());
+ Assert.assertFalse(scanners.isEmpty());
+
+ LoggingInitializer.shutdownLogging();
+
+ Assert.assertFalse("shutdown must close the file appender", appender.isStarted());
+ for (ScheduledFuture<?> scanner : scanners) {
+ Assert.assertTrue("shutdown must cancel configuration scanning", scanner.isCancelled());
+ }
+ Assert.assertFalse(context.isStarted());
+ }
+ }
+
+ @Test
+ public void initializationWithoutResetStartsStoppedContext() throws Exception {
+ context.stop();
+ new LoggingInitializer(temporaryFolder.newFolder(), "lifecycle", false).init();
+ Assert.assertTrue(context.isStarted());
+ LoggingInitializer.shutdownLogging();
+ Assert.assertTrue(context.getCopyOfScheduledFutures().isEmpty());
+ Assert.assertFalse(context.isStarted());
+ }
+
+ @Test
+ public void customConfigurationSkipsInitializationAndShutdown() throws Exception {
+ File workDir = temporaryFolder.newFolder();
+ new LoggingInitializer(workDir, "lifecycle").init();
+ Appender<ILoggingEvent> appender = context.getLogger(Logger.ROOT_LOGGER_NAME).getAppender("file");
+ List<ScheduledFuture<?>> scanners = new ArrayList<>(context.getCopyOfScheduledFutures());
+ Assert.assertFalse(scanners.isEmpty());
+ String configuredWorkDir = System.getProperty("oak.workDir");
+ System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, new File(workDir, "logback-lifecycle.xml").getAbsolutePath());
+
+ File otherWorkDir = temporaryFolder.newFolder();
+ new LoggingInitializer(otherWorkDir, "lifecycle").init();
+ LoggingInitializer.shutdownLogging();
+
+ Assert.assertFalse(new File(otherWorkDir, "logback-lifecycle.xml").exists());
+ Assert.assertEquals(configuredWorkDir, System.getProperty("oak.workDir"));
+ Assert.assertSame(appender, context.getLogger(Logger.ROOT_LOGGER_NAME).getAppender("file"));
+ Assert.assertTrue(context.isStarted());
+ Assert.assertTrue(appender.isStarted());
+ for (ScheduledFuture<?> scanner : scanners) {
+ Assert.assertFalse(scanner.isCancelled());
+ }
+ }
+
+ private static void restoreProperty(String name, String value) {
+ if (value == null) {
+ System.clearProperty(name);
+ } else {
+ System.setProperty(name, value);
+ }
+ }
+}
diff --git a/oak-run-commons/src/test/resources/logback-lifecycle.xml b/oak-run-commons/src/test/resources/logback-lifecycle.xml
new file mode 100644
index 0000000000..29183cded1
--- /dev/null
+++ b/oak-run-commons/src/test/resources/logback-lifecycle.xml
@@ -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.
+-->
+<configuration scan="true" scanPeriod="1 hour">
+ <appender name="file" class="ch.qos.logback.core.FileAppender">
+ <file>${oak.workDir}/lifecycle.log</file>
+ <encoder>
+ <pattern>%msg%n</pattern>
+ </encoder>
+ </appender>
+ <root level="INFO">
+ <appender-ref ref="file"/>
+ </root>
+</configuration>