Skip to content

Commit e7764f4

Browse files
committed
refactor file change scanning for clarity
Signed-off-by: ceki <ceki@qos.ch>
1 parent e56a12f commit e7764f4

File tree

16 files changed

+346
-137
lines changed

16 files changed

+346
-137
lines changed

logback-classic-blackbox/src/test/java/ch/qos/logback/classic/blackbox/joran/BlackboxJoranConfiguratorTest.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,33 @@
1414

1515
package ch.qos.logback.classic.blackbox.joran;
1616

17+
import ch.qos.logback.classic.ClassicConstants;
1718
import ch.qos.logback.classic.Level;
1819
import ch.qos.logback.classic.Logger;
1920
import ch.qos.logback.classic.LoggerContext;
2021
import ch.qos.logback.classic.blackbox.BlackboxClassicTestConstants;
2122
import ch.qos.logback.classic.joran.JoranConfigurator;
2223
import ch.qos.logback.classic.jul.JULHelper;
2324
import ch.qos.logback.classic.spi.ILoggingEvent;
25+
import ch.qos.logback.classic.util.DefaultJoranConfigurator;
2426
import ch.qos.logback.classic.util.LogbackMDCAdapter;
2527
import ch.qos.logback.core.joran.spi.JoranException;
2628
import ch.qos.logback.core.read.ListAppender;
2729
import ch.qos.logback.core.testUtil.RandomUtil;
2830
import ch.qos.logback.core.testUtil.StringListAppender;
31+
import ch.qos.logback.core.util.Loader;
2932
import ch.qos.logback.core.util.StatusPrinter;
3033
import org.junit.jupiter.api.Disabled;
3134
import org.junit.jupiter.api.Test;
3235

3336
import java.io.IOException;
37+
import java.io.InputStream;
38+
import java.net.URL;
3439

35-
import static org.junit.jupiter.api.Assertions.assertEquals;
36-
import static org.junit.jupiter.api.Assertions.assertNotNull;
37-
import static org.junit.jupiter.api.Assertions.assertNull;
38-
import static org.junit.jupiter.api.Assertions.assertTrue;
40+
import static org.junit.jupiter.api.Assertions.*;
3941

4042
public class BlackboxJoranConfiguratorTest {
43+
4144
LoggerContext loggerContext = new LoggerContext();
4245
LogbackMDCAdapter logbackMDCAdapter = new LogbackMDCAdapter();
4346
Logger logger = loggerContext.getLogger(this.getClass().getName());
@@ -51,9 +54,10 @@ void configure(String file) throws JoranException {
5154
jc.setContext(loggerContext);
5255
loggerContext.putProperty("diff", "" + diff);
5356
jc.doConfigure(file);
54-
5557
}
5658

59+
60+
5761
@Test
5862
public void eval() throws JoranException {
5963
configure(BlackboxClassicTestConstants.JORAN_INPUT_PREFIX + "callerData.xml");
@@ -190,5 +194,21 @@ void verifyJULLevel(String loggerName, Level expectedLevel) {
190194
}
191195
}
192196

197+
// See https://github.com/qos-ch/logback/issues/1001
198+
// See https://github.com/qos-ch/logback/issues/997
199+
@Test
200+
public void fileAsResource() throws JoranException, IOException, InterruptedException {
201+
JoranConfigurator joranConfigurator = new JoranConfigurator();
202+
joranConfigurator.setContext(loggerContext);
203+
ClassLoader classLoader = Loader.getClassLoaderOfObject(joranConfigurator);
204+
String logbackConfigFile = "asResource/topFile.xml";
205+
URL aURL = Loader.getResource(logbackConfigFile, classLoader);
206+
InputStream inputStream = aURL.openStream();
207+
assertNotNull(inputStream);
208+
joranConfigurator.doConfigure(inputStream);
209+
StatusPrinter.print(loggerContext);
210+
checker.assertIsWarningOrErrorFree();
211+
fail();
212+
}
193213

194214
}

logback-classic-blackbox/src/test/java/ch/qos/logback/classic/blackbox/joran/ReconfigureOnChangeTaskTest.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ public void checkBasicLifecyle() throws JoranException, IOException, Interrupted
9898
configure(file);
9999
List<File> fileList = getConfigurationWatchList(loggerContext);
100100
assertThatListContainsFile(fileList, file);
101-
statusPrinter2.print(loggerContext);
102101
checkThatTaskHasRan();
103102
checkThatTaskCanBeStopped();
104103
}
@@ -203,10 +202,10 @@ public void reconfigurationIsNotPossibleInTheAbsenceOfATopFile() throws IOExcept
203202
configure(asBAIS(configurationStr));
204203

