Skip to content

Commit

Permalink
LOGBACK-888: Add possibility to mark property file/resource as optional
Browse files Browse the repository at this point in the history
Support attribute "optional" in property element.

Similar to the already existing support in the include element, it
prevents errors loading non-existent property files/resources.
  • Loading branch information
João Costa committed Jul 22, 2021
1 parent b2376cc commit b07a28f
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@
public class PropertyAction extends Action {

static final String RESOURCE_ATTRIBUTE = "resource";
private static final String OPTIONAL_ATTR = "optional";

static String INVALID_ATTRIBUTES = "In <property> element, either the \"file\" attribute alone, or "
+ "the \"resource\" element alone, or both the \"name\" and \"value\" attributes must be set.";
static String INVALID_ATTRIBUTES = "In <property> element, set either both \"name\" and \"value\" attributes, or "
+ "one of \"file\" or \"resource\" (optionally paired with \"optional\").";

/**
* Set a new property for the execution context by name, value pair, or adds
Expand All @@ -69,7 +70,9 @@ public void begin(InterpretationContext ec, String localName, Attributes attribu
FileInputStream istream = new FileInputStream(file);
loadAndSetProperties(ec, istream, scope);
} catch (FileNotFoundException e) {
addError("Could not find properties file [" + file + "].");
if (!OptionHelper.toBoolean(attributes.getValue(OPTIONAL_ATTR), false)) {
addError("Could not find properties file [" + file + "].");
}
} catch (IOException e1) {
addError("Could not read properties file [" + file + "].", e1);
}
Expand All @@ -78,7 +81,9 @@ public void begin(InterpretationContext ec, String localName, Attributes attribu
resource = ec.subst(resource);
URL resourceURL = Loader.getResourceBySelfClassLoader(resource);
if (resourceURL == null) {
addError("Could not find resource [" + resource + "].");
if (!OptionHelper.toBoolean(attributes.getValue(OPTIONAL_ATTR), false)) {
addError("Could not find resource [" + resource + "].");
}
} else {
try {
InputStream istream = resourceURL.openStream();
Expand Down Expand Up @@ -130,6 +135,9 @@ boolean checkValueNameAttributesSanity(Attributes attributes) {
String value = attributes.getValue(VALUE_ATTRIBUTE);
String resource = attributes.getValue(RESOURCE_ATTRIBUTE);

// Note: not checking that the "optional" attribute is empty because there's a risk that doing so would cause
// problems and break existing configuration files.

return (!(OptionHelper.isEmpty(name) || OptionHelper.isEmpty(value)) && (OptionHelper.isEmpty(file) && OptionHelper.isEmpty(resource)));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Iterator;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import ch.qos.logback.core.Context;
import ch.qos.logback.core.ContextBase;
import ch.qos.logback.core.joran.spi.InterpretationContext;
import ch.qos.logback.core.status.ErrorStatus;
import ch.qos.logback.core.status.Status;
import ch.qos.logback.core.util.CoreTestConstants;
import ch.qos.logback.core.util.StatusPrinter;

Expand Down Expand Up @@ -145,18 +141,38 @@ public void testLoadNotPossible() {
atts.setValue("file", "toto");
propertyAction.begin(ec, null, atts);
assertEquals(1, context.getStatusManager().getCount());
assertTrue(checkFileErrors());
assertEquals("Could not find properties file [toto].", getFirstStatusMessage());
}

@Test
public void testLoadOptionalMissingFile() {
atts.setValue("file", "toto");
atts.setValue("optional", "true");
propertyAction.begin(ec, null, atts);
assertEquals(0, context.getStatusManager().getCount());
}

@Test
public void testLoadResourceNotPossible() {
atts.setValue("resource", "toto");
propertyAction.begin(ec, null, atts);
assertEquals(1, context.getStatusManager().getCount());
assertEquals("Could not find resource [toto].", getFirstStatusMessage());
}

@Test
public void testLoadOptionalMissingResource() {
atts.setValue("resource", "toto");
atts.setValue("optional", "true");
propertyAction.begin(ec, null, atts);
assertEquals(0, context.getStatusManager().getCount());
}

private boolean checkError() {
Iterator<Status> it = context.getStatusManager().getCopyOfStatusList().iterator();
ErrorStatus es = (ErrorStatus) it.next();
return PropertyAction.INVALID_ATTRIBUTES.equals(es.getMessage());
return PropertyAction.INVALID_ATTRIBUTES.equals(getFirstStatusMessage());
}

private boolean checkFileErrors() {
Iterator<Status> it = context.getStatusManager().getCopyOfStatusList().iterator();
ErrorStatus es1 = (ErrorStatus) it.next();
return "Could not find properties file [toto].".equals(es1.getMessage());
private String getFirstStatusMessage() {
return context.getStatusManager().getCopyOfStatusList().get(0).getMessage();
}
}
7 changes: 7 additions & 0 deletions logback-site/src/site/pages/manual/configuration.html
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,13 @@ <h4 class="doAnchor" name="definingProps">Defining variables</h4>
&lt;/configuration></pre>


<p>If the specified file or resource cannot be found, logback will
throw an error. In case the included file is optional, you can suppress
that error by setting <span class="attr">optional</span> attribute to
<code>true</code> in the <code>&lt;property&gt;</code> element.</p>

<pre class="prettyprint source">&lt;property <b>optional="true"</b> ... /></pre>

<h4 class="doAnchor" name="scopes">Scopes</h4>

<p>A property can be defined for insertion in <em>local scope</em>,
Expand Down

0 comments on commit b07a28f

Please sign in to comment.