Merge branch 'bullseye' into buster
Markus Koschany
2 years ago
30 | 30 | uses: actions/checkout@v2 |
31 | 31 | |
32 | 32 | # JDK 11 is needed for the build. |
33 | # Search `maven-toolchains-plugin` usages for details. | |
33 | 34 | - name: Set up JDK 11 |
34 | 35 | uses: actions/setup-java@v2.4.0 |
35 | 36 | with: |
49 | 50 | java-package: jdk |
50 | 51 | architecture: x64 |
51 | 52 | cache: maven |
52 | ||
53 | - name: Set up Maven caching | |
54 | uses: actions/cache@v2 | |
55 | with: | |
56 | path: ~/.m2/repository | |
57 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} | |
58 | restore-keys: ${{ runner.os }}-maven- | |
59 | 53 | |
60 | 54 | - name: Build with Maven |
61 | 55 | shell: bash |
0 | # Licensed to the Apache Software Foundation (ASF) under one or more | |
1 | # contributor license agreements. See the NOTICE file distributed with | |
2 | # this work for additional information regarding copyright ownership. | |
3 | # The ASF licenses this file to You under the Apache license, Version 2.0 | |
4 | # (the "License"); you may not use this file except in compliance with | |
5 | # the License. You may obtain a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, | |
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | # See the license for the specific language governing permissions and | |
13 | # limitations under the license. | |
14 | ||
15 | name: build | |
16 | ||
17 | on: [ push, pull_request ] | |
18 | ||
19 | jobs: | |
20 | build: | |
21 | ||
22 | runs-on: ${{ matrix.os }} | |
23 | ||
24 | strategy: | |
25 | matrix: | |
26 | os: [ ubuntu-latest, windows-latest, macos-latest ] | |
27 | ||
28 | steps: | |
29 | ||
30 | - name: Checkout repository | |
31 | uses: actions/checkout@v2 | |
32 | ||
33 | # JDK 11 is needed for the build. | |
34 | # Search `maven-toolchains-plugin` usages for details. | |
35 | - name: Setup JDK 11 | |
36 | uses: actions/setup-java@v2.4.0 | |
37 | with: | |
38 | distribution: temurin | |
39 | java-version: 11 | |
40 | java-package: jdk | |
41 | architecture: x64 | |
42 | cache: maven | |
43 | ||
44 | # JDK 8 is needed for the build, and it is the primary bytecode target. | |
45 | # Hence, JDK 8 is set up after 11, so that JAVA_HOME used by Maven during build will point to 8. | |
46 | - name: Setup JDK 8 | |
47 | uses: actions/setup-java@v2.3.0 | |
48 | with: | |
49 | distribution: temurin | |
50 | java-version: 8 | |
51 | java-package: jdk | |
52 | architecture: x64 | |
53 | cache: maven | |
54 | ||
55 | - name: Inspect environment (Linux) | |
56 | if: runner.os == 'Linux' | |
57 | run: env | grep '^JAVA' | |
58 | ||
59 | - name: Inspect environment (Windows) | |
60 | if: runner.os == 'Windows' | |
61 | run: set java | |
62 | ||
63 | - name: Inspect environment (MacOS) | |
64 | if: runner.os == 'macOS' | |
65 | run: env | grep '^JAVA' | |
66 | ||
67 | - name: Build with Maven | |
68 | timeout-minutes: 60 | |
69 | shell: bash | |
70 | run: | | |
71 | ./mvnw \ | |
72 | --show-version --batch-mode --errors --no-transfer-progress \ | |
73 | -DtrimStackTrace=false \ | |
74 | -Dsurefire.rerunFailingTestsCount=2 \ | |
75 | -Dlog4j2.junit.fileCleanerSleepPeriodMillis=1000 \ | |
76 | --global-toolchains ".github/workflows/maven-toolchains.xml" \ | |
77 | verify |
0 | # Licensed to the Apache Software Foundation (ASF) under one or more | |
1 | # contributor license agreements. See the NOTICE file distributed with | |
2 | # this work for additional information regarding copyright ownership. | |
3 | # The ASF licenses this file to You under the Apache license, Version 2.0 | |
4 | # (the "License"); you may not use this file except in compliance with | |
5 | # the License. You may obtain a copy of the License at | |
6 | # | |
7 | # http://www.apache.org/licenses/LICENSE-2.0 | |
8 | # | |
9 | # Unless required by applicable law or agreed to in writing, software | |
10 | # distributed under the License is distributed on an "AS IS" BASIS, | |
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | # See the license for the specific language governing permissions and | |
13 | # limitations under the license. | |
14 | ||
15 | name: CI | |
16 | ||
17 | on: [push, pull_request] | |
18 | ||
19 | jobs: | |
20 | build: | |
21 | ||
22 | runs-on: ${{ matrix.os }} | |
23 | ||
24 | strategy: | |
25 | matrix: | |
26 | os: [ubuntu-latest, windows-latest, macos-latest] | |
27 | ||
28 | steps: | |
29 | ||
30 | - name: Checkout repository | |
31 | uses: actions/checkout@v2 | |
32 | ||
33 | - name: Setup Maven caching | |
34 | uses: actions/cache@v2 | |
35 | with: | |
36 | path: ~/.m2/repository | |
37 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} | |
38 | restore-keys: | | |
39 | ${{ runner.os }}-maven- | |
40 | ||
41 | - name: Setup JDK 11 | |
42 | uses: actions/setup-java@v2.4.0 | |
43 | with: | |
44 | distribution: 'temurin' | |
45 | java-version: 11 | |
46 | java-package: jdk | |
47 | architecture: x64 | |
48 | ||
49 | - name: Setup JDK 8 | |
50 | uses: actions/setup-java@v2.3.0 | |
51 | with: | |
52 | distribution: 'temurin' | |
53 | java-version: 8 | |
54 | java-package: jdk | |
55 | architecture: x64 | |
56 | cache: 'maven' | |
57 | ||
58 | - name: Inspect environment (Linux) | |
59 | if: runner.os == 'Linux' | |
60 | run: env | grep '^JAVA' | |
61 | ||
62 | - name: Build with Maven (Linux) | |
63 | timeout-minutes: 60 | |
64 | if: runner.os == 'Linux' | |
65 | continue-on-error: true | |
66 | run: ./mvnw -V -B --no-transfer-progress -e -DtrimStackTrace=false -Dmaven.test.failure.ignore=true -Dsurefire.rerunFailingTestsCount=1 --global-toolchains .github/workflows/maven-toolchains.xml verify | |
67 | ||
68 | - name: Inspect environment (Windows) | |
69 | if: runner.os == 'Windows' | |
70 | run: set java | |
71 | ||
72 | - name: Build with Maven (Windows) | |
73 | timeout-minutes: 60 | |
74 | if: runner.os == 'Windows' | |
75 | continue-on-error: true | |
76 | run: ./mvnw -V -B --no-transfer-progress -e "-DtrimStackTrace=false" "-Dmaven.test.failure.ignore=true" "-Dsurefire.rerunFailingTestsCount=1" "-Dlog4j2.junit.fileCleanerSleepPeriodMillis=1000" --global-toolchains ".github\workflows\maven-toolchains.xml" verify | |
77 | ||
78 | - name: Inspect environment (MacOS) | |
79 | if: runner.os == 'macOS' | |
80 | run: env | grep '^JAVA' | |
81 | ||
82 | - name: Build with Maven (MacOS) | |
83 | timeout-minutes: 60 | |
84 | if: runner.os == 'macOS' | |
85 | continue-on-error: true | |
86 | run: ./mvnw -V -B --no-transfer-progress -e -DtrimStackTrace=false -Dmaven.test.failure.ignore=true -Dsurefire.rerunFailingTestsCount=1 --global-toolchains .github/workflows/maven-toolchains.xml verify | |
87 | ||
88 | - name: Publish Test Results | |
89 | # If the CI run is not initiated from the primary repository, it is highly likely that this is a PR from a user who doesn't have commit rights. | |
90 | # Hence, skip this step to avoid permission failures. | |
91 | if: github.repository == 'apache/logging-log4j2' | |
92 | uses: scacap/action-surefire-report@v1 | |
93 | with: | |
94 | github_token: ${{ secrets.GITHUB_TOKEN }} | |
95 | check_name: Test Report (${{ matrix.os }}) | |
96 | report_paths: '**/*-reports/TEST-*.xml' | |
97 | ||
98 | - name: Upload Test Reports | |
99 | # If the CI run is not initiated from the primary repository, it is highly likely that this is a PR from a user who doesn't have commit rights. | |
100 | # Hence, skip this step to avoid permission failures. | |
101 | if: github.repository == 'apache/logging-log4j2' | |
102 | uses: actions/upload-artifact@v2 | |
103 | with: | |
104 | name: test-reports-${{ matrix.os }} | |
105 | path: '**/*-reports' |
0 | <!--- | |
1 | Licensed to the Apache Software Foundation (ASF) under one or more | |
2 | contributor license agreements. See the NOTICE file distributed with | |
3 | this work for additional information regarding copyright ownership. | |
4 | The ASF licenses this file to You under the Apache License, Version 2.0 | |
5 | (the "License"); you may not use this file except in compliance with | |
6 | the License. You may obtain a copy of the License at | |
7 | ||
8 | http://www.apache.org/licenses/LICENSE-2.0 | |
9 | ||
10 | Unless required by applicable law or agreed to in writing, software | |
11 | distributed under the License is distributed on an "AS IS" BASIS, | |
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | See the License for the specific language governing permissions and | |
14 | limitations under the License. | |
15 | --> | |
16 | The Apache code of conduct page is [https://www.apache.org/foundation/policies/conduct.html](https://www.apache.org/foundation/policies/conduct.html). |
9 | 9 | |
10 | 10 | ## Pull Requests on Github |
11 | 11 | |
12 | By sending a pull request you grant the Apache Software Foundation sufficient rights to use and release the submitted | |
13 | work under the Apache license. You grant the same rights (copyright license, patent license, etc.) to the | |
14 | Apache Software Foundation as if you have signed a Contributor License Agreement. For contributions that are | |
12 | By sending a pull request you grant the Apache Software Foundation sufficient rights to use and release the submitted | |
13 | work under the Apache license. You grant the same rights (copyright license, patent license, etc.) to the | |
14 | Apache Software Foundation as if you have signed a Contributor License Agreement. For contributions that are | |
15 | 15 | judged to be non-trivial, you will be asked to actually signing a Contributor License Agreement. |
16 | 16 | |
17 | 17 | ## Usage |
68 | 68 | |
69 | 69 | ## Requirements |
70 | 70 | |
71 | Log4j 2.4 and greater requires Java 7, versions 2.0-alpha1 to 2.3 required Java 6. | |
72 | Some features require optional dependencies; the documentation for these features specifies the dependencies. | |
71 | * Java 8 users should use 2.17.0 or greater. | |
72 | * Java 7 users should use 2.12.2. | |
73 | * Java 6 users should use 2.3. | |
74 | * Some features require optional dependencies; the documentation for these features specifies the dependencies. | |
73 | 75 | |
74 | 76 | ## License |
75 | 77 | |
79 | 81 | |
80 | 82 | [How to download Log4j](http://logging.apache.org/log4j/2.x/download.html), |
81 | 83 | and [how to use it from Maven, Ivy and Gradle](http://logging.apache.org/log4j/2.x/maven-artifacts.html). |
82 | You can access the latest development snapshot by using the Maven repository `https://repository.apache.org/snapshots`, | |
84 | You can access the latest development snapshot by using the Maven repository `https://repository.apache.org/snapshots`, | |
83 | 85 | see [Snapshot builds](https://logging.apache.org/log4j/2.x/maven-artifacts.html#Snapshot_builds). |
84 | 86 | |
85 | 87 | ## Issue Tracking |
86 | 88 | |
87 | Issues, bugs, and feature requests should be submitted to the | |
89 | Issues, bugs, and feature requests should be submitted to the | |
88 | 90 | [JIRA issue tracking system for this project](https://issues.apache.org/jira/browse/LOG4J2). |
89 | 91 | |
90 | Pull request on GitHub are welcome, but please open a ticket in the JIRA issue tracker first, and mention the | |
92 | Pull request on GitHub are welcome, but please open a ticket in the JIRA issue tracker first, and mention the | |
91 | 93 | JIRA issue in the Pull Request. |
92 | 94 | |
93 | 95 | ## Building From Source |
13 | 13 | See the License for the specific language governing permissions and |
14 | 14 | limitations under the License. |
15 | 15 | --> |
16 | # Apache Log4j 2.17.0 Release Notes | |
16 | # Apache Log4j 2.17.1 Release Notes | |
17 | 17 | |
18 | The Apache Log4j 2 team is pleased to announce the Log4j 2.17.0 release! | |
18 | The Apache Log4j 2 team is pleased to announce the Log4j 2.17.1 release! | |
19 | 19 | |
20 | 20 | Apache Log4j is a well known framework for logging application behavior. Log4j 2 is an upgrade |
21 | 21 | to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides |
37 | 37 | later. SLF4J-2.0.0 alpha releases are not fully supported. See https://issues.apache.org/jira/browse/LOG4J2-2975 and |
38 | 38 | https://jira.qos.ch/browse/SLF4J-511. |
39 | 39 | |
40 | Some of the changes in Log4j 2.17.0 include: | |
40 | Some of the changes in Log4j 2.17.1 include: | |
41 | 41 | |
42 | 42 | * Disable recursive evaluation of Lookups during log event processing. Recursive evaluation is still allwoed while |
43 | 43 | generating the configuration. |
44 | 44 | * The JndiLookup, JndiContextSelector, and JMSAppender now require individual system properties to be enabled. |
45 | 45 | * Removed support for the LDAP and LDAPS protocols via JNDI. |
46 | 46 | |
47 | The Log4j 2.17.0 API, as well as many core components, maintains binary compatibility with previous releases. | |
47 | The Log4j 2.17.1 API, as well as many core components, maintains binary compatibility with previous releases. | |
48 | 48 | |
49 | ## GA Release 2.17.0 | |
49 | ## GA Release 2.17.1 | |
50 | 50 | |
51 | 51 | Changes in this version include: |
52 | 52 | |
53 | 53 | |
54 | 54 | ### Fixed Bugs |
55 | * [LOG4J2-3230](https://issues.apache.org/jira/browse/LOG4J2-3230): | |
56 | Fix string substitution recursion. | |
57 | * [LOG4J2-3242](https://issues.apache.org/jira/browse/LOG4J2-3242): | |
58 | Limit JNDI to the java protocol only. JNDI will remain disabled by default. Rename JNDI enablement property from | |
59 | 'log4j2.enableJndi' to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and 'log4j2.enableJndiContextSelector'. | |
60 | * [LOG4J2-3242](https://issues.apache.org/jira/browse/LOG4J2-3242): | |
61 | Limit JNDI to the java protocol only. JNDI will remain disabled by default. The enablement | |
62 | property has been renamed to 'log4j2.enableJndiJava' | |
63 | * [LOG4J2-3241](https://issues.apache.org/jira/browse/LOG4J2-3241): | |
64 | Do not declare log4j-api-java9 and log4j-core-java9 as dependencies as it causes problems with the | |
65 | Maven enforcer plugin. | |
66 | * [LOG4J2-3247](https://issues.apache.org/jira/browse/LOG4J2-3247): | |
67 | PropertiesConfiguration.parseAppenderFilters NPE when parsing properties file filters. | |
68 | * [LOG4J2-3249](https://issues.apache.org/jira/browse/LOG4J2-3249): | |
69 | Log4j 1.2 bridge for Syslog Appender defaults to port 512 instead of 514. | |
70 | * [LOG4J2-3237](https://issues.apache.org/jira/browse/LOG4J2-3237): | |
71 | Log4j 1.2 bridge API hard codes the Syslog protocol to TCP. | |
55 | * [LOG4J2-3290](https://issues.apache.org/jira/browse/LOG4J2-3290): | |
56 | Remove unused method. | |
57 | * [LOG4J2-3292](https://issues.apache.org/jira/browse/LOG4J2-3292): | |
58 | ExtendedLoggerWrapper.logMessage no longer double-logs when location is requested. | |
59 | * [LOG4J2-3289](https://issues.apache.org/jira/browse/LOG4J2-3289): | |
60 | log4j-to-slf4j no longer re-interpolates formatted message contents. | |
61 | * [LOG4J2-3204](https://issues.apache.org/jira/browse/LOG4J2-3204): | |
62 | Correct SpringLookup package name in Interpolator. Thanks to Francis-FY. | |
63 | * [LOG4J2-3284](https://issues.apache.org/jira/browse/LOG4J2-3284): | |
64 | log4j-to-slf4j takes the provided MessageFactory into account Thanks to Michael Vorburger. | |
65 | * [LOG4J2-3264](https://issues.apache.org/jira/browse/LOG4J2-3264): | |
66 | Fix MapLookup to lookup MapMessage before DefaultMap Thanks to Yanming Zhou. | |
67 | * [LOG4J2-3274](https://issues.apache.org/jira/browse/LOG4J2-3274): | |
68 | Buffered I/O checked had inverted logic in RollingFileAppenderBuidler. Thanks to Faisal Khan Thayub Khan. | |
69 | * [](https://issues.apache.org/jira/browse/LOG4J2-3274): | |
70 | Fix NPE when input is null in StrSubstitutor.replace(String, Properties). | |
71 | * [LOG4J2-3270](https://issues.apache.org/jira/browse/LOG4J2-3270): | |
72 | Lookups with no prefix only read values from the configuration properties as expected. | |
73 | * [LOG4J2-3256](https://issues.apache.org/jira/browse/LOG4J2-3256): | |
74 | Reduce ignored package scope of KafkaAppender. Thanks to Lee Dongjin. | |
72 | 75 | |
73 | 76 | |
74 | 77 | --- |
75 | 78 | |
76 | Apache Log4j 2.17.0 requires a minimum of Java 8 to build and run. Log4j 2.12.1 is the last release to support | |
79 | Apache Log4j 2.17.1 requires a minimum of Java 8 to build and run. Log4j 2.12.1 is the last release to support | |
77 | 80 | Java 7. Java 7 is not longer supported by the Log4j team. |
78 | 81 | |
79 | 82 | For complete information on Apache Log4j 2, including instructions on how to submit bug |
81 | 84 | |
82 | 85 | https://logging.apache.org/log4j/2.x/ |
83 | 86 | |
87 | --- | |
88 | ||
89 | Earlier release notes are accessible in [Release History](https://logging.apache.org/log4j/2.x/changes-report.html). |
0 | apache-log4j2 (2.17.0-1~deb10u1) buster-security; urgency=high | |
1 | ||
2 | * Team upload. | |
3 | * Backport 2.17.0-1 to Buster and fix CVE-2021-45105. (Closes: #1001891) | |
4 | ||
5 | -- Markus Koschany <apo@debian.org> Sat, 18 Dec 2021 18:56:50 +0100 | |
0 | apache-log4j2 (2.17.1-1~deb10u1) buster; urgency=medium | |
1 | ||
2 | * Team upload. | |
3 | * Backport 2.17.1 to Buster and fix CVE-2021-44832: remote code execution | |
4 | vulnerability but requires permission to modify the logging configuration. | |
5 | ||
6 | -- Markus Koschany <apo@debian.org> Fri, 11 Feb 2022 20:55:04 +0100 | |
7 | ||
8 | apache-log4j2 (2.17.1-1) unstable; urgency=high | |
9 | ||
10 | * Team upload. | |
11 | * New upstream version 2.17.1. | |
12 | - Fix CVE-2021-44832: | |
13 | Apache Log4j2 is vulnerable to a remote code execution | |
14 | (RCE) attack where an attacker with permission to modify the logging | |
15 | configuration file can construct a malicious configuration using a JDBC | |
16 | Appender with a data source referencing a JNDI URI which can execute | |
17 | remote code. This issue is fixed by limiting JNDI data source names to | |
18 | the java protocol. | |
19 | Thanks to Salvatore Bonaccorso for the report. (Closes: #1002813) | |
20 | ||
21 | -- Markus Koschany <apo@debian.org> Wed, 29 Dec 2021 11:44:21 +0100 | |
6 | 22 | |
7 | 23 | apache-log4j2 (2.17.0-1) unstable; urgency=high |
8 | 24 |
0 | I'd like to go into detail on some of the changes in 2.17.0, why they're so important, and how they relate to both [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-45105](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45105). | |
1 | ||
2 | The substitution of untrusted log data allowed access to code that was never meant to be exposed. Lookups should be triggered only by configuration and the logging framework (including custom layout/appender/etc plugins). Not by user-provided inputs. | |
3 | ||
4 | ## 1. PatternLayout rendered message substitution | |
5 | ||
6 | Substitution within the contents of a rendered log message provided the largest opportunity for untrusted inputs to be evaluated by the string replacement system. This was [removed (by default) in 2.15.0](https://github.com/apache/logging-log4j2/commit/001aaada7dab82c3c09cde5f8e14245dc9d8b454), and [removed entirely in 2.16.0](https://github.com/apache/logging-log4j2/commit/27972043b76c9645476f561c5adc483dec6d3f5d) after public disclosure. | |
7 | ||
8 | ## 2. Recursive Substitution Within Lookups | |
9 | ||
10 | Despite message replacements being removed in 2.15.0, other pathways still exist (based on the configuration) which can evaluate untrusted user-provided values. For example, a `PatternLayout` using the pattern `%p %t %c $${ctx:userAgent} %m%n`[1][2] would re-evaluate `config.getStrSubstitutor().replace(event, " ${ctx:userAgent} ")` for each log-event due to the [LiteralPatternConverter](https://github.com/apache/logging-log4j2/blob/cffe58f6a433ea1ab60ceb129d4c9b3377acda1d/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LiteralPatternConverter.java#L62-L65). The substitutor would evaluate recursively, and invoke unexpected lookups. At worst triggering something like jndi or an exception preventing logging, but even resulting in logging that doesn't match the literal data input is a very serious bug. For example if `MDC.put("userAgent", "${lower:FOO}")` then `${ctx:userAgent}` would evaluate to literal `foo` instead of literal `${lower:FOO}` | |
11 | ||
12 | This is not isolated to the PatternLayout, rather anywhere lookups in which the result contained user-provided data. e.g. `${ctx:USER_PROVIDED}`, `${event:Message}`. For example `<Routes pattern="$${ctx:userAgent}">` would be impacted as well. | |
13 | ||
14 | In 2.17.0 we resolved this class of issues with a simple idea: | |
15 | Recursive evaluation is allowed while parsing the configuration (no user-input/LogEvent data is present, and configuration breaks are to be avoided) however when log-events themselves are being evaluated we _never_ recursively evaluate substitutions. [That's it](https://github.com/apache/logging-log4j2/commit/806023265f8c905b2dd1d81fd2458f64b2ea0b5e). That means when `${lower:${event:Message}}` is evaluated for message `Hello, World!` the result is `hello, world!`, and when evaluated for `${java:version}` the result is the string literal `${java:version}` which itself is not evaluated. | |
16 | ||
17 | ----- | |
18 | ||
19 | 1. Note that I used `$${ctx:userAgent}` so the value itself is not evaluated, however even `${ctx:userAgent}` may be vulnerable because it's not likely that a thread-context value is set when the configuration itself is evaluated, in which case no replacement occurs and the value is equivalent to the `$${ctx:userAgent}` example. | |
20 | 2. Please use `%X{userAgent}` in the PatternLayout instead of `${ctx:userAgent}`. It's safer, more obvious, and more efficient. LogEventPatternConverters are pluggable, don't rely on stringly typed data, and are created when the pattern is parsed, not re-scanned on a per-LogEvent basis. | |
21 | ||
22 | ## 3. Impact Upon Configuration | |
23 | ||
24 | There are certainly cases in which this change impacts existing configurations, however I believe that the safety is well worth the trade-off. | |
25 | For example, [this test configuration](https://github.com/apache/logging-log4j2/commit/806023265f8c905b2dd1d81fd2458f64b2ea0b5e#diff-f13a31d919bf2e7169ca936948aeef1cda6089f295be684d71f2bd5709248475) had to be updated because routes are created based on a log-event, thus we cannot allow recursive evaluation. An argument can be made that the inputs must already be sanitized to avoid path traversal, however the filename isn't the only place these lookups can be evaluated, and the type of sanitization differs dramatically between validating against string replacement data, and validating against unexpected path-based attacks. | |
26 | ||
27 | In a perfect world I'd love to swap the types used for substitution to avoid stringly matching anything, using the type system to differentiate between trusted lookups and user-input data, however in such a large, widely-used framework, that's not something we can do, certainly not quickly or easily. | |
28 | ||
29 | ### Configuration Impact: Examples | |
30 | ||
31 | **Complex Lookups :heavy_check_mark: :heavy_check_mark: :heavy_check_mark:** | |
32 | ||
33 | This example uses complex lookups based on the [ThreadContext](https://logging.apache.org/log4j/2.x/manual/thread-context.html) (aka MDC), however it continues to work as expected **and** prevents user-provided data from `key1` or `key2` from being substituted. | |
34 | ||
35 | ```xml | |
36 | <-- | |
37 | Note that lookups are all escaped to prevent them from being evaluated | |
38 | immediately when the Pattern is constructed | |
39 | --> | |
40 | <PatternLayout pattern="%d %p %t %c $${lower:$${ctx:key1:-$${ctx:key2}}} %m%n"/> | |
41 | ``` | |
42 | ||
43 | ||
44 | **Pattern Reuse Via Lookups :heavy_check_mark: :heavy_check_mark: :heavy_check_mark:** | |
45 | ||
46 | This is not impacted either: | |
47 | ||
48 | ```xml | |
49 | <Properties> | |
50 | <Property name="defaultPattern">%d %p %t %c %m%n</Property> | |
51 | </Properties> | |
52 | <Appenders> | |
53 | <Console name="console"> | |
54 | <PatternLayout pattern="${defaultPattern}"/> | |
55 | </Console> | |
56 | </Appenders> | |
57 | ``` | |
58 | ||
59 | **Lazy Pattern Lookups Which include Lazy Lookups :x::x::x:** | |
60 | ||
61 | However, in this case, evaluation depends on a lazily-replaced property which itself is lazily evaluated: | |
62 | ||
63 | ```xml | |
64 | <Properties> | |
65 | <Property name="messageFormat">$${event:Message}</Property> | |
66 | </Properties> | |
67 | <Appenders> | |
68 | <Console name="console"> | |
69 | <PatternLayout pattern="%c $${messageFormat}%n"/> | |
70 | </Console> | |
71 | </Appenders> | |
72 | ``` | |
73 | ||
74 | The upgrade to 2.17.0 would change the output for the following log line: | |
75 | ||
76 | ```java | |
77 | LogManager.getLogger(com.example.Main.class).info("example"); | |
78 | ``` | |
79 | ||
80 | ```diff | |
81 | - com.example.Main example | |
82 | + com.example.Main ${event:Message} | |
83 | ``` | |
84 | ||
85 | This can be resolved by unescaping the property reference in the pattern, allowing the pattern itself to be fully evaluated when the configuration is loaded, but preventing message contents from being further interpolated due to the runtime-substitution protections. | |
86 | ||
87 | Note that this example is contrived, and in practice one should use the `%m` pattern here rather than a lookup, however this example applies to a general shape of usage and some extrapolation may be required for your configuration. | |
88 | ||
89 | ||
90 | ```diff | |
91 | <Properties> | |
92 | <Property name="messageFormat">$${event:Message}</Property> | |
93 | </Properties> | |
94 | <Appenders> | |
95 | <Console name="console"> | |
96 | - <PatternLayout pattern="%c $${messageFormat}%n"/> | |
97 | + <PatternLayout pattern="%c ${messageFormat}%n"/> | |
98 | </Console> | |
99 | </Appenders> | |
100 | ``` | |
101 | ||
102 | **RoutingAppender with lazy property references in routes :x::x::x:** | |
103 | ||
104 | RoutingAppender routes are lazily evaluated when they're needed, which means a LogEvent (thus potentially user-provided data) is available. Everything that could be represented before can still be done, however it's no longer possible to extract some pieces to shared properties. | |
105 | ||
106 | Let's take the [example from the test liked above](https://github.com/apache/logging-log4j2/commit/806023265f8c905b2dd1d81fd2458f64b2ea0b5e#diff-f13a31d919bf2e7169ca936948aeef1cda6089f295be684d71f2bd5709248475) | |
107 | ||
108 | ```xml | |
109 | <Configuration status="WARN" name="RoutingTest"> | |
110 | <Properties> | |
111 | <Property name="filename">target/routing1/routingtest-$${sd:type}.log</Property> | |
112 | </Properties> | |
113 | <Appenders> | |
114 | <Routing name="Routing"> | |
115 | <Routes> | |
116 | <Route> | |
117 | <RollingFile name="Routing-${sd:type}" fileName="${filename}" | |
118 | filePattern="target/routing1/test1-${sd:type}.%i.log.gz"> | |
119 | <PatternLayout> | |
120 | <Pattern>%d %p %C{1.} [%t] %m%n</Pattern> | |
121 | </PatternLayout> | |
122 | <SizeBasedTriggeringPolicy size="500" /> | |
123 | </RollingFile> | |
124 | </Route> | |
125 | </Routes> | |
126 | </Routing> | |
127 | </Appenders> | |
128 | <Loggers> | |
129 | <Root level="info"> | |
130 | <AppenderRef ref="Routing"/> | |
131 | </Root> | |
132 | </Loggers> | |
133 | </Configuration> | |
134 | ``` | |
135 | ||
136 | The reference to `fileName="${filename}"` is no longer evaluated recursively to `fileName="target/routing1/routingtest-${sd:type}.log"` however the `${sd:type}` is left as a string literal, not expanded as it was before. | |
137 | ||
138 | The fix in this case is to inline the `fileName` property value into the `RollingFile` `filename` attribute, removing the extra`$` escaping the `${sd:type}` lookup like so: | |
139 | ||
140 | ```diff | |
141 | <Routing name="Routing"> | |
142 | <Routes> | |
143 | <Route> | |
144 | - <RollingFile name="Routing-${sd:type}" fileName="${filename}" | |
145 | + <RollingFile name="Routing-${sd:type}" fileName="target/routing1/routingtest-${sd:type}.log" | |
146 | filePattern="target/routing1/test1-${sd:type}.%i.log.gz"> | |
147 | <PatternLayout> | |
148 | <Pattern>%d %p %C{1.} [%t] %m%n</Pattern> | |
149 | </PatternLayout> | |
150 | <SizeBasedTriggeringPolicy size="500" /> | |
151 | </RollingFile> | |
152 | </Route> | |
153 | </Routes> | |
154 | </Routing> | |
155 | ```⏎ |
0 | This is a map of CVEs and Log4j *2* Versions. | |
1 | ||
2 | | CVE | Affects | Fixed In | Java Required | | |
3 | | -------------- | --------- | --------------- | --- | | |
4 | | CVE-2021-45105 | 2.0-beta9 to 2.16.0, excluding 2.12.3 | 2.17.0<br>2.12.3<br>2.3.1 | Java 8<br>Java 7<br>Java 6 | | |
5 | | CVE-2021-45046 | 2.0-beta9 to 2.15.0, excluding 2.12.2 | 2.16.0<br>2.12.2<br>2.3.1 | Java 8<br>Java 7<br>Java 6 | | |
6 | | CVE-2021-44228 | 2.0-beta9 to 2.16.0, excluding 2.12.3 & 2.3.1 | 2.17.0<br>2.12.3<br>2.3.1 | Java 8<br>Java 7<br>Java 6 | | |
7 | | CVE-2020-9488 | 2.0-alpha1 to 2.13.1 | 2.13.2<br>2.12.3 | Java 8<br>Java 7 | | |
8 | | CVE-2017-5645 | 2.0-alpha1 to 2.8.1 | 2.8.2 | Java 7 | | |
9 | ||
10 | This is a map of CVEs and Log4j *1* End-of-Life Versions. | |
11 | ||
12 | | CVE | Affects | Fixed In | Java Required | | |
13 | | -------------- | --------- | --------------- | --- | | |
14 | | CVE-2019-17571 | 1.2 to 1.2.17 | Not fixed | Not fixed | |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-1.2-api</artifactId> |
32 | 32 | } |
33 | 33 | |
34 | 34 | @Override |
35 | public void start() { | |
36 | filter.activateOptions(); | |
37 | } | |
38 | ||
39 | @Override | |
40 | 35 | public Result filter(LogEvent event) { |
41 | 36 | LoggingEvent loggingEvent = new LogEventAdapter(event); |
42 | 37 | Filter next = filter; |
52 | 47 | } |
53 | 48 | return Result.NEUTRAL; |
54 | 49 | } |
50 | ||
51 | /** | |
52 | * Gets the actual filter. | |
53 | * | |
54 | * @return the actual filter. | |
55 | * @since 2.17.1 | |
56 | */ | |
57 | public Filter getFilter() { | |
58 | return filter; | |
59 | } | |
60 | ||
61 | @Override | |
62 | public void start() { | |
63 | filter.activateOptions(); | |
64 | } | |
55 | 65 | } |
+1
-1
176 | 176 | final Filter filter, final boolean bufferedIo, boolean immediateFlush, final String fileName, |
177 | 177 | final String level, final String maxSize, final String maxBackups) { |
178 | 178 | org.apache.logging.log4j.core.Layout<?> fileLayout = null; |
179 | if (bufferedIo) { | |
179 | if (!bufferedIo) { | |
180 | 180 | immediateFlush = true; |
181 | 181 | } |
182 | 182 | if (layout instanceof LayoutWrapper) { |
23 | 23 | import java.util.HashMap; |
24 | 24 | import java.util.List; |
25 | 25 | import java.util.Map; |
26 | import java.util.Objects; | |
26 | 27 | import java.util.Properties; |
27 | 28 | import java.util.SortedMap; |
28 | 29 | import java.util.StringTokenizer; |
329 | 330 | * Parse non-root elements, such non-root categories and renderers. |
330 | 331 | */ |
331 | 332 | private void parseLoggers(Properties props) { |
332 | Enumeration enumeration = props.propertyNames(); | |
333 | Enumeration<?> enumeration = props.propertyNames(); | |
333 | 334 | while (enumeration.hasMoreElements()) { |
334 | String key = (String) enumeration.nextElement(); | |
335 | String key = Objects.toString(enumeration.nextElement(), null); | |
335 | 336 | if (key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) { |
336 | 337 | String loggerName = null; |
337 | 338 | if (key.startsWith(CATEGORY_PREFIX)) { |
39 | 39 | } |
40 | 40 | |
41 | 41 | @Override |
42 | public Enumeration getAllAppenders() { | |
42 | public Enumeration<Appender> getAllAppenders() { | |
43 | 43 | return Collections.enumeration(appenders.values()); |
44 | 44 | } |
45 | 45 |
19 | 19 | import org.apache.log4j.Level; |
20 | 20 | import org.apache.logging.log4j.LogManager; |
21 | 21 | import org.apache.logging.log4j.Logger; |
22 | import org.apache.logging.log4j.core.lookup.StrSubstitutor; | |
22 | 23 | import org.apache.logging.log4j.util.LoaderUtil; |
23 | 24 | |
24 | 25 | import java.io.InterruptedIOException; |
289 | 290 | * @throws IllegalArgumentException if <code>val</code> is malformed. |
290 | 291 | */ |
291 | 292 | public static String substVars(String val, Properties props) throws IllegalArgumentException { |
292 | ||
293 | StringBuilder sbuf = new StringBuilder(); | |
294 | ||
295 | int i = 0; | |
296 | int j, k; | |
297 | ||
298 | while (true) { | |
299 | j = val.indexOf(DELIM_START, i); | |
300 | if (j == -1) { | |
301 | // no more variables | |
302 | if (i == 0) { // this is a simple string | |
303 | return val; | |
304 | } | |
305 | sbuf.append(val.substring(i, val.length())); | |
306 | return sbuf.toString(); | |
307 | } | |
308 | sbuf.append(val.substring(i, j)); | |
309 | k = val.indexOf(DELIM_STOP, j); | |
310 | if (k == -1) { | |
311 | throw new IllegalArgumentException('"' + val + | |
312 | "\" has no closing brace. Opening brace at position " + j | |
313 | + '.'); | |
314 | } | |
315 | j += DELIM_START_LEN; | |
316 | String key = val.substring(j, k); | |
317 | // first try in System properties | |
318 | String replacement = getSystemProperty(key, null); | |
319 | // then try props parameter | |
320 | if (replacement == null && props != null) { | |
321 | replacement = props.getProperty(key); | |
322 | } | |
323 | ||
324 | if (replacement != null) { | |
325 | // Do variable substitution on the replacement string | |
326 | // such that we can solve "Hello ${x2}" as "Hello p1" | |
327 | // the where the properties are | |
328 | // x1=p1 | |
329 | // x2=${x1} | |
330 | String recursiveReplacement = substVars(replacement, props); | |
331 | sbuf.append(recursiveReplacement); | |
332 | } | |
333 | i = k + DELIM_STOP_LEN; | |
334 | } | |
293 | return StrSubstitutor.replace(val, props); | |
335 | 294 | } |
336 | 295 | |
337 | 296 | public static org.apache.logging.log4j.Level convertLevel(String level, |
0 | /* | |
1 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
2 | * contributor license agreements. See the NOTICE file distributed with | |
3 | * this work for additional information regarding copyright ownership. | |
4 | * The ASF licenses this file to You under the Apache license, Version 2.0 | |
5 | * (the "License"); you may not use this file except in compliance with | |
6 | * the License. You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the license for the specific language governing permissions and | |
14 | * limitations under the license. | |
15 | */ | |
16 | package org.apache.log4j.config; | |
17 | ||
18 | import org.apache.log4j.spi.Filter; | |
19 | import org.apache.log4j.spi.LoggingEvent; | |
20 | ||
21 | /** | |
22 | * A test fixture used by {@code src/test/resources/LOG4J2-3247.properties}. | |
23 | */ | |
24 | public class NeutralFilterFixture extends Filter { | |
25 | ||
26 | @Override | |
27 | public int decide(LoggingEvent event) { | |
28 | return NEUTRAL; | |
29 | } | |
30 | ||
31 | } |
+22
-1
26 | 26 | import org.apache.log4j.LogManager; |
27 | 27 | import org.apache.log4j.Logger; |
28 | 28 | import org.apache.log4j.bridge.AppenderAdapter; |
29 | import org.apache.log4j.bridge.FilterAdapter; | |
29 | 30 | import org.apache.log4j.spi.LoggingEvent; |
30 | 31 | import org.apache.logging.log4j.core.Appender; |
31 | 32 | import org.apache.logging.log4j.core.LoggerContext; |
32 | 33 | import org.apache.logging.log4j.core.config.Configuration; |
34 | import org.apache.logging.log4j.core.filter.Filterable; | |
33 | 35 | import org.junit.Test; |
34 | 36 | |
35 | 37 | /** |
38 | 40 | public class PropertiesConfigurationTest { |
39 | 41 | |
40 | 42 | @Test |
43 | public void testConfigureNullPointerException() throws Exception { | |
44 | try (LoggerContext loggerContext = TestConfigurator.configure("target/test-classes/LOG4J2-3247.properties")) { | |
45 | // [LOG4J2-3247] configure() should not throw an NPE. | |
46 | Configuration configuration = loggerContext.getConfiguration(); | |
47 | assertNotNull(configuration); | |
48 | Appender appender = configuration.getAppender("CONSOLE"); | |
49 | assertNotNull(appender); | |
50 | } | |
51 | } | |
52 | ||
53 | @Test | |
41 | 54 | public void testFilter() throws Exception { |
42 | 55 | try (LoggerContext loggerContext = TestConfigurator.configure("target/test-classes/LOG4J2-3247.properties")) { |
43 | // [LOG4J2-3247] configure() should not throw an NPE. | |
56 | // LOG4J2-3281 PropertiesConfiguration.buildAppender not adding filters to appender | |
57 | Configuration configuration = loggerContext.getConfiguration(); | |
58 | assertNotNull(configuration); | |
59 | Appender appender = configuration.getAppender("CONSOLE"); | |
60 | assertNotNull(appender); | |
61 | Filterable filterable = (Filterable) appender; | |
62 | FilterAdapter filter = (FilterAdapter) filterable.getFilter(); | |
63 | assertNotNull(filter); | |
64 | assertTrue(filter.getFilter() instanceof NeutralFilterFixture); | |
44 | 65 | } |
45 | 66 | } |
46 | 67 |
0 | /* | |
1 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
2 | * contributor license agreements. See the NOTICE file distributed with | |
3 | * this work for additional information regarding copyright ownership. | |
4 | * The ASF licenses this file to You under the Apache license, Version 2.0 | |
5 | * (the "License"); you may not use this file except in compliance with | |
6 | * the License. You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the license for the specific language governing permissions and | |
14 | * limitations under the license. | |
15 | */ | |
16 | package org.apache.log4j.config; | |
17 | ||
18 | import org.apache.log4j.spi.Filter; | |
19 | import org.apache.log4j.spi.LoggingEvent; | |
20 | ||
21 | public class ZeroFilterFixture extends Filter { | |
22 | ||
23 | @Override | |
24 | public int decide(LoggingEvent event) { | |
25 | return 0; | |
26 | } | |
27 | ||
28 | } |
14 | 14 | |
15 | 15 | |
16 | 16 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender |
17 | log4j.appender.CONSOLE.filter.1=org.apache.log4j.config.ZeroFilterFixture | |
17 | log4j.appender.CONSOLE.filter.1=org.apache.log4j.config.NeutralFilterFixture | |
18 | log4j.appender.CONSOLE.filter.1.onMatch=neutral | |
18 | 19 | log4j.appender.CONSOLE.Target=System.out |
19 | 20 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout |
20 | 21 | log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-api</artifactId> |
4266 | 4266 | */ |
4267 | 4267 | default void logMessage(Level level, Marker marker, String fqcn, StackTraceElement location, Message message, |
4268 | 4268 | Throwable throwable) { |
4269 | ||
4269 | // noop | |
4270 | 4270 | } |
4271 | 4271 | |
4272 | 4272 | /** |
4334 | 4334 | |
4335 | 4335 | /** |
4336 | 4336 | * Construct a log event. |
4337 | * @param level Any level (ignoreed here). | |
4337 | 4338 | * @return a LogBuilder. |
4338 | 4339 | * @since 2.13.0 |
4339 | 4340 | */ |
2915 | 2915 | public LogBuilder atLevel(Level level) { |
2916 | 2916 | if (isEnabled(level)) { |
2917 | 2917 | return getLogBuilder(level).reset(level); |
2918 | } else { | |
2919 | return LogBuilder.NOOP; | |
2920 | } | |
2918 | } | |
2919 | return LogBuilder.NOOP; | |
2921 | 2920 | } |
2922 | 2921 | |
2923 | 2922 | private DefaultLogBuilder getLogBuilder(Level level) { |
217 | 217 | if (logger instanceof LocationAwareLogger && requiresLocation()) { |
218 | 218 | ((LocationAwareLogger) logger).logMessage(level, marker, fqcn, StackLocatorUtil.calcLocation(fqcn), |
219 | 219 | message, t); |
220 | } else { | |
221 | logger.logMessage(fqcn, level, marker, message, t); | |
220 | 222 | } |
221 | logger.logMessage(fqcn, level, marker, message, t); | |
222 | 223 | } |
223 | 224 | } |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-api-java9</artifactId> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <modelVersion>4.0.0</modelVersion> |
25 | 25 |
25 | 25 | <description>Apache Log4j Bill of Materials</description> |
26 | 26 | <groupId>org.apache.logging.log4j</groupId> |
27 | 27 | <artifactId>log4j-bom</artifactId> |
28 | <version>2.17.0</version> | |
28 | <version>2.17.1</version> | |
29 | 29 | <packaging>pom</packaging> |
30 | 30 | <dependencyManagement> |
31 | 31 | <dependencies> |
216 | 216 | </build> |
217 | 217 | |
218 | 218 | <scm> |
219 | <tag>log4j-2.17.0-rc1</tag> | |
219 | <tag>log4j-2.17.1-rc1</tag> | |
220 | 220 | </scm> |
221 | 221 | </project> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <modelVersion>4.0.0</modelVersion> |
25 | 25 |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-core</artifactId> |
186 | 186 | "code": "java.field.removedWithConstant", |
187 | 187 | "old": "field org.apache.logging.log4j.core.net.JndiManager.ALLOWED_PROTOCOLS", |
188 | 188 | "justification": "Removed allowing additional protocols" |
189 | }, | |
190 | { | |
191 | "code": "java.method.removed", | |
192 | "old": "method java.util.List<java.lang.String> org.apache.logging.log4j.core.util.NetUtils::getLocalIps()", | |
193 | "justification": "method is no longer used." | |
189 | 194 | } |
190 | 195 | ] |
191 | 196 | } |
+11
-9
17 | 17 | |
18 | 18 | import java.sql.Connection; |
19 | 19 | import java.sql.SQLException; |
20 | import java.util.Objects; | |
20 | 21 | |
21 | import javax.naming.InitialContext; | |
22 | 22 | import javax.naming.NamingException; |
23 | 23 | import javax.sql.DataSource; |
24 | 24 | |
27 | 27 | import org.apache.logging.log4j.core.config.plugins.Plugin; |
28 | 28 | import org.apache.logging.log4j.core.config.plugins.PluginAttribute; |
29 | 29 | import org.apache.logging.log4j.core.config.plugins.PluginFactory; |
30 | import org.apache.logging.log4j.core.net.JndiManager; | |
30 | 31 | import org.apache.logging.log4j.status.StatusLogger; |
31 | 32 | import org.apache.logging.log4j.util.Strings; |
32 | 33 | |
41 | 42 | private final String description; |
42 | 43 | |
43 | 44 | private DataSourceConnectionSource(final String dataSourceName, final DataSource dataSource) { |
44 | this.dataSource = dataSource; | |
45 | this.dataSource = Objects.requireNonNull(dataSource, "dataSource"); | |
45 | 46 | this.description = "dataSource{ name=" + dataSourceName + ", value=" + dataSource + " }"; |
46 | 47 | } |
47 | 48 | |
58 | 59 | /** |
59 | 60 | * Factory method for creating a connection source within the plugin manager. |
60 | 61 | * |
61 | * @param jndiName The full JNDI path where the data source is bound. Should start with java:/comp/env or | |
62 | * environment-equivalent. | |
62 | * @param jndiName The full JNDI path where the data source is bound. Must start with java:/comp/env or environment-equivalent. | |
63 | 63 | * @return the created connection source. |
64 | 64 | */ |
65 | 65 | @PluginFactory |
66 | 66 | public static DataSourceConnectionSource createConnectionSource(@PluginAttribute("jndiName") final String jndiName) { |
67 | if (!JndiManager.isJndiJdbcEnabled()) { | |
68 | LOGGER.error("JNDI must be enabled by setting log4j2.enableJndiJdbc=true"); | |
69 | return null; | |
70 | } | |
67 | 71 | if (Strings.isEmpty(jndiName)) { |
68 | 72 | LOGGER.error("No JNDI name provided."); |
69 | 73 | return null; |
70 | 74 | } |
71 | ||
72 | 75 | try { |
73 | final InitialContext context = new InitialContext(); | |
74 | final DataSource dataSource = (DataSource) context.lookup(jndiName); | |
76 | @SuppressWarnings("resource") | |
77 | final DataSource dataSource = JndiManager.getDefaultManager(DataSourceConnectionSource.class.getCanonicalName()).lookup(jndiName); | |
75 | 78 | if (dataSource == null) { |
76 | LOGGER.error("No data source found with JNDI name [" + jndiName + "]."); | |
79 | LOGGER.error("No DataSource found with JNDI name [" + jndiName + "]."); | |
77 | 80 | return null; |
78 | 81 | } |
79 | ||
80 | 82 | return new DataSourceConnectionSource(jndiName, dataSource); |
81 | 83 | } catch (final NamingException e) { |
82 | 84 | LOGGER.error(e.getMessage(), e); |
130 | 130 | logger().error("Error creating JmsManager using JmsManagerConfiguration [{}]", data, e); |
131 | 131 | return null; |
132 | 132 | } |
133 | } else { | |
134 | logger().error("JNDI must be enabled by setting log4j2.enableJndiJms=true"); | |
135 | return null; | |
136 | } | |
133 | } | |
134 | logger().error("JNDI must be enabled by setting log4j2.enableJndiJms=true"); | |
135 | return null; | |
137 | 136 | } |
138 | 137 | } |
139 | 138 | |
352 | 351 | * @param object |
353 | 352 | * The LogEvent or String message to wrap. |
354 | 353 | * @return A new JMS message containing the provided object. |
355 | * @throws JMSException | |
354 | * @throws JMSException if the JMS provider fails to create this message due to some internal error. | |
356 | 355 | */ |
357 | 356 | public Message createMessage(final Serializable object) throws JMSException { |
358 | 357 | if (object instanceof String) { |
373 | 372 | * Creates a MessageConsumer on this Destination using the current Session. |
374 | 373 | * |
375 | 374 | * @return A MessageConsumer on this Destination. |
376 | * @throws JMSException | |
375 | * @throws JMSException if the session fails to create a consumer due to some internal error. | |
377 | 376 | */ |
378 | 377 | public MessageConsumer createMessageConsumer() throws JMSException { |
379 | 378 | return this.session.createConsumer(this.destination); |
387 | 386 | * @param destination |
388 | 387 | * The JMS Destination for the MessageProducer |
389 | 388 | * @return A MessageProducer on this Destination. |
390 | * @throws JMSException | |
389 | * @throws JMSException if the session fails to create a MessageProducer due to some internal error. | |
391 | 390 | */ |
392 | 391 | public MessageProducer createMessageProducer(final Session session, final Destination destination) |
393 | 392 | throws JMSException { |
+61
-48
21 | 21 | import java.util.concurrent.ExecutionException; |
22 | 22 | import java.util.concurrent.TimeUnit; |
23 | 23 | import java.util.concurrent.TimeoutException; |
24 | import java.util.stream.Stream; | |
24 | 25 | |
25 | 26 | import org.apache.logging.log4j.core.AbstractLifeCycle; |
26 | 27 | import org.apache.logging.log4j.core.Appender; |
42 | 43 | @Plugin(name = "Kafka", category = Node.CATEGORY, elementType = Appender.ELEMENT_TYPE, printObject = true) |
43 | 44 | public final class KafkaAppender extends AbstractAppender { |
44 | 45 | |
45 | private final Integer retryCount; | |
46 | ||
47 | /** | |
46 | /** | |
48 | 47 | * Builds KafkaAppender instances. |
49 | 48 | * |
50 | 49 | * @param <B> The type to build |
78 | 77 | getPropertyArray(), getRetryCount()); |
79 | 78 | } |
80 | 79 | |
81 | public String getTopic() { | |
82 | return topic; | |
83 | } | |
84 | ||
85 | public boolean isSyncSend() { | |
86 | return syncSend; | |
87 | } | |
88 | ||
89 | public B setTopic(final String topic) { | |
90 | this.topic = topic; | |
91 | return asBuilder(); | |
92 | } | |
93 | ||
94 | public B setSyncSend(final boolean syncSend) { | |
95 | this.syncSend = syncSend; | |
96 | return asBuilder(); | |
97 | } | |
98 | ||
99 | public B setKey(final String key) { | |
100 | this.key = key; | |
101 | return asBuilder(); | |
102 | } | |
103 | ||
104 | 80 | public Integer getRetryCount() { |
105 | 81 | Integer intRetryCount = null; |
106 | 82 | try { |
112 | 88 | |
113 | 89 | } |
114 | 90 | |
115 | } | |
91 | public String getTopic() { | |
92 | return topic; | |
93 | } | |
94 | ||
95 | public boolean isSyncSend() { | |
96 | return syncSend; | |
97 | } | |
98 | ||
99 | public B setKey(final String key) { | |
100 | this.key = key; | |
101 | return asBuilder(); | |
102 | } | |
103 | ||
104 | public B setSyncSend(final boolean syncSend) { | |
105 | this.syncSend = syncSend; | |
106 | return asBuilder(); | |
107 | } | |
108 | ||
109 | public B setTopic(final String topic) { | |
110 | this.topic = topic; | |
111 | return asBuilder(); | |
112 | } | |
113 | ||
114 | } | |
115 | ||
116 | private static final String[] KAFKA_CLIENT_PACKAGES = new String[] { "org.apache.kafka.common", "org.apache.kafka.clients" }; | |
116 | 117 | |
117 | 118 | @Deprecated |
118 | 119 | public static KafkaAppender createAppender(final Layout<? extends Serializable> layout, final Filter filter, |
128 | 129 | properties, key); |
129 | 130 | return new KafkaAppender(name, layout, filter, ignoreExceptions, kafkaManager, null, null); |
130 | 131 | } |
132 | ||
133 | /** | |
134 | * Tests if the given log event is from a Kafka Producer implementation. | |
135 | * | |
136 | * @param event The event to test. | |
137 | * @return true to avoid recursion and skip logging, false to log. | |
138 | */ | |
139 | private static boolean isRecursive(final LogEvent event) { | |
140 | return Stream.of(KAFKA_CLIENT_PACKAGES).anyMatch(prefix -> event.getLoggerName().startsWith(prefix)); | |
141 | } | |
131 | 142 | |
132 | 143 | /** |
133 | 144 | * Creates a builder for a KafkaAppender. |
139 | 150 | return new Builder<B>().asBuilder(); |
140 | 151 | } |
141 | 152 | |
153 | private final Integer retryCount; | |
154 | ||
142 | 155 | private final KafkaManager manager; |
143 | 156 | |
144 | 157 | private KafkaAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, |
151 | 164 | |
152 | 165 | @Override |
153 | 166 | public void append(final LogEvent event) { |
154 | if (event.getLoggerName() != null && event.getLoggerName().startsWith("org.apache.kafka")) { | |
167 | if (event.getLoggerName() != null && isRecursive(event)) { | |
155 | 168 | LOGGER.warn("Recursive logging from [{}] for appender [{}].", event.getLoggerName(), getName()); |
156 | 169 | } else { |
157 | 170 | try { |
173 | 186 | error("Unable to write to Kafka in appender [" + getName() + "]", event, e); |
174 | 187 | } |
175 | 188 | } |
189 | } | |
190 | ||
191 | @Override | |
192 | public void start() { | |
193 | super.start(); | |
194 | manager.startup(); | |
195 | } | |
196 | ||
197 | @Override | |
198 | public boolean stop(final long timeout, final TimeUnit timeUnit) { | |
199 | setStopping(); | |
200 | boolean stopped = super.stop(timeout, timeUnit, false); | |
201 | stopped &= manager.stop(timeout, timeUnit); | |
202 | setStopped(); | |
203 | return stopped; | |
204 | } | |
205 | ||
206 | @Override | |
207 | public String toString() { | |
208 | return "KafkaAppender{" + "name=" + getName() + ", state=" + getState() + ", topic=" + manager.getTopic() + '}'; | |
176 | 209 | } |
177 | 210 | |
178 | 211 | private void tryAppend(final LogEvent event) throws ExecutionException, InterruptedException, TimeoutException { |
189 | 222 | } |
190 | 223 | manager.send(data); |
191 | 224 | } |
192 | ||
193 | @Override | |
194 | public void start() { | |
195 | super.start(); | |
196 | manager.startup(); | |
197 | } | |
198 | ||
199 | @Override | |
200 | public boolean stop(final long timeout, final TimeUnit timeUnit) { | |
201 | setStopping(); | |
202 | boolean stopped = super.stop(timeout, timeUnit, false); | |
203 | stopped &= manager.stop(timeout, timeUnit); | |
204 | setStopped(); | |
205 | return stopped; | |
206 | } | |
207 | ||
208 | @Override | |
209 | public String toString() { | |
210 | return "KafkaAppender{" + "name=" + getName() + ", state=" + getState() + ", topic=" + manager.getTopic() + '}'; | |
211 | } | |
212 | 225 | } |
+2
-2
57 | 57 | import org.apache.logging.log4j.core.layout.PatternLayout; |
58 | 58 | import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor; |
59 | 59 | import org.apache.logging.log4j.core.lookup.Interpolator; |
60 | import org.apache.logging.log4j.core.lookup.MapLookup; | |
60 | import org.apache.logging.log4j.core.lookup.PropertiesLookup; | |
61 | 61 | import org.apache.logging.log4j.core.lookup.RuntimeStrSubstitutor; |
62 | 62 | import org.apache.logging.log4j.core.lookup.StrLookup; |
63 | 63 | import org.apache.logging.log4j.core.lookup.StrSubstitutor; |
632 | 632 | } |
633 | 633 | } else { |
634 | 634 | final Map<String, String> map = this.getComponent(CONTEXT_PROPERTIES); |
635 | final StrLookup lookup = map == null ? null : new MapLookup(map); | |
635 | final StrLookup lookup = map == null ? null : new PropertiesLookup(map); | |
636 | 636 | Interpolator interpolator = new Interpolator(lookup, pluginPackages); |
637 | 637 | subst.setVariableResolver(interpolator); |
638 | 638 | configurationStrSubstitutor.setVariableResolver(interpolator); |
23 | 23 | import org.apache.logging.log4j.core.config.plugins.PluginElement; |
24 | 24 | import org.apache.logging.log4j.core.config.plugins.PluginFactory; |
25 | 25 | import org.apache.logging.log4j.core.lookup.Interpolator; |
26 | import org.apache.logging.log4j.core.lookup.MapLookup; | |
26 | import org.apache.logging.log4j.core.lookup.PropertiesLookup; | |
27 | 27 | import org.apache.logging.log4j.core.lookup.StrLookup; |
28 | 28 | |
29 | 29 | /** |
53 | 53 | map.put(prop.getName(), prop.getValue()); |
54 | 54 | } |
55 | 55 | |
56 | return new Interpolator(new MapLookup(map), config.getPluginPackages()); | |
56 | return new Interpolator(new PropertiesLookup(map), config.getPluginPackages()); | |
57 | 57 | } |
58 | 58 | } |
69 | 69 | * @since 2.1 |
70 | 70 | */ |
71 | 71 | public Interpolator(final StrLookup defaultLookup, final List<String> pluginPackages) { |
72 | this.defaultLookup = defaultLookup == null ? new MapLookup(new HashMap<String, String>()) : defaultLookup; | |
72 | this.defaultLookup = defaultLookup == null ? new PropertiesLookup(new HashMap<String, String>()) : defaultLookup; | |
73 | 73 | final PluginManager manager = new PluginManager(CATEGORY); |
74 | 74 | manager.collectPlugins(pluginPackages); |
75 | 75 | final Map<String, PluginType<?>> plugins = manager.getPlugins(); |
97 | 97 | * Creates the Interpolator using only Lookups that work without an event and initial properties. |
98 | 98 | */ |
99 | 99 | public Interpolator(final Map<String, String> properties) { |
100 | this.defaultLookup = new MapLookup(properties == null ? new HashMap<String, String>() : properties); | |
100 | this.defaultLookup = new PropertiesLookup(properties); | |
101 | 101 | // TODO: this ought to use the PluginManager |
102 | 102 | strLookupMap.put("log4j", new Log4jLookup()); |
103 | 103 | strLookupMap.put("sys", new SystemPropertiesLookup()); |
104 | 104 | strLookupMap.put("env", new EnvironmentLookup()); |
105 | 105 | strLookupMap.put("main", MainMapLookup.MAIN_SINGLETON); |
106 | strLookupMap.put("map", new MapLookup(properties)); | |
106 | 107 | strLookupMap.put("marker", new MarkerLookup()); |
107 | 108 | strLookupMap.put("java", new JavaLookup()); |
108 | 109 | strLookupMap.put("lower", new LowerLookup()); |
127 | 128 | handleError(LOOKUP_KEY_JVMRUNARGS, e); |
128 | 129 | } |
129 | 130 | strLookupMap.put("date", new DateLookup()); |
130 | strLookupMap.put("ctx", new ContextMapLookup()); | |
131 | 131 | if (Constants.IS_WEB_APP) { |
132 | 132 | try { |
133 | 133 | strLookupMap.put(LOOKUP_KEY_WEB, |
146 | 146 | } |
147 | 147 | try { |
148 | 148 | strLookupMap.put(LOOKUP_KEY_SPRING, |
149 | Loader.newCheckedInstanceOf("org.apache.logging.log4j.spring.cloud.config.client.SpringLookup", StrLookup.class)); | |
149 | Loader.newCheckedInstanceOf("org.apache.logging.log4j.spring.boot.SpringLookup", StrLookup.class)); | |
150 | 150 | } catch (final Exception ignored) { |
151 | 151 | handleError(LOOKUP_KEY_SPRING, ignored); |
152 | 152 | } |
+14
-0
19 | 19 | import java.util.List; |
20 | 20 | import java.util.Map; |
21 | 21 | |
22 | import org.apache.logging.log4j.core.LogEvent; | |
22 | 23 | import org.apache.logging.log4j.core.config.plugins.Plugin; |
23 | 24 | |
24 | 25 | /** |
47 | 48 | super(map); |
48 | 49 | } |
49 | 50 | |
51 | @Override | |
52 | public String lookup(final LogEvent event, final String key) { | |
53 | return lookup(key); | |
54 | } | |
55 | ||
56 | @Override | |
57 | public String lookup(final String key) { | |
58 | if (key == null) { | |
59 | return null; | |
60 | } | |
61 | Map<String, String> map = getMap(); | |
62 | return map == null ? null : map.get(key); | |
63 | } | |
50 | 64 | } |
42 | 42 | } |
43 | 43 | |
44 | 44 | /** |
45 | * Creates a new instance backed by a Map. Used by the default lookup. | |
45 | * Creates a new instance backed by a Map. | |
46 | 46 | * |
47 | 47 | * @param map |
48 | 48 | * the map of keys to values, may be null |
118 | 118 | @Override |
119 | 119 | public String lookup(final LogEvent event, final String key) { |
120 | 120 | final boolean isMapMessage = event != null && event.getMessage() instanceof MapMessage; |
121 | if (map == null && !isMapMessage) { | |
122 | return null; | |
123 | } | |
124 | if (map != null && map.containsKey(key)) { | |
125 | final String obj = map.get(key); | |
121 | if (isMapMessage) { | |
122 | final String obj = ((MapMessage) event.getMessage()).get(key); | |
126 | 123 | if (obj != null) { |
127 | 124 | return obj; |
128 | 125 | } |
129 | 126 | } |
130 | if (isMapMessage) { | |
131 | return ((MapMessage) event.getMessage()).get(key); | |
127 | if (map != null) { | |
128 | return map.get(key); | |
132 | 129 | } |
133 | 130 | return null; |
134 | 131 | } |
145 | 142 | */ |
146 | 143 | @Override |
147 | 144 | public String lookup(final String key) { |
148 | if (map == null) { | |
145 | if (key == null || map == null) { | |
149 | 146 | return null; |
150 | 147 | } |
151 | 148 | return map.get(key); |
+68
-0
0 | /* | |
1 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
2 | * contributor license agreements. See the NOTICE file distributed with | |
3 | * this work for additional information regarding copyright ownership. | |
4 | * The ASF licenses this file to You under the Apache license, Version 2.0 | |
5 | * (the "License"); you may not use this file except in compliance with | |
6 | * the License. You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the license for the specific language governing permissions and | |
14 | * limitations under the license. | |
15 | */ | |
16 | package org.apache.logging.log4j.core.lookup; | |
17 | ||
18 | import org.apache.logging.log4j.core.LogEvent; | |
19 | ||
20 | import java.util.Collections; | |
21 | import java.util.Map; | |
22 | ||
23 | /** | |
24 | * A lookup designed for {@code Properties} defined in the configuration. This is similar | |
25 | * to {@link MapLookup} without special handling for structured messages. | |
26 | * | |
27 | * Note that this lookup is not a plugin, but wired as a default lookup in the configuration. | |
28 | */ | |
29 | public final class PropertiesLookup implements StrLookup { | |
30 | ||
31 | /** | |
32 | * Configuration from which to read properties. | |
33 | */ | |
34 | private final Map<String, String> properties; | |
35 | ||
36 | public PropertiesLookup(final Map<String, String> properties) { | |
37 | this.properties = properties == null | |
38 | ? Collections.emptyMap() | |
39 | : properties; | |
40 | } | |
41 | ||
42 | @Override | |
43 | public String lookup( | |
44 | @SuppressWarnings("ignored") final LogEvent event, | |
45 | final String key) { | |
46 | return lookup(key); | |
47 | } | |
48 | ||
49 | /** | |
50 | * Looks a value from configuration properties. | |
51 | * <p> | |
52 | * If the property is not defined, then null is returned. | |
53 | * </p> | |
54 | * | |
55 | * @param key the key to be looked up, may be null | |
56 | * @return the matching value, null if no match | |
57 | */ | |
58 | @Override | |
59 | public String lookup(final String key) { | |
60 | return key == null ? null : properties.get(key); | |
61 | } | |
62 | ||
63 | @Override | |
64 | public String toString() { | |
65 | return "PropertiesLookup{properties=" + properties + '}'; | |
66 | } | |
67 | } |
226 | 226 | * @param valueMap the map with the variables' values, may be null |
227 | 227 | */ |
228 | 228 | public StrSubstitutor(final Map<String, String> valueMap) { |
229 | this(new MapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); | |
229 | this(new PropertiesLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE); | |
230 | 230 | } |
231 | 231 | |
232 | 232 | /** |
238 | 238 | * @throws IllegalArgumentException if the prefix or suffix is null |
239 | 239 | */ |
240 | 240 | public StrSubstitutor(final Map<String, String> valueMap, final String prefix, final String suffix) { |
241 | this(new MapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE); | |
241 | this(new PropertiesLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE); | |
242 | 242 | } |
243 | 243 | |
244 | 244 | /** |
252 | 252 | */ |
253 | 253 | public StrSubstitutor(final Map<String, String> valueMap, final String prefix, final String suffix, |
254 | 254 | final char escape) { |
255 | this(new MapLookup(valueMap), prefix, suffix, escape); | |
255 | this(new PropertiesLookup(valueMap), prefix, suffix, escape); | |
256 | 256 | } |
257 | 257 | |
258 | 258 | /** |
267 | 267 | */ |
268 | 268 | public StrSubstitutor(final Map<String, String> valueMap, final String prefix, final String suffix, |
269 | 269 | final char escape, final String valueDelimiter) { |
270 | this(new MapLookup(valueMap), prefix, suffix, escape, valueDelimiter); | |
270 | this(new PropertiesLookup(valueMap), prefix, suffix, escape, valueDelimiter); | |
271 | 271 | } |
272 | 272 | |
273 | 273 | /** |
436 | 436 | */ |
437 | 437 | public static String replace(final Object source, final Properties valueProperties) { |
438 | 438 | if (valueProperties == null) { |
439 | return source.toString(); | |
439 | return Objects.toString(source, null); | |
440 | 440 | } |
441 | 441 | final Map<String, String> valueMap = new HashMap<>(); |
442 | 442 | final Enumeration<?> propNames = valueProperties.propertyNames(); |
41 | 41 | private static final String PREFIX = "log4j2.enableJndi"; |
42 | 42 | private static final String JAVA_SCHEME = "java"; |
43 | 43 | |
44 | private static final boolean JNDI_CONTEXT_SELECTOR_ENABLED = isJndiEnabled("ContextSelector"); | |
45 | private static final boolean JNDI_JDBC_ENABLED = isJndiEnabled("Jdbc"); | |
46 | private static final boolean JNDI_JMS_ENABLED = isJndiEnabled("Jms"); | |
47 | private static final boolean JNDI_LOOKUP_ENABLED = isJndiEnabled("Lookup"); | |
48 | ||
44 | 49 | private final InitialContext context; |
45 | 50 | |
46 | 51 | private static boolean isJndiEnabled(final String subKey) { |
48 | 53 | } |
49 | 54 | |
50 | 55 | public static boolean isJndiEnabled() { |
51 | return isJndiContextSelectorEnabled() || isJndiJmsEnabled() || isJndiLookupEnabled(); | |
56 | return isJndiContextSelectorEnabled() || isJndiJdbcEnabled() || isJndiJmsEnabled() || isJndiLookupEnabled(); | |
52 | 57 | } |
53 | 58 | |
54 | 59 | public static boolean isJndiContextSelectorEnabled() { |
55 | return isJndiEnabled("ContextSelector"); | |
60 | return JNDI_CONTEXT_SELECTOR_ENABLED; | |
61 | } | |
62 | ||
63 | public static boolean isJndiJdbcEnabled() { | |
64 | return JNDI_JDBC_ENABLED; | |
56 | 65 | } |
57 | 66 | |
58 | 67 | public static boolean isJndiJmsEnabled() { |
59 | return isJndiEnabled("Jms"); | |
68 | return JNDI_JMS_ENABLED; | |
60 | 69 | } |
61 | 70 | |
62 | 71 | public static boolean isJndiLookupEnabled() { |
63 | return isJndiEnabled("Lookup"); | |
72 | return JNDI_LOOKUP_ENABLED; | |
64 | 73 | } |
65 | 74 | |
66 | 75 | private JndiManager(final String name, final InitialContext context) { |
203 | 212 | } |
204 | 213 | LOGGER.warn("Unsupported JNDI URI - {}", name); |
205 | 214 | } catch (URISyntaxException ex) { |
206 | LOGGER.warn("Invalid JNDI URI - {}", name); | |
215 | LOGGER.warn("Invalid JNDI URI - {}", name); | |
207 | 216 | } |
208 | 217 | return null; |
209 | 218 | } |
16 | 16 | package org.apache.logging.log4j.core.util; |
17 | 17 | |
18 | 18 | import java.io.File; |
19 | import java.net.Inet4Address; | |
20 | import java.net.Inet6Address; | |
21 | 19 | import java.net.InetAddress; |
22 | 20 | import java.net.MalformedURLException; |
23 | 21 | import java.net.NetworkInterface; |
26 | 24 | import java.net.URISyntaxException; |
27 | 25 | import java.net.URL; |
28 | 26 | import java.net.UnknownHostException; |
29 | import java.util.ArrayList; | |
30 | 27 | import java.util.Arrays; |
31 | 28 | import java.util.Enumeration; |
32 | import java.util.List; | |
33 | 29 | |
34 | 30 | import org.apache.logging.log4j.Logger; |
35 | 31 | import org.apache.logging.log4j.status.StatusLogger; |
36 | import org.apache.logging.log4j.util.Strings; | |
37 | 32 | |
38 | 33 | /** |
39 | 34 | * Networking-related convenience methods. |
80 | 75 | } |
81 | 76 | LOGGER.error("Could not determine local host name", uhe); |
82 | 77 | return UNKNOWN_LOCALHOST; |
83 | } | |
84 | } | |
85 | ||
86 | /** | |
87 | * Returns all the local host names and ip addresses. | |
88 | * @return The local host names and ip addresses. | |
89 | */ | |
90 | public static List<String> getLocalIps() { | |
91 | List<String> localIps = new ArrayList<>(); | |
92 | localIps.add("localhost"); | |
93 | localIps.add("127.0.0.1"); | |
94 | try { | |
95 | final InetAddress addr = Inet4Address.getLocalHost(); | |
96 | setHostName(addr, localIps); | |
97 | } catch (final UnknownHostException ex) { | |
98 | // Ignore this. | |
99 | } | |
100 | try { | |
101 | final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); | |
102 | if (interfaces != null) { | |
103 | while (interfaces.hasMoreElements()) { | |
104 | final NetworkInterface nic = interfaces.nextElement(); | |
105 | final Enumeration<InetAddress> addresses = nic.getInetAddresses(); | |
106 | while (addresses.hasMoreElements()) { | |
107 | final InetAddress address = addresses.nextElement(); | |
108 | setHostName(address, localIps); | |
109 | } | |
110 | } | |
111 | } | |
112 | } catch (final SocketException se) { | |
113 | // ignore. | |
114 | } | |
115 | return localIps; | |
116 | } | |
117 | ||
118 | private static void setHostName(InetAddress address, List<String> localIps) { | |
119 | String[] parts = address.toString().split("\\s*/\\s*"); | |
120 | if (parts.length > 0) { | |
121 | for (String part : parts) { | |
122 | if (Strings.isNotBlank(part) && !localIps.contains(part)) { | |
123 | localIps.add(part); | |
124 | } | |
125 | } | |
126 | 78 | } |
127 | 79 | } |
128 | 80 |
21 | 21 | |
22 | 22 | import org.apache.logging.log4j.Level; |
23 | 23 | import org.apache.logging.log4j.Logger; |
24 | import org.apache.logging.log4j.core.lookup.StrSubstitutor; | |
24 | 25 | import org.apache.logging.log4j.status.StatusLogger; |
25 | import org.apache.logging.log4j.util.PropertiesUtil; | |
26 | import org.apache.logging.log4j.util.Strings; | |
27 | 26 | |
28 | 27 | /** |
29 | 28 | * A convenience class to convert property values to specific types. |
32 | 31 | |
33 | 32 | private static final Logger LOGGER = StatusLogger.getLogger(); |
34 | 33 | |
35 | private static final String DELIM_START = "${"; | |
36 | private static final char DELIM_STOP = '}'; | |
37 | private static final int DELIM_START_LEN = 2; | |
38 | private static final int DELIM_STOP_LEN = 1; | |
39 | 34 | private static final int ONE_K = 1024; |
40 | 35 | |
41 | 36 | /** |
166 | 161 | if (hashIndex == -1) { |
167 | 162 | if("NULL".equalsIgnoreCase(value)) { |
168 | 163 | return null; |
169 | } else { | |
170 | // no class name specified : use standard Level class | |
171 | return Level.toLevel(value, defaultValue); | |
172 | } | |
164 | } | |
165 | // no class name specified : use standard Level class | |
166 | return Level.toLevel(value, defaultValue); | |
173 | 167 | } |
174 | 168 | |
175 | 169 | Level result = defaultValue; |
346 | 340 | */ |
347 | 341 | public static String substVars(final String val, final Properties props) throws |
348 | 342 | IllegalArgumentException { |
349 | ||
350 | final StringBuilder sbuf = new StringBuilder(); | |
351 | ||
352 | int i = 0; | |
353 | int j; | |
354 | int k; | |
355 | ||
356 | while (true) { | |
357 | j = val.indexOf(DELIM_START, i); | |
358 | if (j == -1) { | |
359 | // no more variables | |
360 | if (i == 0) { // this is a simple string | |
361 | return val; | |
362 | } | |
363 | // add the tail string which contails no variables and return the result. | |
364 | sbuf.append(val.substring(i, val.length())); | |
365 | return sbuf.toString(); | |
366 | } | |
367 | sbuf.append(val.substring(i, j)); | |
368 | k = val.indexOf(DELIM_STOP, j); | |
369 | if (k == -1) { | |
370 | throw new IllegalArgumentException(Strings.dquote(val) | |
371 | + " has no closing brace. Opening brace at position " + j | |
372 | + '.'); | |
373 | } | |
374 | j += DELIM_START_LEN; | |
375 | final String key = val.substring(j, k); | |
376 | // first try in System properties | |
377 | String replacement = PropertiesUtil.getProperties().getStringProperty(key, null); | |
378 | // then try props parameter | |
379 | if (replacement == null && props != null) { | |
380 | replacement = props.getProperty(key); | |
381 | } | |
382 | ||
383 | if (replacement != null) { | |
384 | // Do variable substitution on the replacement string | |
385 | // such that we can solve "Hello ${x2}" as "Hello p1" | |
386 | // the where the properties are | |
387 | // x1=p1 | |
388 | // x2=${x1} | |
389 | final String recursiveReplacement = substVars(replacement, props); | |
390 | sbuf.append(recursiveReplacement); | |
391 | } | |
392 | i = k + DELIM_STOP_LEN; | |
393 | } | |
343 | return StrSubstitutor.replace(val, props); | |
394 | 344 | } |
395 | 345 | } |
+8
-5
15 | 15 | */ |
16 | 16 | package org.apache.logging.log4j.core.appender.db.jdbc; |
17 | 17 | |
18 | import static org.junit.Assert.assertEquals; | |
19 | import static org.junit.Assert.assertFalse; | |
20 | import static org.junit.Assert.assertTrue; | |
21 | import static org.mockito.BDDMockito.given; | |
22 | import static org.mockito.Mockito.mock; | |
23 | ||
18 | 24 | import java.io.ByteArrayOutputStream; |
19 | 25 | import java.io.PrintWriter; |
20 | 26 | import java.sql.Connection; |
21 | 27 | import java.sql.ResultSet; |
22 | 28 | import java.sql.SQLException; |
23 | 29 | import java.sql.Statement; |
30 | ||
24 | 31 | import javax.sql.DataSource; |
25 | 32 | |
26 | 33 | import org.apache.logging.log4j.LogManager; |
34 | 41 | import org.junit.Test; |
35 | 42 | import org.junit.rules.RuleChain; |
36 | 43 | |
37 | import static org.junit.Assert.*; | |
38 | import static org.mockito.BDDMockito.given; | |
39 | import static org.mockito.Mockito.mock; | |
40 | ||
41 | 44 | /** |
42 | 45 | * Abstract unit test for JdbcAppender using a {@link DataSource} configuration. |
43 | 46 | */ |
44 | public abstract class AbstractJdbcAppenderDataSourceTest { | |
47 | public abstract class AbstractJdbcAppenderDataSourceTest extends AbstractJdbcDataSourceTest { | |
45 | 48 | |
46 | 49 | @Rule |
47 | 50 | public final RuleChain rules; |
+39
-0
0 | /* | |
1 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
2 | * contributor license agreements. See the NOTICE file distributed with | |
3 | * this work for additional information regarding copyright ownership. | |
4 | * The ASF licenses this file to You under the Apache license, Version 2.0 | |
5 | * (the "License"); you may not use this file except in compliance with | |
6 | * the License. You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the license for the specific language governing permissions and | |
14 | * limitations under the license. | |
15 | */ | |
16 | package org.apache.logging.log4j.core.appender.db.jdbc; | |
17 | ||
18 | import javax.sql.DataSource; | |
19 | ||
20 | import org.junit.AfterClass; | |
21 | import org.junit.BeforeClass; | |
22 | ||
23 | /** | |
24 | * Abstract unit test for JDBC using a {@link DataSource} configuration. | |
25 | */ | |
26 | public abstract class AbstractJdbcDataSourceTest { | |
27 | ||
28 | @AfterClass | |
29 | public static void afterClass() throws Exception { | |
30 | System.clearProperty("log4j2.enableJndiJdbc"); | |
31 | } | |
32 | ||
33 | @BeforeClass | |
34 | public static void beforeClass() throws Exception { | |
35 | System.setProperty("log4j2.enableJndiJdbc", "true"); | |
36 | } | |
37 | ||
38 | } |
+1
-1
36 | 36 | import org.junit.runners.Parameterized; |
37 | 37 | |
38 | 38 | @RunWith(Parameterized.class) |
39 | public class DataSourceConnectionSourceTest { | |
39 | public class DataSourceConnectionSourceTest extends AbstractJdbcDataSourceTest { | |
40 | 40 | |
41 | 41 | @Parameterized.Parameters(name = "{0}") |
42 | 42 | public static Object[][] data() { |
+1
-1
45 | 45 | /** |
46 | 46 | * Unit tests {@link MapMessage}s for JdbcAppender using a {@link DataSource} configuration. |
47 | 47 | */ |
48 | public class JdbcAppenderMapMessageDataSourceTest { | |
48 | public class JdbcAppenderMapMessageDataSourceTest extends AbstractJdbcDataSourceTest { | |
49 | 49 | |
50 | 50 | @Rule |
51 | 51 | public final RuleChain rules; |
+2
-1
47 | 47 | import org.apache.logging.log4j.message.Message; |
48 | 48 | import org.apache.logging.log4j.message.SimpleMessage; |
49 | 49 | import org.apache.logging.log4j.message.StringMapMessage; |
50 | import org.junit.AfterClass; | |
50 | 51 | import org.junit.Before; |
51 | 52 | import org.junit.BeforeClass; |
52 | 53 | import org.junit.Rule; |
83 | 84 | @Rule |
84 | 85 | public RuleChain rules = RuleChain.outerRule(jndiRule).around(ctx); |
85 | 86 | |
86 | @BeforeClass | |
87 | @AfterClass | |
87 | 88 | public static void afterClass() throws Exception { |
88 | 89 | System.clearProperty("log4j2.enableJndiJms"); |
89 | 90 | } |
+1
-1
26 | 26 | public class RollingFileAppenderReconfigureTest { |
27 | 27 | |
28 | 28 | @Rule |
29 | public final LoggerContextRule loggerContextRule = new LoggerContextRule("src/test/rolling-file-appender-reconfigure.xml"); | |
29 | public final LoggerContextRule loggerContextRule = new LoggerContextRule("rolling-file-appender-reconfigure.xml"); | |
30 | 30 | |
31 | 31 | @Test |
32 | 32 | public void testReconfigure() { |
+57
-1
16 | 16 | package org.apache.logging.log4j.core.lookup; |
17 | 17 | |
18 | 18 | import java.text.SimpleDateFormat; |
19 | import java.util.Collections; | |
19 | 20 | import java.util.Date; |
20 | 21 | import java.util.HashMap; |
21 | 22 | import java.util.Map; |
22 | 23 | |
24 | import org.apache.logging.log4j.Level; | |
23 | 25 | import org.apache.logging.log4j.ThreadContext; |
26 | import org.apache.logging.log4j.core.LogEvent; | |
27 | import org.apache.logging.log4j.core.Logger; | |
28 | import org.apache.logging.log4j.core.impl.Log4jLogEvent; | |
24 | 29 | import org.apache.logging.log4j.junit.JndiRule; |
25 | import org.junit.BeforeClass; | |
30 | import org.apache.logging.log4j.message.StringMapMessage; | |
26 | 31 | import org.junit.ClassRule; |
27 | 32 | import org.junit.Test; |
28 | 33 | import org.junit.rules.ExternalResource; |
29 | 34 | import org.junit.rules.RuleChain; |
30 | 35 | |
31 | 36 | import static org.junit.Assert.*; |
37 | import static org.junit.jupiter.api.Assertions.assertEquals; | |
38 | import static org.junit.jupiter.api.Assertions.assertNull; | |
32 | 39 | |
33 | 40 | /** |
34 | 41 | * |
111 | 118 | assertLookupNotEmpty(lookup, "java:locale"); |
112 | 119 | assertLookupNotEmpty(lookup, "java:hw"); |
113 | 120 | } |
121 | ||
122 | ||
123 | @Test | |
124 | public void testInterpolatorMapMessageWithNoPrefix() { | |
125 | final HashMap<String, String> configProperties = new HashMap<>(); | |
126 | configProperties.put("key", "configProperties"); | |
127 | Interpolator interpolator = new Interpolator(configProperties); | |
128 | final HashMap<String, String> map = new HashMap<>(); | |
129 | map.put("key", "mapMessage"); | |
130 | LogEvent event = Log4jLogEvent.newBuilder() | |
131 | .setLoggerName(getClass().getName()) | |
132 | .setLoggerFqcn(Logger.class.getName()) | |
133 | .setLevel(Level.INFO) | |
134 | .setMessage(new StringMapMessage(map)) | |
135 | .build(); | |
136 | assertEquals("configProperties", interpolator.lookup(event, "key")); | |
137 | } | |
138 | ||
139 | @Test | |
140 | public void testInterpolatorMapMessageWithNoPrefixConfigDoesntMatch() { | |
141 | Interpolator interpolator = new Interpolator(Collections.emptyMap()); | |
142 | final HashMap<String, String> map = new HashMap<>(); | |
143 | map.put("key", "mapMessage"); | |
144 | LogEvent event = Log4jLogEvent.newBuilder() | |
145 | .setLoggerName(getClass().getName()) | |
146 | .setLoggerFqcn(Logger.class.getName()) | |
147 | .setLevel(Level.INFO) | |
148 | .setMessage(new StringMapMessage(map)) | |
149 | .build(); | |
150 | assertNull( | |
151 | interpolator.lookup(event, "key"), | |
152 | "Values without a map prefix should not match MapMessages"); | |
153 | } | |
154 | ||
155 | @Test | |
156 | public void testInterpolatorMapMessageWithMapPrefix() { | |
157 | final HashMap<String, String> configProperties = new HashMap<>(); | |
158 | configProperties.put("key", "configProperties"); | |
159 | Interpolator interpolator = new Interpolator(configProperties); | |
160 | final HashMap<String, String> map = new HashMap<>(); | |
161 | map.put("key", "mapMessage"); | |
162 | LogEvent event = Log4jLogEvent.newBuilder() | |
163 | .setLoggerName(getClass().getName()) | |
164 | .setLoggerFqcn(Logger.class.getName()) | |
165 | .setLevel(Level.INFO) | |
166 | .setMessage(new StringMapMessage(map)) | |
167 | .build(); | |
168 | assertEquals("mapMessage", interpolator.lookup(event, "map:key")); | |
169 | } | |
114 | 170 | } |
+16
-0
14 | 14 | * limitations under the license. |
15 | 15 | */ |
16 | 16 | package org.apache.logging.log4j.core.lookup; |
17 | ||
18 | import org.apache.logging.log4j.core.LogEvent; | |
17 | 19 | |
18 | 20 | import java.util.Map; |
19 | 21 | |
53 | 55 | public MainInputArgumentsMapLookup(final Map<String, String> map) { |
54 | 56 | super(map); |
55 | 57 | } |
58 | ||
59 | @Override | |
60 | public String lookup(final LogEvent event, final String key) { | |
61 | return lookup(key); | |
62 | } | |
63 | ||
64 | @Override | |
65 | public String lookup(final String key) { | |
66 | if (key == null) { | |
67 | return null; | |
68 | } | |
69 | Map<String, String> map = getMap(); | |
70 | return map == null ? null : map.get(key); | |
71 | } | |
56 | 72 | } |
96 | 96 | } |
97 | 97 | |
98 | 98 | @Test |
99 | public void testLookupDefaultMapIsCheckedBeforeMapMessage() { | |
99 | public void testLookupMapMessageIsCheckedBeforeDefaultMap() { | |
100 | 100 | final HashMap<String, String> map = new HashMap<>(); |
101 | 101 | map.put("A", "ADefault"); |
102 | map.put("B", "BDefault"); | |
102 | 103 | final HashMap<String, Object> eventMap = new HashMap<>(); |
103 | 104 | eventMap.put("A", "AEvent"); |
104 | 105 | final MapMessage message = new MapMessage<>(eventMap); |
106 | 107 | .setMessage(message) |
107 | 108 | .build(); |
108 | 109 | final MapLookup lookup = new MapLookup(map); |
109 | assertEquals("ADefault", lookup.lookup(event, "A")); | |
110 | assertEquals("AEvent", lookup.lookup(event, "A")); | |
111 | assertEquals("BDefault", lookup.lookup(event, "B")); | |
110 | 112 | } |
111 | 113 | |
112 | 114 | @Test |
+167
-125
15 | 15 | */ |
16 | 16 | package org.apache.logging.log4j.core.lookup; |
17 | 17 | |
18 | import static org.junit.jupiter.api.Assertions.assertEquals; | |
19 | import static org.junit.jupiter.api.Assertions.assertNull; | |
20 | ||
18 | 21 | import java.util.HashMap; |
19 | 22 | import java.util.Map; |
23 | import java.util.Properties; | |
20 | 24 | |
21 | 25 | import org.apache.logging.log4j.ThreadContext; |
22 | 26 | import org.apache.logging.log4j.core.LogEvent; |
24 | 28 | import org.junit.jupiter.api.BeforeAll; |
25 | 29 | import org.junit.jupiter.api.Test; |
26 | 30 | |
27 | import static org.junit.jupiter.api.Assertions.*; | |
28 | ||
29 | 31 | public class StrSubstitutorTest { |
30 | 32 | |
31 | 33 | private static final String TESTKEY = "TestKey"; |
32 | 34 | private static final String TESTVAL = "TestValue"; |
33 | 35 | |
36 | ||
37 | @AfterAll | |
38 | public static void after() { | |
39 | System.clearProperty(TESTKEY); | |
40 | } | |
34 | 41 | |
35 | 42 | @BeforeAll |
36 | 43 | public static void before() { |
37 | 44 | System.setProperty(TESTKEY, TESTVAL); |
38 | 45 | } |
39 | 46 | |
40 | @AfterAll | |
41 | public static void after() { | |
42 | System.clearProperty(TESTKEY); | |
43 | } | |
44 | ||
47 | ||
48 | @Test | |
49 | public void testDefault() { | |
50 | final Map<String, String> map = new HashMap<>(); | |
51 | map.put(TESTKEY, TESTVAL); | |
52 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
53 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
54 | ThreadContext.put(TESTKEY, TESTVAL); | |
55 | //String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); | |
56 | final String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); | |
57 | assertEquals("TestValue", value); | |
58 | } | |
59 | ||
60 | @Test | |
61 | public void testDefaultReferencesLookupValue() { | |
62 | final Map<String, String> map = new HashMap<>(); | |
63 | map.put(TESTKEY, "${java:version}"); | |
64 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
65 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
66 | subst.setRecursiveEvaluationAllowed(false); | |
67 | final String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); | |
68 | assertEquals("${java:version}", value); | |
69 | } | |
70 | ||
71 | @Test | |
72 | public void testInfiniteSubstitutionOnString() { | |
73 | final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>())); | |
74 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
75 | subst.setRecursiveEvaluationAllowed(true); | |
76 | String infiniteSubstitution = "${${::-${::-$${::-j}}}}"; | |
77 | assertEquals(infiniteSubstitution, subst.replace(infiniteSubstitution)); | |
78 | } | |
79 | ||
80 | @Test | |
81 | public void testInfiniteSubstitutionOnStringBuilder() { | |
82 | final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>())); | |
83 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
84 | subst.setRecursiveEvaluationAllowed(true); | |
85 | String infiniteSubstitution = "${${::-${::-$${::-j}}}}"; | |
86 | assertEquals(infiniteSubstitution, subst.replace(null, new StringBuilder(infiniteSubstitution))); | |
87 | } | |
45 | 88 | |
46 | 89 | @Test |
47 | 90 | public void testLookup() { |
64 | 107 | } |
65 | 108 | |
66 | 109 | @Test |
67 | public void testDefault() { | |
68 | final Map<String, String> map = new HashMap<>(); | |
69 | map.put(TESTKEY, TESTVAL); | |
70 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
71 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
72 | ThreadContext.put(TESTKEY, TESTVAL); | |
73 | //String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); | |
74 | final String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); | |
75 | assertEquals("TestValue", value); | |
76 | } | |
77 | ||
78 | @Test | |
79 | public void testDefaultReferencesLookupValue() { | |
80 | final Map<String, String> map = new HashMap<>(); | |
81 | map.put(TESTKEY, "${java:version}"); | |
82 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
83 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
84 | subst.setRecursiveEvaluationAllowed(false); | |
85 | final String value = subst.replace("${sys:TestKey1:-${ctx:TestKey}}"); | |
86 | assertEquals("${java:version}", value); | |
87 | } | |
88 | ||
89 | @Test | |
90 | public void testInfiniteSubstitutionOnString() { | |
91 | final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>())); | |
92 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
93 | subst.setRecursiveEvaluationAllowed(true); | |
94 | String infiniteSubstitution = "${${::-${::-$${::-j}}}}"; | |
95 | assertEquals(infiniteSubstitution, subst.replace(infiniteSubstitution)); | |
96 | } | |
97 | ||
98 | @Test | |
99 | public void testInfiniteSubstitutionOnStringBuilder() { | |
100 | final StrLookup lookup = new Interpolator(new MapLookup(new HashMap<>())); | |
101 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
102 | subst.setRecursiveEvaluationAllowed(true); | |
103 | String infiniteSubstitution = "${${::-${::-$${::-j}}}}"; | |
104 | assertEquals(infiniteSubstitution, subst.replace(null, new StringBuilder(infiniteSubstitution))); | |
105 | } | |
106 | ||
107 | @Test | |
108 | public void testRecursiveSubstitution() { | |
109 | final Map<String, String> map = new HashMap<>(); | |
110 | map.put("first", "${ctx:first}"); | |
111 | map.put("second", "secondValue"); | |
112 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
113 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
114 | subst.setRecursiveEvaluationAllowed(true); | |
115 | assertEquals("${ctx:first} and secondValue", subst.replace("${ctx:first} and ${ctx:second}")); | |
116 | } | |
117 | ||
118 | @Test | |
119 | public void testRecursiveWithDefault() { | |
120 | final Map<String, String> map = new HashMap<>(); | |
121 | map.put("first", "${ctx:first:-default}"); | |
122 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
123 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
124 | subst.setRecursiveEvaluationAllowed(true); | |
125 | assertEquals("default", subst.replace("${ctx:first}")); | |
126 | } | |
127 | ||
128 | @Test | |
129 | public void testRecursiveWithRecursiveDefault() { | |
130 | final Map<String, String> map = new HashMap<>(); | |
131 | map.put("first", "${ctx:first:-${ctx:first}}"); | |
132 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
133 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
134 | subst.setRecursiveEvaluationAllowed(true); | |
135 | assertEquals("${ctx:first}", subst.replace("${ctx:first}")); | |
136 | } | |
137 | ||
138 | @Test | |
139 | public void testNestedSelfReferenceWithRecursiveEvaluation() { | |
140 | final Map<String, String> map = new HashMap<>(); | |
141 | map.put("first", "${${ctx:first}}"); | |
142 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
143 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
144 | subst.setRecursiveEvaluationAllowed(true); | |
145 | assertEquals("${${ctx:first}}", subst.replace("${ctx:first}")); | |
146 | } | |
147 | ||
148 | @Test | |
149 | public void testRandomWithRecursiveDefault() { | |
150 | final Map<String, String> map = new HashMap<>(); | |
151 | map.put("first", "${env:RANDOM:-${ctx:first}}"); | |
152 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
153 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
154 | subst.setRecursiveEvaluationAllowed(true); | |
155 | assertEquals("${ctx:first}", subst.replace("${ctx:first}")); | |
156 | } | |
157 | ||
158 | @Test | |
159 | public void testNoRecursiveEvaluationWithDefault() { | |
160 | final Map<String, String> map = new HashMap<>(); | |
161 | map.put("first", "${java:version}"); | |
162 | map.put("second", "${java:runtime}"); | |
163 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
164 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
165 | subst.setRecursiveEvaluationAllowed(false); | |
166 | assertEquals("${java:version}", subst.replace("${ctx:first:-${ctx:second}}")); | |
167 | } | |
168 | ||
169 | @Test | |
170 | public void testNoRecursiveEvaluationWithDepthOne() { | |
171 | final Map<String, String> map = new HashMap<>(); | |
172 | map.put("first", "${java:version}"); | |
173 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
174 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
175 | subst.setRecursiveEvaluationAllowed(false); | |
176 | assertEquals("${java:version}", subst.replace("${ctx:first}")); | |
177 | } | |
178 | ||
179 | @Test | |
180 | 110 | public void testLookupsNestedWithoutRecursiveEvaluation() { |
181 | 111 | final Map<String, String> map = new HashMap<>(); |
182 | 112 | map.put("first", "${java:version}"); |
189 | 119 | @Test |
190 | 120 | public void testLookupThrows() { |
191 | 121 | final StrSubstitutor subst = new StrSubstitutor(new Interpolator(new StrLookup() { |
122 | ||
123 | @Override | |
124 | public String lookup(LogEvent event, String key) { | |
125 | return lookup(key); | |
126 | } | |
192 | 127 | |
193 | 128 | @Override |
194 | 129 | public String lookup(String key) { |
197 | 132 | } |
198 | 133 | return "success"; |
199 | 134 | } |
200 | ||
201 | @Override | |
202 | public String lookup(LogEvent event, String key) { | |
203 | return lookup(key); | |
204 | } | |
205 | 135 | })); |
206 | 136 | subst.setRecursiveEvaluationAllowed(false); |
207 | 137 | assertEquals("success ${foo:throw} success", subst.replace("${foo:a} ${foo:throw} ${foo:c}")); |
208 | 138 | } |
139 | ||
140 | @Test | |
141 | public void testNestedSelfReferenceWithRecursiveEvaluation() { | |
142 | final Map<String, String> map = new HashMap<>(); | |
143 | map.put("first", "${${ctx:first}}"); | |
144 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
145 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
146 | subst.setRecursiveEvaluationAllowed(true); | |
147 | assertEquals("${${ctx:first}}", subst.replace("${ctx:first}")); | |
148 | } | |
149 | ||
150 | @Test | |
151 | public void testNoRecursiveEvaluationWithDefault() { | |
152 | final Map<String, String> map = new HashMap<>(); | |
153 | map.put("first", "${java:version}"); | |
154 | map.put("second", "${java:runtime}"); | |
155 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
156 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
157 | subst.setRecursiveEvaluationAllowed(false); | |
158 | assertEquals("${java:version}", subst.replace("${ctx:first:-${ctx:second}}")); | |
159 | } | |
160 | ||
161 | @Test | |
162 | public void testNoRecursiveEvaluationWithDepthOne() { | |
163 | final Map<String, String> map = new HashMap<>(); | |
164 | map.put("first", "${java:version}"); | |
165 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
166 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
167 | subst.setRecursiveEvaluationAllowed(false); | |
168 | assertEquals("${java:version}", subst.replace("${ctx:first}")); | |
169 | } | |
170 | ||
171 | @Test | |
172 | public void testRandomWithRecursiveDefault() { | |
173 | final Map<String, String> map = new HashMap<>(); | |
174 | map.put("first", "${env:RANDOM:-${ctx:first}}"); | |
175 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
176 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
177 | subst.setRecursiveEvaluationAllowed(true); | |
178 | assertEquals("${ctx:first}", subst.replace("${ctx:first}")); | |
179 | } | |
180 | ||
181 | @Test | |
182 | public void testRecursiveSubstitution() { | |
183 | final Map<String, String> map = new HashMap<>(); | |
184 | map.put("first", "${ctx:first}"); | |
185 | map.put("second", "secondValue"); | |
186 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
187 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
188 | subst.setRecursiveEvaluationAllowed(true); | |
189 | assertEquals("${ctx:first} and secondValue", subst.replace("${ctx:first} and ${ctx:second}")); | |
190 | } | |
191 | ||
192 | @Test | |
193 | public void testRecursiveWithDefault() { | |
194 | final Map<String, String> map = new HashMap<>(); | |
195 | map.put("first", "${ctx:first:-default}"); | |
196 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
197 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
198 | subst.setRecursiveEvaluationAllowed(true); | |
199 | assertEquals("default", subst.replace("${ctx:first}")); | |
200 | } | |
201 | ||
202 | @Test | |
203 | public void testRecursiveWithRecursiveDefault() { | |
204 | final Map<String, String> map = new HashMap<>(); | |
205 | map.put("first", "${ctx:first:-${ctx:first}}"); | |
206 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
207 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
208 | subst.setRecursiveEvaluationAllowed(true); | |
209 | assertEquals("${ctx:first}", subst.replace("${ctx:first}")); | |
210 | } | |
211 | ||
212 | @Test | |
213 | public void testReplaceProperties() { | |
214 | Properties properties = new Properties(); | |
215 | properties.put("a", "A"); | |
216 | assertNull(StrSubstitutor.replace((String) null, properties)); | |
217 | assertNull(StrSubstitutor.replace((String) null, (Properties) null)); | |
218 | assertEquals("A", StrSubstitutor.replace("${a}", properties)); | |
219 | assertEquals("${a}", StrSubstitutor.replace("${a}", (Properties) null)); | |
220 | } | |
221 | ||
222 | @Test | |
223 | public void testTopLevelLookupsWithoutRecursiveEvaluation() { | |
224 | final Map<String, String> map = new HashMap<>(); | |
225 | map.put("key", "VaLuE"); | |
226 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
227 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
228 | subst.setRecursiveEvaluationAllowed(false); | |
229 | assertEquals("value", subst.replace("${lower:${ctx:key}}")); | |
230 | } | |
231 | ||
232 | @Test | |
233 | public void testTopLevelLookupsWithoutRecursiveEvaluation_doubleLower() { | |
234 | final Map<String, String> map = new HashMap<>(); | |
235 | map.put("key", "VaLuE"); | |
236 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
237 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
238 | subst.setRecursiveEvaluationAllowed(false); | |
239 | assertEquals("value", subst.replace("${lower:${lower:${ctx:key}}}")); | |
240 | } | |
241 | ||
242 | @Test | |
243 | public void testTopLevelLookupsWithoutRecursiveEvaluationAndDefaultValueLookup() { | |
244 | final Map<String, String> map = new HashMap<>(); | |
245 | map.put("key2", "TWO"); | |
246 | final StrLookup lookup = new Interpolator(new MapLookup(map)); | |
247 | final StrSubstitutor subst = new StrSubstitutor(lookup); | |
248 | subst.setRecursiveEvaluationAllowed(false); | |
249 | assertEquals("two", subst.replace("${lower:${ctx:key1:-${ctx:key2}}}")); | |
250 | } | |
209 | 251 | } |
29 | 29 | public class JndiManagerTest { |
30 | 30 | |
31 | 31 | @Test |
32 | public void testIsJndiContextSelectorEnabled() { | |
33 | assertFalse(JndiManager.isJndiContextSelectorEnabled()); | |
34 | } | |
35 | ||
36 | @Test | |
32 | 37 | public void testIsJndiEnabled() { |
33 | 38 | assertFalse(JndiManager.isJndiEnabled()); |
34 | 39 | } |
35 | 40 | |
36 | 41 | @Test |
37 | public void testIsJndiContextSelectorEnabled() { | |
38 | assertFalse(JndiManager.isJndiContextSelectorEnabled()); | |
42 | public void testIsJndiJdbcEnabled() { | |
43 | assertFalse(JndiManager.isJndiJdbcEnabled()); | |
39 | 44 | } |
40 | 45 | |
41 | 46 | @Test |
+3
-14
27 | 27 | import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; |
28 | 28 | import org.apache.logging.log4j.core.net.TcpSocketManager.HostResolver; |
29 | 29 | import org.apache.logging.log4j.status.StatusLogger; |
30 | import org.apache.logging.log4j.util.PropertiesUtil; | |
31 | 30 | import org.junit.jupiter.api.Test; |
32 | 31 | |
33 | 32 | import java.io.BufferedReader; |
199 | 198 | } |
200 | 199 | |
201 | 200 | private static void awaitUntilSucceeds(final Runnable runnable) { |
202 | final long pollIntervalMillis; | |
203 | final long timeoutSeconds; | |
204 | final boolean osWindows = PropertiesUtil.getProperties().isOsWindows(); | |
205 | if (osWindows) { | |
206 | // Windows-specific non-sense values. | |
207 | // These figures are collected by trial-and-error on a friend's laptop which has Windows installed. | |
208 | pollIntervalMillis = 1_000L; | |
209 | timeoutSeconds = 15; | |
210 | } else { | |
211 | // Universally sensible values. | |
212 | pollIntervalMillis = 1000; | |
213 | timeoutSeconds = 3; | |
214 | } | |
201 | // These figures are collected via trial-and-error; nothing scientific to look for here. | |
202 | final long pollIntervalMillis = 1_000L; | |
203 | final long timeoutSeconds = 15L; | |
215 | 204 | await() |
216 | 205 | .pollInterval(pollIntervalMillis, TimeUnit.MILLISECONDS) |
217 | 206 | .atMost(timeoutSeconds, TimeUnit.SECONDS) |
+36
-0
0 | /* | |
1 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
2 | * contributor license agreements. See the NOTICE file distributed with | |
3 | * this work for additional information regarding copyright ownership. | |
4 | * The ASF licenses this file to You under the Apache license, Version 2.0 | |
5 | * (the "License"); you may not use this file except in compliance with | |
6 | * the License. You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the license for the specific language governing permissions and | |
14 | * limitations under the license. | |
15 | */ | |
16 | package org.apache.logging.log4j.core.util; | |
17 | ||
18 | import static org.junit.jupiter.api.Assertions.assertEquals; | |
19 | ||
20 | import java.util.Properties; | |
21 | ||
22 | import org.junit.jupiter.api.Test; | |
23 | ||
24 | /** | |
25 | * Tests {@link OptionConverter}. | |
26 | */ | |
27 | public class OptionConverterTest { | |
28 | ||
29 | @Test | |
30 | public void testSubstVars() { | |
31 | Properties props = new Properties(); | |
32 | props.setProperty("key", "${key}"); | |
33 | assertEquals("Value of key is ${key}.", OptionConverter.substVars("Value of key is ${key}.", props)); | |
34 | } | |
35 | } |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-core-its</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-core-java9</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <modelVersion>4.0.0</modelVersion> |
25 | 25 |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-distribution</artifactId> |
492 | 492 | </execution> --> |
493 | 493 | </executions> |
494 | 494 | </plugin> |
495 | <!-- calculate checksums of source release for Apache dist area --> | |
496 | <plugin> | |
497 | <groupId>net.nicoulaj.maven.plugins</groupId> | |
498 | <artifactId>checksum-maven-plugin</artifactId> | |
499 | <version>1.11</version> | |
500 | <executions> | |
501 | <execution> | |
502 | <id>calculate-checksums</id> | |
503 | <goals> | |
504 | <goal>files</goal> | |
505 | </goals> | |
506 | <!-- execute prior to maven-gpg-plugin:sign due to https://github.com/nicoulaj/checksum-maven-plugin/issues/112 --> | |
507 | <phase>post-integration-test</phase> | |
508 | <configuration> | |
509 | <algorithms> | |
510 | <algorithm>SHA-256</algorithm> | |
511 | <algorithm>SHA-512</algorithm> | |
512 | </algorithms> | |
513 | <!-- https://maven.apache.org/apache-resource-bundles/#source-release-assembly-descriptor --> | |
514 | <fileSets> | |
515 | <fileSet> | |
516 | <directory>${project.build.directory}</directory> | |
517 | <includes> | |
518 | <include>apache-log4j-${project.version}-src.zip</include> | |
519 | <include>apache-log4j-${project.version}-src.tar.gz</include> | |
520 | <include>apache-log4j-${project.version}-bin.zip</include> | |
521 | <include>apache-log4j-${project.version}-bin.tar.gz</include> | |
522 | </includes> | |
523 | </fileSet> | |
524 | </fileSets> | |
525 | <csvSummary>false</csvSummary> | |
526 | <appendFilename>true</appendFilename> | |
527 | </configuration> | |
528 | </execution> | |
529 | </executions> | |
530 | </plugin> | |
531 | <plugin> | |
532 | <groupId>org.apache.maven.plugins</groupId> | |
533 | <artifactId>maven-gpg-plugin</artifactId> | |
534 | <executions> | |
535 | <execution> | |
536 | <id>sign-release-artifacts</id> | |
537 | <goals> | |
538 | <goal>sign</goal> | |
539 | </goals> | |
540 | <configuration> | |
541 | <keyname>${Log4jSigningUserName}</keyname> | |
542 | </configuration> | |
543 | </execution> | |
544 | </executions> | |
545 | </plugin> | |
495 | 546 | <plugin> |
496 | 547 | <groupId>org.apache.maven.plugins</groupId> |
497 | 548 | <artifactId>maven-site-plugin</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-docker</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-flume-ng</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-iostreams</artifactId> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <modelVersion>4.0.0</modelVersion> |
25 | 25 |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-jcl</artifactId> |
10 | 10 | <parent> |
11 | 11 | <groupId>org.apache.logging.log4j</groupId> |
12 | 12 | <artifactId>log4j</artifactId> |
13 | <version>2.17.0</version> | |
13 | <version>2.17.1</version> | |
14 | 14 | </parent> |
15 | 15 | <modelVersion>4.0.0</modelVersion> |
16 | 16 |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-jmx-gui</artifactId> |
10 | 10 | <parent> |
11 | 11 | <groupId>org.apache.logging.log4j</groupId> |
12 | 12 | <artifactId>log4j</artifactId> |
13 | <version>2.17.0</version> | |
13 | <version>2.17.1</version> | |
14 | 14 | </parent> |
15 | 15 | <modelVersion>4.0.0</modelVersion> |
16 | 16 |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <modelVersion>4.0.0</modelVersion> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <modelVersion>4.0.0</modelVersion> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-kubernetes</artifactId> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.apache.logging.log4j</groupId> |
23 | 23 | <artifactId>log4j</artifactId> |
24 | <version>2.17.0</version> | |
24 | <version>2.17.1</version> | |
25 | 25 | </parent> |
26 | 26 | |
27 | 27 | <artifactId>log4j-layout-template-json</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-liquibase</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <modelVersion>4.0.0</modelVersion> |
25 | 25 |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <modelVersion>4.0.0</modelVersion> |
25 | 25 |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-osgi</artifactId> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j-samples</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j.samples</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <artifactId>log4j-samples-configuration</artifactId> |
25 | 25 | <packaging>jar</packaging> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j-samples</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j.samples</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <artifactId>log4j-samples-flume-common</artifactId> |
25 | 25 | <packaging>jar</packaging> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j-samples</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j.samples</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <artifactId>log4j-samples-flume-embedded</artifactId> |
25 | 25 | <packaging>war</packaging> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j-samples</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j.samples</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <artifactId>log4j-samples-flume-remote</artifactId> |
25 | 25 | <packaging>war</packaging> |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j-samples</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j.samples</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <artifactId>log4j-samples-loggerProperties</artifactId> |
25 | 25 | <packaging>jar</packaging> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <groupId>org.apache.logging.log4j.samples</groupId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-slf4j-impl</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-slf4j18-impl</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-spring-boot</artifactId> |
+20
-0
17 | 17 | |
18 | 18 | import org.apache.logging.log4j.LogManager; |
19 | 19 | import org.apache.logging.log4j.core.LoggerContext; |
20 | import org.apache.logging.log4j.core.lookup.Interpolator; | |
21 | import org.apache.logging.log4j.core.lookup.StrLookup; | |
20 | 22 | import org.junit.Test; |
21 | 23 | import org.springframework.mock.env.MockEnvironment; |
22 | 24 | |
56 | 58 | assertNotNull("Did not find property", result); |
57 | 59 | assertEquals("Incorrect property value", "test", result); |
58 | 60 | } |
61 | ||
62 | @Test | |
63 | public void testSpringLookupWithDefaultInterpolator() { | |
64 | MockEnvironment env = new MockEnvironment(); | |
65 | env.setActiveProfiles("test"); | |
66 | env.setProperty("app.property", "test"); | |
67 | LoggerContext context = (LoggerContext) LogManager.getContext(false); | |
68 | context.putObject(Log4j2CloudConfigLoggingSystem.ENVIRONMENT_KEY, env); | |
69 | ||
70 | StrLookup lookup = new Interpolator(); | |
71 | String result = lookup.lookup("spring:profiles.active"); | |
72 | assertNotNull("No active profiles", result); | |
73 | assertEquals("Incorrect active profile", "test", result); | |
74 | ||
75 | result = lookup.lookup("spring:app.property"); | |
76 | assertNotNull("Did not find property", result); | |
77 | assertEquals("Incorrect property value", "test", result); | |
78 | } | |
59 | 79 | } |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j-spring-cloud-config</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-spring-cloud-config-client</artifactId> |
+1
-1
20 | 20 | <parent> |
21 | 21 | <groupId>org.apache.logging.log4j.samples</groupId> |
22 | 22 | <artifactId>log4j-spring-cloud-config-samples</artifactId> |
23 | <version>2.17.0</version> | |
23 | <version>2.17.1</version> | |
24 | 24 | <relativePath>..</relativePath> |
25 | 25 | </parent> |
26 | 26 |
+2
-2
20 | 20 | <groupId>org.apache.logging.log4j.samples</groupId> |
21 | 21 | <artifactId>log4j-spring-cloud-config-sample-server</artifactId> |
22 | 22 | <packaging>jar</packaging> |
23 | <version>2.17.0</version> | |
23 | <version>2.17.1</version> | |
24 | 24 | |
25 | 25 | <name>Apache Log4j Sample Configuration Service</name> |
26 | 26 | <description>Sample Cloud Config Server</description> |
304 | 304 | </profiles> |
305 | 305 | |
306 | 306 | <scm> |
307 | <tag>log4j-2.17.0-rc1</tag> | |
307 | <tag>log4j-2.17.1-rc1</tag> | |
308 | 308 | </scm> |
309 | 309 | </project> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j-spring-cloud-config</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <groupId>org.apache.logging.log4j.samples</groupId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <groupId>org.apache.logging.log4j</groupId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-taglib</artifactId> |
19 | 19 | <parent> |
20 | 20 | <groupId>org.apache.logging.log4j</groupId> |
21 | 21 | <artifactId>log4j</artifactId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <relativePath>../</relativePath> |
24 | 24 | </parent> |
25 | 25 | <artifactId>log4j-to-slf4j</artifactId> |
24 | 24 | import org.slf4j.MarkerFactory; |
25 | 25 | import org.slf4j.spi.LocationAwareLogger; |
26 | 26 | |
27 | /** | |
28 | * | |
29 | */ | |
30 | 27 | public class SLF4JLogger extends AbstractLogger { |
31 | 28 | |
32 | 29 | private static final long serialVersionUID = 1L; |
88 | 85 | return locationAwareLogger != null ? locationAwareLogger : logger; |
89 | 86 | } |
90 | 87 | |
91 | private org.slf4j.Marker getMarker(final Marker marker) { | |
92 | if (marker == null) { | |
93 | return null; | |
94 | } | |
88 | private static org.slf4j.Marker getMarker(final Marker marker) { | |
89 | // No marker is provided in the common case, small methods | |
90 | // are optimized more effectively. | |
91 | return marker == null ? null : convertMarker(marker); | |
92 | } | |
93 | ||
94 | private static org.slf4j.Marker convertMarker(final Marker marker) { | |
95 | 95 | final org.slf4j.Marker slf4jMarker = MarkerFactory.getMarker(marker.getName()); |
96 | 96 | final Marker[] parents = marker.getParents(); |
97 | 97 | if (parents != null) { |
224 | 224 | |
225 | 225 | @Override |
226 | 226 | public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable t) { |
227 | org.slf4j.Marker slf4jMarker = getMarker(marker); | |
228 | String formattedMessage = message.getFormattedMessage(); | |
227 | 229 | if (locationAwareLogger != null) { |
228 | 230 | if (message instanceof LoggerNameAwareMessage) { |
229 | 231 | ((LoggerNameAwareMessage) message).setLoggerName(getName()); |
230 | 232 | } |
231 | locationAwareLogger.log(getMarker(marker), fqcn, convertLevel(level), message.getFormattedMessage(), | |
232 | message.getParameters(), t); | |
233 | locationAwareLogger.log(slf4jMarker, fqcn, convertLevel(level), formattedMessage, null, t); | |
233 | 234 | } else { |
234 | 235 | switch (level.getStandardLevel()) { |
235 | 236 | case DEBUG : |
236 | logger.debug(getMarker(marker), message.getFormattedMessage(), message.getParameters(), t); | |
237 | logger.debug(slf4jMarker, formattedMessage, t); | |
237 | 238 | break; |
238 | 239 | case TRACE : |
239 | logger.trace(getMarker(marker), message.getFormattedMessage(), message.getParameters(), t); | |
240 | logger.trace(slf4jMarker, formattedMessage, t); | |
240 | 241 | break; |
241 | 242 | case INFO : |
242 | logger.info(getMarker(marker), message.getFormattedMessage(), message.getParameters(), t); | |
243 | logger.info(slf4jMarker, formattedMessage, t); | |
243 | 244 | break; |
244 | 245 | case WARN : |
245 | logger.warn(getMarker(marker), message.getFormattedMessage(), message.getParameters(), t); | |
246 | logger.warn(slf4jMarker, formattedMessage, t); | |
246 | 247 | break; |
247 | 248 | case ERROR : |
248 | logger.error(getMarker(marker), message.getFormattedMessage(), message.getParameters(), t); | |
249 | logger.error(slf4jMarker, formattedMessage, t); | |
249 | 250 | break; |
250 | 251 | default : |
251 | logger.error(getMarker(marker), message.getFormattedMessage(), message.getParameters(), t); | |
252 | logger.error(slf4jMarker, formattedMessage, t); | |
252 | 253 | break; |
253 | 254 | } |
254 | 255 | } |
21 | 21 | import org.apache.logging.log4j.spi.LoggerRegistry; |
22 | 22 | import org.slf4j.LoggerFactory; |
23 | 23 | |
24 | /** | |
25 | * | |
26 | */ | |
27 | 24 | public class SLF4JLoggerContext implements LoggerContext { |
28 | 25 | private final LoggerRegistry<ExtendedLogger> loggerRegistry = new LoggerRegistry<>(); |
29 | 26 | |
42 | 39 | |
43 | 40 | @Override |
44 | 41 | public ExtendedLogger getLogger(final String name, final MessageFactory messageFactory) { |
45 | // FIXME according to LOG4J2-1180, the below line should be: | |
46 | // FIXME if (!loggerRegistry.hasLogger(name, messageFactory)) { | |
47 | if (!loggerRegistry.hasLogger(name)) { | |
48 | // FIXME: should be loggerRegistry.putIfAbsent(name, messageFactory, | |
49 | loggerRegistry.putIfAbsent(name, null, | |
42 | if (!loggerRegistry.hasLogger(name, messageFactory)) { | |
43 | loggerRegistry.putIfAbsent(name, messageFactory, | |
50 | 44 | new SLF4JLogger(name, messageFactory, LoggerFactory.getLogger(name))); |
51 | 45 | } |
52 | // FIXME should be return loggerRegistry.getLogger(name, messageFactory); | |
53 | return loggerRegistry.getLogger(name); | |
54 | ||
55 | // TODO applying the above fixes causes (log4j-to-slf4j) LoggerTest to fail | |
46 | return loggerRegistry.getLogger(name, messageFactory); | |
56 | 47 | } |
57 | 48 | |
58 | 49 | @Override |
+0
-3
22 | 22 | import org.apache.logging.log4j.status.StatusLogger; |
23 | 23 | import org.apache.logging.log4j.util.LoaderUtil; |
24 | 24 | |
25 | /** | |
26 | * | |
27 | */ | |
28 | 25 | public class SLF4JLoggerContextFactory implements LoggerContextFactory { |
29 | 26 | private static final StatusLogger LOGGER = StatusLogger.getLogger(); |
30 | 27 | private static final LoggerContext context = new SLF4JLoggerContext(); |
16 | 16 | */ |
17 | 17 | package org.apache.logging.slf4j; |
18 | 18 | |
19 | import java.lang.reflect.InvocationTargetException; | |
20 | import java.lang.reflect.Proxy; | |
19 | 21 | import java.util.Date; |
20 | 22 | import java.util.List; |
21 | 23 | |
37 | 39 | import static org.hamcrest.Matchers.*; |
38 | 40 | import static org.junit.Assert.*; |
39 | 41 | |
40 | /** | |
41 | * | |
42 | */ | |
43 | 42 | public class LoggerTest { |
44 | 43 | |
45 | 44 | private static final String CONFIG = "target/test-classes/logback-slf4j.xml"; |
124 | 123 | |
125 | 124 | @Test |
126 | 125 | public void getLogger_String_MessageFactoryMismatchNull() { |
127 | final Logger testLogger = testMessageFactoryMismatch("getLogger_String_MessageFactoryMismatchNull", | |
126 | final Logger testLogger = testMessageFactoryMismatch("getLogger_String_MessageFactoryMismatchNull", | |
128 | 127 | StringFormatterMessageFactory.INSTANCE, null); |
129 | 128 | testLogger.debug("%,d", Integer.MAX_VALUE); |
130 | 129 | assertThat(list.strList, hasSize(1)); |
136 | 135 | assertThat(testLogger, is(notNullValue())); |
137 | 136 | checkMessageFactory(messageFactory1, testLogger); |
138 | 137 | final Logger testLogger2 = LogManager.getLogger(name, messageFactory2); |
139 | checkMessageFactory(messageFactory1, testLogger2); | |
138 | checkMessageFactory(messageFactory2, testLogger2); | |
140 | 139 | return testLogger; |
141 | 140 | } |
142 | 141 | |
162 | 161 | public void debugWithParms() { |
163 | 162 | logger.debug("Hello, {}", "World"); |
164 | 163 | assertThat(list.strList, hasSize(1)); |
164 | String message = list.strList.get(0); | |
165 | assertEquals("Hello, World", message); | |
166 | } | |
167 | ||
168 | @Test | |
169 | public void paramIncludesSubstitutionMarker_locationAware() { | |
170 | logger.info("Hello, {}", "foo {} bar"); | |
171 | assertThat(list.strList, hasSize(1)); | |
172 | String message = list.strList.get(0); | |
173 | assertEquals("Hello, foo {} bar", message); | |
174 | } | |
175 | ||
176 | @Test | |
177 | public void paramIncludesSubstitutionMarker_nonLocationAware() { | |
178 | final org.slf4j.Logger slf4jLogger = CTX.getLogger(); | |
179 | Logger nonLocationAwareLogger = new SLF4JLogger( | |
180 | slf4jLogger.getName(), | |
181 | (org.slf4j.Logger) Proxy.newProxyInstance( | |
182 | getClass().getClassLoader(), | |
183 | new Class<?>[]{org.slf4j.Logger.class}, | |
184 | (proxy, method, args) -> { | |
185 | try { | |
186 | return method.invoke(slf4jLogger, args); | |
187 | } catch (InvocationTargetException e) { | |
188 | throw e.getCause(); | |
189 | } | |
190 | })); | |
191 | nonLocationAwareLogger.info("Hello, {}", "foo {} bar"); | |
192 | assertThat(list.strList, hasSize(1)); | |
193 | String message = list.strList.get(0); | |
194 | assertEquals("Hello, foo {} bar", message); | |
165 | 195 | } |
166 | 196 | |
167 | 197 | @Test |
19 | 19 | <parent> |
20 | 20 | <artifactId>log4j</artifactId> |
21 | 21 | <groupId>org.apache.logging.log4j</groupId> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | </parent> |
24 | 24 | <modelVersion>4.0.0</modelVersion> |
25 | 25 |
19 | 19 | <artifactId>log4j</artifactId> |
20 | 20 | <packaging>pom</packaging> |
21 | 21 | <name>Apache Log4j 2</name> |
22 | <version>2.17.0</version> | |
22 | <version>2.17.1</version> | |
23 | 23 | <parent> |
24 | 24 | <groupId>org.apache.logging</groupId> |
25 | 25 | <artifactId>logging-parent</artifactId> |
182 | 182 | <connection>scm:git:https://gitbox.apache.org/repos/asf/logging-log4j2.git</connection> |
183 | 183 | <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/logging-log4j2.git</developerConnection> |
184 | 184 | <url>https://gitbox.apache.org/repos/asf?p=logging-log4j2.git</url> |
185 | <tag>log4j-2.17.0-rc1</tag> | |
185 | <tag>log4j-2.17.1-rc1</tag> | |
186 | 186 | </scm> |
187 | 187 | <properties> |
188 | 188 | <!-- make sure to update these for each release! --> |
189 | 189 | <log4jParentDir>${basedir}</log4jParentDir> |
190 | <Log4jReleaseVersion>2.17.0</Log4jReleaseVersion> | |
191 | <Log4jReleaseVersionJava7>2.12.2</Log4jReleaseVersionJava7> | |
192 | <Log4jReleaseVersionJava6>2.3</Log4jReleaseVersionJava6> | |
193 | <!--Log4jReleaseManager>Ralph Goers</Log4jReleaseManager--> | |
194 | <!--Log4jReleaseKey>B3D8E1BA</Log4jReleaseKey--> | |
195 | <Log4jReleaseManager>Ralph Goers</Log4jReleaseManager> | |
196 | <Log4jReleaseKey>B3D8E1BA</Log4jReleaseKey> | |
190 | <Log4jReleaseVersion>2.17.1</Log4jReleaseVersion> | |
191 | <Log4jReleaseVersionJava7>2.12.3</Log4jReleaseVersionJava7> | |
192 | <Log4jReleaseVersionJava6>2.3.1</Log4jReleaseVersionJava6> | |
193 | <Log4jReleaseManager>Matt Sicker</Log4jReleaseManager> | |
194 | <Log4jReleaseKey>D7C92B70FA1C814D</Log4jReleaseKey> | |
195 | <Log4jSigningUserName>mattsicker@apache.org</Log4jSigningUserName> | |
197 | 196 | <!-- note that any properties you want available in velocity templates must not use periods! --> |
198 | 197 | <slf4jVersion>1.7.25</slf4jVersion> |
199 | 198 | <logbackVersion>1.2.3</logbackVersion> |
243 | 242 | <maven.compiler.target>1.8</maven.compiler.target> |
244 | 243 | <maven.doap.skip>false</maven.doap.skip> |
245 | 244 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
245 | <!-- See https://maven.apache.org/guides/mini/guide-reproducible-builds.html --> | |
246 | <project.build.outputTimestamp>10</project.build.outputTimestamp> | |
246 | 247 | <docLabel>Site Documentation</docLabel> |
247 | 248 | <projectDir /> |
248 | 249 | <commonsLoggingVersion>1.2</commonsLoggingVersion> |
1451 | 1452 | <webAccessUrl>${project.scm.url}</webAccessUrl> |
1452 | 1453 | <anonymousConnection>${project.scm.connection}</anonymousConnection> |
1453 | 1454 | <developerConnection>${project.scm.developerConnection}</developerConnection> |
1454 | <scmTag>log4j-${Log4jReleaseVersion}</scmTag> | |
1455 | <scmTag>rel/${Log4jReleaseVersion}</scmTag> | |
1455 | 1456 | </configuration> |
1456 | 1457 | </plugin> |
1457 | 1458 | <!-- Surefire report --> |
132 | 132 | |
133 | 133 | ${project.url} |
134 | 134 | |
135 | --- | |
136 | ||
137 | Earlier release notes are accessible in [Release History](${project.url}changes-report.html). |
28 | 28 | - "update" - Change |
29 | 29 | - "remove" - Removed |
30 | 30 | --> |
31 | <release version="2.17.0" date="2021-MM-dd" description="GA Release 2.17.0"> | |
31 | <release version="2.17.1" date="2021-12-27" description="GA Release 2.17.1"> | |
32 | <!-- FIXES --> | |
33 | <action issue="LOG4J2-3290" dev="rogers" type="fix"> | |
34 | Remove unused method. | |
35 | </action> | |
36 | <action issue="LOG4J2-3292" dev="ckozak" type="fix"> | |
37 | ExtendedLoggerWrapper.logMessage no longer double-logs when location is requested. | |
38 | </action> | |
39 | <action issue="LOG4J2-3289" dev="ckozak" type="fix"> | |
40 | log4j-to-slf4j no longer re-interpolates formatted message contents. | |
41 | </action> | |
42 | <action issue="LOG4J2-3204" dev="vy" type="fix" due-to="Francis-FY"> | |
43 | Correct SpringLookup package name in Interpolator. | |
44 | </action> | |
45 | <action issue="LOG4J2-3284" dev="ckozak" type="fix" due-to="Michael Vorburger"> | |
46 | log4j-to-slf4j takes the provided MessageFactory into account | |
47 | </action> | |
48 | <action issue="LOG4J2-3264" dev="ckozak" type="fix" due-to="Yanming Zhou"> | |
49 | Fix MapLookup to lookup MapMessage before DefaultMap | |
50 | </action> | |
51 | <action issue="LOG4J2-3274" dev="rgoers" type="fix" due-to="Faisal Khan Thayub Khan"> | |
52 | Buffered I/O checked had inverted logic in RollingFileAppenderBuidler. | |
53 | </action> | |
54 | <action dev="ggregory" type="fix"> | |
55 | Fix NPE when input is null in StrSubstitutor.replace(String, Properties). | |
56 | </action> | |
57 | <action issue="LOG4J2-3270" dev="ckozak" type="fix"> | |
58 | Lookups with no prefix only read values from the configuration properties as expected. | |
59 | </action> | |
60 | <action issue="LOG4J2-3256" dev="ggregory" type="fix" due-to="Lee Dongjin"> | |
61 | Reduce ignored package scope of KafkaAppender. | |
62 | </action> | |
63 | </release> | |
64 | <release version="2.17.0" date="2021-12-17" description="GA Release 2.17.0"> | |
32 | 65 | <action issue="LOG4J2-3230" dev="ckozak" type="fix"> |
33 | 66 | Fix string substitution recursion. |
34 | 67 | </action> |
36 | 69 | Limit JNDI to the java protocol only. JNDI will remain disabled by default. Rename JNDI enablement property from |
37 | 70 | 'log4j2.enableJndi' to 'log4j2.enableJndiLookup', 'log4j2.enableJndiJms', and 'log4j2.enableJndiContextSelector'. |
38 | 71 | </action> |
39 | <action issue="LOG4J2-3242" dev="rgoers" type="fix"> | |
40 | Limit JNDI to the java protocol only. JNDI will remain disabled by default. The enablement | |
41 | property has been renamed to 'log4j2.enableJndiJava' | |
42 | </action> | |
43 | 72 | <action issue="LOG4J2-3241" dev="rgoers" type="fix"> |
44 | 73 | Do not declare log4j-api-java9 and log4j-core-java9 as dependencies as it causes problems with the |
45 | 74 | Maven enforcer plugin. |
55 | 84 | </action> |
56 | 85 | </release> |
57 | 86 | <release version="2.16.0" date="2021-12-13" description="GA Release 2.16.0"> |
87 | <!-- FIXES --> | |
58 | 88 | <action issue="LOG4J2-3208" dev="rgoers" type="fix"> |
59 | 89 | Disable JNDI by default. Require log4j2.enableJndi to be set to true to allow JNDI. |
60 | 90 | </action> |