205204
ConfigurationWatchList configurationWatchList = ConfigurationWatchListUtil.getConfigurationWatchList(loggerContext);
206-
assertNull(configurationWatchList);
205+
206+
assertNotNull(configurationWatchList);
207207
assertFalse(ConfigurationWatchListUtil.watchPredicateFulfilled(loggerContext));
208208
statusChecker.containsMatch(Status.WARN, ConfigurationModelHandlerFull.FAILED_WATCH_PREDICATE_MESSAGE_1);
209-
StatusPrinter.print(loggerContext);
210209

211210
assertFalse(listener.changeDetectorRegisteredEventOccurred);
212211
assertEquals(0, loggerContext.getCopyOfScheduledFutures().size());
@@ -222,7 +221,7 @@ public void fallbackToSafe_FollowedByRecovery() throws IOException, JoranExcepti
222221

223222
addResetResistantOnConsoleStatusListener();
224223
configure(topLevelFile);
225-
224+
//statusPrinter2.print(loggerContext);
226225
CountDownLatch changeDetectedLatch = registerChangeDetectedListener();
227226
CountDownLatch configurationDoneLatch = registerNewReconfigurationDoneSuccessfullyListener();
228227

@@ -251,12 +250,13 @@ public void fallbackToSafe_FollowedByRecovery() throws IOException, JoranExcepti
251250
statusChecker.assertIsErrorFree();
252251
statusChecker.containsMatch(DETECTED_CHANGE_IN_CONFIGURATION_FILES);
253252
} finally {
254-
StatusPrinter.print(loggerContext);
253+
//StatusPrinter.print(loggerContext);
255254
}
256255
}
257256

