Skip to content

Commit 56be0ab

Browse files
committed
Ensure scripts are processed before their references
Alters AbstractConfiguration to process the Scripts element before other components. This allows ScriptRef elements to be resolved correctly, regardless of their order in the configuration file.
1 parent aa0294d commit 56be0ab

File tree

4 files changed

+95
-18
lines changed

4 files changed

+95
-18
lines changed

log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/AbstractConfigurationTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@
2424
import java.util.Map;
2525
import java.util.Map.Entry;
2626
import org.apache.logging.log4j.core.LoggerContext;
27+
import org.apache.logging.log4j.core.filter.CompositeFilter;
28+
import org.apache.logging.log4j.core.filter.ScriptFilter;
2729
import org.apache.logging.log4j.core.lookup.Interpolator;
2830
import org.apache.logging.log4j.core.lookup.InterpolatorTest;
2931
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
32+
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
33+
import org.apache.logging.log4j.test.junit.SetTestProperty;
3034
import org.junit.jupiter.api.Test;
3135
import org.junit.jupiter.params.ParameterizedTest;
3236
import org.junit.jupiter.params.provider.ValueSource;
3337
import org.junitpioneer.jupiter.Issue;
3438

39+
@SetTestProperty(key = "log4j2.scriptEnableLanguages", value = "groovy")
3540
class AbstractConfigurationTest {
3641

3742
@Test
@@ -60,6 +65,26 @@ void substitutorHasConfigurationAndLoggerContext(final boolean hasProperties) {
6065
}
6166
}
6267

68+
@Test
69+
@LoggerContextSource("log4j2-script-order-test.xml")
70+
void scriptRefShouldBeResolvedWhenScriptsElementIsLast(final Configuration config) {
71+
assertThat(config.getFilter())
72+
.as("Top-level filter should be a CompositeFilter")
73+
.isInstanceOf(CompositeFilter.class);
74+
final CompositeFilter compositeFilter = (CompositeFilter) config.getFilter();
75+
76+
assertThat(compositeFilter.getFilters())
77+
.as("CompositeFilter should contain one filter")
78+
.hasSize(1);
79+
final ScriptFilter scriptFilter =
80+
(ScriptFilter) compositeFilter.getFilters().get(0);
81+
82+
assertThat(scriptFilter).isNotNull();
83+
assertThat(scriptFilter.toString())
84+
.as("Script name should match the one in the config")
85+
.isEqualTo("GLOBAL_FILTER");
86+
}
87+
6388
private static class TestConfiguration extends AbstractConfiguration {
6489

6590
private final Map<String, String> map;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to you under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
<Configuration status="WARN">
19+
<Filters>
20+
<ScriptFilter onMatch="ACCEPT" onMisMatch="DENY">
21+
<ScriptRef ref="GLOBAL_FILTER"/>
22+
</ScriptFilter>
23+
</Filters>
24+
25+
<Scripts>
26+
<Script name="GLOBAL_FILTER" language="groovy"><![CDATA[
27+
// simple script
28+
return true
29+
]]></Script>
30+
</Scripts>
31+
</Configuration>

log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -682,13 +682,14 @@ protected void doConfigure() {
682682
preConfigure(rootNode);
683683
configurationScheduler.start();
684684
// Find the "Properties" node first
685+
final List<Node> children = rootNode.getChildren();
685686
boolean hasProperties = false;
686-
for (final Node node : rootNode.getChildren()) {
687-
if ("Properties".equalsIgnoreCase(node.getName())) {
687+
for (final Node child : children) {
688+
if ("Properties".equalsIgnoreCase(child.getName())) {
688689
hasProperties = true;
689-
createConfiguration(node, null);
690-
if (node.getObject() != null) {
691-
final StrLookup lookup = node.getObject();
690+
createConfiguration(child, null);
691+
if (child.getObject() != null) {
692+
final StrLookup lookup = child.getObject();
692693
runtimeStrSubstitutor.setVariableResolver(lookup);
693694
configurationStrSubstitutor.setVariableResolver(lookup);
694695
}
@@ -705,28 +706,36 @@ protected void doConfigure() {
705706
configurationStrSubstitutor.setVariableResolver(interpolator);
706707
}
707708

709+
for (final Node child : children) {
710+
if ("Scripts".equalsIgnoreCase(child.getName())) {
711+
createConfiguration(child, null);
712+
if (child.getObject() != null) {
713+
for (final AbstractScript script : child.getObject(AbstractScript[].class)) {
714+
if (script instanceof ScriptRef) {
715+
LOGGER.error(
716+
"Script reference to {} not added. Scripts definition cannot contain script references",
717+
script.getName());
718+
} else if (scriptManager != null) {
719+
scriptManager.addScript(script);
720+
}
721+
}
722+
}
723+
break;
724+
}
725+
}
726+
708727
boolean setLoggers = false;
709728
boolean setRoot = false;
710-
for (final Node child : rootNode.getChildren()) {
711-
if ("Properties".equalsIgnoreCase(child.getName())) {
729+
for (final Node child : children) {
730+
if ("Properties".equalsIgnoreCase(child.getName()) || "Scripts".equalsIgnoreCase(child.getName())) {
712731
// We already used this node
713732
continue;
714733
}
715734
createConfiguration(child, null);
716735
if (child.getObject() == null) {
717736
continue;
718737
}
719-
if ("Scripts".equalsIgnoreCase(child.getName())) {
720-
for (final AbstractScript script : child.getObject(AbstractScript[].class)) {
721-
if (script instanceof ScriptRef) {
722-
LOGGER.error(
723-
"Script reference to {} not added. Scripts definition cannot contain script references",
724-
script.getName());
725-
} else if (scriptManager != null) {
726-
scriptManager.addScript(script);
727-
}
728-
}
729-
} else if ("Appenders".equalsIgnoreCase(child.getName())) {
738+
if ("Appenders".equalsIgnoreCase(child.getName())) {
730739
appenders = child.getObject();
731740
} else if (child.isInstanceOf(Filter.class)) {
732741
addFilter(child.getObject(Filter.class));
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<entry xmlns="https://logging.apache.org/xml/ns"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="
5+
https://logging.apache.org/xml/ns
6+
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
7+
type="fixed">
8+
<issue id="3336" link="https://github.com/apache/logging-log4j2/issues/3336"/>
9+
<description format="asciidoc">
10+
Fix script resolution failure when the Scripts element is placed after a ScriptRef in the configuration.
11+
</description>
12+
</entry>

0 commit comments

Comments
 (0)