Skip to content

Commit de63a4f

Browse files
jhl221123vy
andauthored
Correct script resolution order dependency (#3718)
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. Co-authored-by: Volkan Yazıcı <[email protected]>
1 parent 1450533 commit de63a4f

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)