258257
private void addResetResistantOnConsoleStatusListener() {
259-
if (1 == 1)
258+
// enable when debugging
259+
if(1==1)
260260
return;
261261
OnConsoleStatusListener ocs = new OnConsoleStatusListener();
262262
ocs.setContext(loggerContext);
@@ -285,7 +285,6 @@ public void fallbackToSafeWithIncludedFile_FollowedByRecovery() throws IOExcepti
285285

286286
ReconfigureOnChangeTask roct = roctRegisteredListener.reconfigureOnChangeTask;
287287

288-
System.out.println("===================================================");
289288

290289
CountDownLatch changeDetectedLatch = registerChangeDetectedListener();
291290
CountDownLatch configurationDoneLatch = registerNewReconfigurationDoneSuccessfullyListener(roct);
@@ -299,6 +298,8 @@ public void fallbackToSafeWithIncludedFile_FollowedByRecovery() throws IOExcepti
299298
statusChecker.assertContainsMatch(Status.WARN, FALLING_BACK_TO_SAFE_CONFIGURATION);
300299
statusChecker.assertContainsMatch(Status.INFO, RE_REGISTERING_PREVIOUS_SAFE_CONFIGURATION);
301300

301+
//statusPrinter2.print(loggerContext);
302+
302303
loggerContext.getStatusManager().clear();
303304

304305
CountDownLatch secondDoneLatch = registerNewReconfigurationDoneSuccessfullyListener();

logback-classic/src/main/java/ch/qos/logback/classic/joran/ReconfigureOnChangeTask.java

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ public void run() {
6767

6868
context.fireConfigurationEvent(ConfigurationEvent.newConfigurationChangeDetectedEvent(this));
6969
addInfo(DETECTED_CHANGE_IN_CONFIGURATION_FILES);
70-
7170
if(changedFile != null) {
7271
changeInFile(changedFile, configurationWatchList);
7372
}
@@ -84,6 +83,7 @@ private void changeInURL(URL url) {
8483
}
8584
}
8685
private void changeInFile(File changedFile, ConfigurationWatchList configurationWatchList) {
86+
8787
if(changedFile.getName().endsWith(PROPERTIES_FILE_EXTENSION)) {
8888
runPropertiesConfigurator(changedFile);
8989
return;
@@ -92,13 +92,11 @@ private void changeInFile(File changedFile, ConfigurationWatchList configuration
9292
// ======== fuller processing below
9393
addInfo(CoreConstants.RESET_MSG_PREFIX + "named [" + context.getName() + "]");
9494
cancelFutureInvocationsOfThisTaskInstance();
95-
URL mainConfigurationURL = configurationWatchList.getMainURL();
95+
URL mainConfigurationURL = configurationWatchList.getTopURL();
9696

9797
LoggerContext lc = (LoggerContext) context;
9898
if (mainConfigurationURL.toString().endsWith("xml")) {
9999
performXMLConfiguration(lc, mainConfigurationURL);
100-
} else if (mainConfigurationURL.toString().endsWith("groovy")) {
101-
addError("Groovy configuration disabled due to Java 9 compilation issues.");
102100
}
103101
}
104102

@@ -127,50 +125,54 @@ private void cancelFutureInvocationsOfThisTaskInstance() {
127125
}
128126
}
129127

130-
private void performXMLConfiguration(LoggerContext lc, URL mainConfigurationURL) {
128+
private void performXMLConfiguration(LoggerContext loggerContext, URL mainConfigurationURL) {
129+
131130
JoranConfigurator jc = new JoranConfigurator();
132-
jc.setContext(context);
133-
StatusUtil statusUtil = new StatusUtil(context);
131+
jc.setContext(loggerContext);
132+
StatusUtil statusUtil = new StatusUtil(loggerContext);
134133
Model failsafeTop = jc.recallSafeConfiguration();
135-
URL mainURL = ConfigurationWatchListUtil.getMainWatchURL(context);
136-
addInfo("Resetting loggerContext ["+lc.getName()+"]");
137-
lc.reset();
134+
URL topURL = ConfigurationWatchListUtil.getMainWatchURL(context);
135+
addInfo("Resetting loggerContext ["+loggerContext.getName()+"]");
136+
loggerContext.reset();
138137
long threshold = System.currentTimeMillis();
139138
try {
140139
jc.doConfigure(mainConfigurationURL);
141140
// e.g. IncludeAction will add a status regarding XML parsing errors but no exception will reach here
142141
if (statusUtil.hasXMLParsingErrors(threshold)) {
143-
fallbackConfiguration(lc, failsafeTop, mainURL);
142+
fallbackConfiguration(loggerContext, failsafeTop, topURL);
144143
}
145144
} catch (JoranException e) {
146145
addWarn("Exception occurred during reconfiguration", e);
147-
fallbackConfiguration(lc, failsafeTop, mainURL);
146+
fallbackConfiguration(loggerContext, failsafeTop, topURL);
148147
}
149148
}
150149

151-
private void fallbackConfiguration(LoggerContext lc, Model failsafeTop, URL mainURL) {
150+
private void fallbackConfiguration(LoggerContext loggerContext, Model failsafeTopModel, URL topURL) {
152151
// failsafe events are used only in case of errors. Therefore, we must *not*
153152
// invoke file inclusion since the included files may be the cause of the error.
154153

155154
// List<SaxEvent> failsafeEvents = removeIncludeEvents(eventList);
156155
JoranConfigurator joranConfigurator = new JoranConfigurator();
157-
joranConfigurator.setContext(context);
158-
ConfigurationWatchList oldCWL = ConfigurationWatchListUtil.getConfigurationWatchList(context);
159-
ConfigurationWatchList newCWL = oldCWL.buildClone();
156+
joranConfigurator.setContext(loggerContext);
157+
joranConfigurator.setTopURL(topURL);
158+
159+
// ConfigurationWatchList oldCWL = ConfigurationWatchListUtil.getConfigurationWatchList(loggerContext);
160+
// System.out.println("--------oldCWL:"+oldCWL);
161+
// ConfigurationWatchList newCWL = oldCWL.buildClone();
160162

161-
if (failsafeTop == null) {
163+
if (failsafeTopModel == null) {
162164
addWarn("No previous configuration to fall back on.");
163165
return;
164166
} else {
165167
addWarn(FALLING_BACK_TO_SAFE_CONFIGURATION);
166-
addInfo("Safe model "+failsafeTop);
168+
addInfo("Safe model "+failsafeTopModel);
167169
try {
168-
lc.reset();
169-
ConfigurationWatchListUtil.registerConfigurationWatchList(context, newCWL);
170-
ModelUtil.resetForReuse(failsafeTop);
171-
joranConfigurator.processModel(failsafeTop);
170+
loggerContext.reset();
171+
// ConfigurationWatchListUtil.registerConfigurationWatchList(context, newCWL);
172+
ModelUtil.resetForReuse(failsafeTopModel);
173+
joranConfigurator.processModel(failsafeTopModel);
172174
addInfo(RE_REGISTERING_PREVIOUS_SAFE_CONFIGURATION);
173-
joranConfigurator.registerSafeConfiguration(failsafeTop);
175+
joranConfigurator.registerSafeConfiguration(failsafeTopModel);
174176
context.fireConfigurationEvent(newConfigurationEndedSuccessfullyEvent(this));
175177
} catch (Exception e) {
176178
addError("Unexpected exception thrown by a configuration considered safe.", e);

logback-classic/src/main/java/ch/qos/logback/classic/model/PropertiesConfiguratorModel.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,15 @@
1919
public class PropertiesConfiguratorModel extends ResourceModel {
2020

2121
private static final long serialVersionUID = -2009536798661734346L;
22+
23+
String scanStr;
24+
25+
public String getScanStr() {
26+
return scanStr;
27+
}
28+
29+
public void setScanStr(String scanStr) {
30+
this.scanStr = scanStr;
31+
}
32+
2233
}

logback-classic/src/main/java/ch/qos/logback/classic/model/processor/ConfigurationModelHandler.java

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import ch.qos.logback.classic.LoggerContext;
1717
import ch.qos.logback.classic.model.ConfigurationModel;
1818
import ch.qos.logback.core.Context;
19+
import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
1920
import ch.qos.logback.core.model.Model;
2021
import ch.qos.logback.core.model.processor.ModelHandlerBase;
2122
import ch.qos.logback.core.model.processor.ModelHandlerException;
@@ -33,7 +34,7 @@
3334
/**
3435
* In 1.3.9/1.49, ConfigurationModelHandler has been reduced in functionality and no
3536
* longer initiates a reconfiguration task. This change was justified by the need
36-
* to remove java.xml reachability. See also LOGBACK-1717.
37+
* to remove java.xml reachability. See also https://jira.qos.ch/browse/LOGBACK-1717
3738
*
3839
* <p>
3940
* See {@link ConfigurationModelHandlerFull} subclass offering configuration
@@ -44,6 +45,8 @@ public class ConfigurationModelHandler extends ModelHandlerBase {
4445

4546
static final Duration SCAN_PERIOD_DEFAULT = Duration.buildByMinutes(1);
4647

48+
protected Boolean scanning = null;
49+
4750
public ConfigurationModelHandler(Context context) {
4851
super(context);
4952
}
@@ -75,7 +78,18 @@ public void handle(ModelInterpretationContext mic, Model model) {
7578
StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
7679
}
7780

78-
processScanAttrib(mic, configurationModel);
81+
// It is hard to gauge at this stage which URL ares watchable
82+
// However, we know for sure if the user wants scanning or not
83+
this.scanning = scanAttrToBoolean(configurationModel);
84+
85+
mic.setTopScanBoolean(scanning);
86+
87+
printScanMessage(scanning);
88+
89+
if (scanning == Boolean.TRUE) {
90+
ConfigurationWatchListUtil.registerNewConfigurationWatchListWithContext(getContext());
91+
ConfigurationWatchListUtil.setMainWatchURL(context, mic.getTopURL());
92+
}
7993

8094
LoggerContext lc = (LoggerContext) context;
8195
boolean packagingData = OptionHelper.toBoolean(mic.subst(configurationModel.getPackagingDataStr()),
@@ -88,20 +102,47 @@ public void handle(ModelInterpretationContext mic, Model model) {
88102

89103
}
90104

91-
protected void processScanAttrib(ModelInterpretationContext mic, ConfigurationModel configurationModel) {
92-
String scanStr = mic.subst(configurationModel.getScanStr());
93-
if (!OptionHelper.isNullOrEmptyOrAllSpaces(scanStr) && !"false".equalsIgnoreCase(scanStr)) {
94-
addInfo("Skipping ReconfigureOnChangeTask registration");
105+
void printScanMessage(Boolean scanning) {
106+
if (scanning == null) {
107+
addInfo("Scan attribute not set or set to unrecognized value.");
108+
return;
109+
}
110+
if (scanning) {
111+
addInfo("Scan attribute set to true. Will scan for configuration file changes.");
112+
} else {
113+
addInfo("Scan attribute set to false.");
95114
}
96115
}
97116

98-
protected void postProcessScanAttrib(ModelInterpretationContext mic, ConfigurationModel configurationModel) {
99-
100-
}
101117

102118
@Override
103119
public void postHandle(ModelInterpretationContext mic, Model model) throws ModelHandlerException {
104-
ConfigurationModel configurationModel = (ConfigurationModel) model;
120+
//ConfigurationModel configurationModel = (ConfigurationModel) model;
121+
122+
}
123+
124+
/**
125+
* Converts the scan string attribute of the given model to a Boolean value.
126+
*
127+
* <p>If the provided model is an instance of {@code ConfigurationModel}, the scan string is retrieved
128+
* and converted to a {@code Boolean}. If the provided model is not a {@code ConfigurationModel},
129+
* the method returns {@code null}.
130+
* </p>
131+
*
132+
* @param model the model object, which may be an instance of {@code ConfigurationModel}
133+
* @return a {@code Boolean} corresponding to the scan string attribute if the model is
134+
* an instance of {@code ConfigurationModel}, or {@code null} otherwise
135+
*
136+
* @since 1.5.27
137+
*/
138+
private Boolean scanAttrToBoolean(Model model) {
139+
if(model instanceof ConfigurationModel) {
140+
ConfigurationModel configurationModel = (ConfigurationModel) model;
141+
String scanStr = configurationModel.getScanStr();
142+
return OptionHelper.toBooleanObject(scanStr);
143+
} else {
144+
return null;
145+
}
105146

106147
}
107148
}

0 commit comments

Comments
 (0)