diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index fdc91f7bcf8..26db2fc9c24 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -37,6 +37,10 @@ New Features Improvements --------------------- +* LUCENE-10313: use java util logging in Luke. Add dynamic log filtering. Drop + the persistent log previously written to ~/.luke.d/luke.log. Configure Java's default + logging handlers to persist Luke logs according to your needs. (Tomoko Uchida, Dawid Weiss) + * LUCENE-10238: Upgrade icu4j dependency to 70.1. (Dawid Weiss) * LUCENE-9820: Extract BKD tree interface and move intersecting logic to the diff --git a/lucene/distribution/src/binary-release/bin/luke.cmd b/lucene/distribution/src/binary-release/bin/luke.cmd index d5a3ce17c83..b4591aedafe 100644 --- a/lucene/distribution/src/binary-release/bin/luke.cmd +++ b/lucene/distribution/src/binary-release/bin/luke.cmd @@ -17,5 +17,5 @@ SETLOCAL SET MODULES=%~dp0.. -start javaw --module-path "%MODULES%\modules;%MODULES%\modules-thirdparty" --add-modules jdk.unsupported,org.apache.logging.log4j --module org.apache.lucene.luke +start javaw --module-path "%MODULES%\modules;%MODULES%\modules-thirdparty" --add-modules jdk.unsupported --module org.apache.lucene.luke ENDLOCAL diff --git a/lucene/distribution/src/binary-release/bin/luke.sh b/lucene/distribution/src/binary-release/bin/luke.sh index 09145328b5a..053eddacd80 100644 --- a/lucene/distribution/src/binary-release/bin/luke.sh +++ b/lucene/distribution/src/binary-release/bin/luke.sh @@ -17,4 +17,4 @@ MODULES=`dirname "$0"`/.. MODULES=`cd "$MODULES" && pwd` -java --module-path "$MODULES/modules:$MODULES/modules-thirdparty" --add-modules jdk.unsupported,org.apache.logging.log4j --module org.apache.lucene.luke +java --module-path "$MODULES/modules:$MODULES/modules-thirdparty" --add-modules jdk.unsupported --module org.apache.lucene.luke diff --git a/lucene/licenses/log4j-api-2.15.0.jar.sha1 b/lucene/licenses/log4j-api-2.15.0.jar.sha1 deleted file mode 100644 index a699db85f74..00000000000 --- a/lucene/licenses/log4j-api-2.15.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4a5aa7e55a29391c6f66e0b259d5189aa11e45d0 \ No newline at end of file diff --git a/lucene/licenses/log4j-api-LICENSE-ASL.txt b/lucene/licenses/log4j-api-LICENSE-ASL.txt deleted file mode 100644 index f49a4e16e68..00000000000 --- a/lucene/licenses/log4j-api-LICENSE-ASL.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/lucene/licenses/log4j-api-NOTICE.txt b/lucene/licenses/log4j-api-NOTICE.txt deleted file mode 100644 index ebba5ac0018..00000000000 --- a/lucene/licenses/log4j-api-NOTICE.txt +++ /dev/null @@ -1,17 +0,0 @@ -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma \ No newline at end of file diff --git a/lucene/licenses/log4j-core-2.15.0.jar.sha1 b/lucene/licenses/log4j-core-2.15.0.jar.sha1 deleted file mode 100644 index b0ab8d9f40f..00000000000 --- a/lucene/licenses/log4j-core-2.15.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -ba55c13d7ac2fd44df9cc8074455719a33f375b9 \ No newline at end of file diff --git a/lucene/licenses/log4j-core-LICENSE-ASL.txt b/lucene/licenses/log4j-core-LICENSE-ASL.txt deleted file mode 100644 index f49a4e16e68..00000000000 --- a/lucene/licenses/log4j-core-LICENSE-ASL.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/lucene/licenses/log4j-core-NOTICE.txt b/lucene/licenses/log4j-core-NOTICE.txt deleted file mode 100644 index ebba5ac0018..00000000000 --- a/lucene/licenses/log4j-core-NOTICE.txt +++ /dev/null @@ -1,17 +0,0 @@ -Apache Log4j -Copyright 1999-2017 Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - -ResolverUtil.java -Copyright 2005-2006 Tim Fennell - -Dumbster SMTP test server -Copyright 2004 Jason Paul Kitchen - -TypeUtil.java -Copyright 2002-2012 Ramnivas Laddad, Juergen Hoeller, Chris Beams - -picocli (http://picocli.info) -Copyright 2017 Remko Popma \ No newline at end of file diff --git a/lucene/luke/build.gradle b/lucene/luke/build.gradle index 23c843a39ab..fe556ca9527 100644 --- a/lucene/luke/build.gradle +++ b/lucene/luke/build.gradle @@ -27,8 +27,6 @@ ext { dependencies { api project(':lucene:core') - implementation 'org.apache.logging.log4j:log4j-core' - implementation project(':lucene:codecs') implementation project(':lucene:backward-codecs') implementation project(':lucene:analysis:common') diff --git a/lucene/luke/src/distribution/README.md b/lucene/luke/src/distribution/README.md index 0548fd17df8..4ff8bc717a6 100644 --- a/lucene/luke/src/distribution/README.md +++ b/lucene/luke/src/distribution/README.md @@ -27,7 +27,7 @@ java -jar ${luke.cmd} or, using Java modules: ``` -java --module-path . --add-modules jdk.unsupported,org.apache.logging.log4j --module org.apache.lucene.luke +java --module-path . --add-modules jdk.unsupported --module org.apache.lucene.luke ``` Happy index hacking! diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/AbstractHandler.java b/lucene/luke/src/java/org/apache/lucene/luke/app/AbstractHandler.java index 5abd9d931fd..ad77385a5dc 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/AbstractHandler.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/AbstractHandler.java @@ -20,7 +20,8 @@ package org.apache.lucene.luke.app; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.List; -import org.apache.logging.log4j.Logger; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.lucene.luke.util.LoggerFactory; /** Abstract handler class */ @@ -32,8 +33,8 @@ public abstract class AbstractHandler { public void addObserver(T observer) { observers.add(observer); - if (log.isDebugEnabled()) { - log.debug("{} registered.", observer.getClass().getName()); + if (log.isLoggable(Level.FINE)) { + log.fine(observer.getClass().getName() + " registered."); } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/IndexHandler.java b/lucene/luke/src/java/org/apache/lucene/luke/app/IndexHandler.java index 46e2e3de4d4..f35139e46d5 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/IndexHandler.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/IndexHandler.java @@ -21,7 +21,8 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.NoSuchFileException; import java.util.Objects; -import org.apache.logging.log4j.Logger; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.lucene.index.IndexReader; import org.apache.lucene.luke.app.desktop.PreferencesFactory; import org.apache.lucene.luke.app.desktop.util.MessageUtils; @@ -75,19 +76,19 @@ public final class IndexHandler extends AbstractHandler { try { reader = IndexUtils.openIndex(indexPath, dirImpl); } catch (NoSuchFileException e) { - log.error("Error opening index", e); + log.log(Level.SEVERE, "Error opening index", e); try { // remove the non-existing index path from history. PreferencesFactory.getInstance().removeHistory(indexPath); } catch (IOException ioe) { - log.error("Preference file is deleted?", ioe); + log.log(Level.SEVERE, "Preference file is deleted?", ioe); } throw new LukeException( MessageUtils.getLocalizedMessage( "openindex.message.index_path_does_not_exist", indexPath), e); } catch (Exception e) { - log.error("Error opening index", e); + log.log(Level.SEVERE, "Error opening index", e); throw new LukeException( MessageUtils.getLocalizedMessage("openindex.message.index_path_invalid", indexPath), e); } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java index 78c52544091..f64ec18bd2c 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/LukeMain.java @@ -22,10 +22,10 @@ import static org.apache.lucene.luke.app.desktop.util.ExceptionHandler.handle; import java.awt.GraphicsEnvironment; import java.io.IOException; import java.lang.invoke.MethodHandles; -import java.nio.file.FileSystems; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.UIManager; -import org.apache.logging.log4j.Logger; import org.apache.lucene.luke.app.desktop.components.LukeWindowProvider; import org.apache.lucene.luke.app.desktop.components.dialog.menubar.OpenIndexDialogFactory; import org.apache.lucene.luke.app.desktop.util.DialogOpener; @@ -36,15 +36,8 @@ import org.apache.lucene.luke.util.LoggerFactory; /** Entry class for desktop Luke */ public class LukeMain { - public static final String LOG_FILE = - System.getProperty("user.home") - + FileSystems.getDefault().getSeparator() - + ".luke.d" - + FileSystems.getDefault().getSeparator() - + "luke.log"; - static { - LoggerFactory.initGuiLogging(LOG_FILE); + LoggerFactory.initGuiLogging(); } private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -77,7 +70,7 @@ public class LukeMain { (factory) -> {}); } catch (IOException e) { messageBroker.showUnknownErrorMessage(); - log.error("Cannot initialize components.", e); + log.log(Level.SEVERE, "Cannot initialize components.", e); } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LogsPanelProvider.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LogsPanelProvider.java index 1f6bcf11d72..26bf9fb725c 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LogsPanelProvider.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LogsPanelProvider.java @@ -17,24 +17,28 @@ package org.apache.lucene.luke.app.desktop.components; -import java.awt.BorderLayout; -import java.awt.FlowLayout; -import javax.swing.BorderFactory; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import org.apache.lucene.luke.app.desktop.LukeMain; +import java.awt.*; +import java.awt.event.HierarchyEvent; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Objects; +import java.util.function.Function; +import java.util.logging.Level; +import java.util.stream.Collectors; +import javax.swing.*; import org.apache.lucene.luke.app.desktop.util.MessageUtils; +import org.apache.lucene.luke.util.CircularLogBufferHandler; +import org.apache.lucene.luke.util.LoggerFactory; /** Provider of the Logs panel */ public final class LogsPanelProvider { - private final JTextArea logTextArea; - - public LogsPanelProvider(JTextArea logTextArea) { - this.logTextArea = logTextArea; - } + public LogsPanelProvider() {} public JPanel get() { JPanel panel = new JPanel(new BorderLayout()); @@ -43,14 +47,107 @@ public final class LogsPanelProvider { JPanel header = new JPanel(new FlowLayout(FlowLayout.LEADING)); header.setOpaque(false); - header.add(new JLabel(MessageUtils.getLocalizedMessage("logs.label.see_also"))); + header.add(new JLabel(MessageUtils.getLocalizedMessage("logs.label.level"))); - JLabel logPathLabel = new JLabel(LukeMain.LOG_FILE); - header.add(logPathLabel); + JComboBox logFilter = + new JComboBox<>( + new Level[] { + Level.FINEST, + Level.FINER, + Level.FINE, + Level.CONFIG, + Level.INFO, + Level.WARNING, + Level.SEVERE, + Level.OFF + }); + logFilter.setEditable(false); + logFilter.setSelectedItem(Level.INFO); + header.add(logFilter); + + var logTextArea = createLogPanel(logFilter); panel.add(header, BorderLayout.PAGE_START); - panel.add(new JScrollPane(logTextArea), BorderLayout.CENTER); return panel; } + + /** Prepare the component responsible for displaying logs. */ + private JTextArea createLogPanel(JComboBox logFilter) { + JTextArea logTextArea = new JTextArea(); + logTextArea.setEditable(false); + + class LogRecordFormatter + implements Function { + @Override + public String apply(CircularLogBufferHandler.ImmutableLogRecord record) { + return String.format( + Locale.ROOT, + "%s [%s] %s: %s", + DateTimeFormatter.ofPattern("HH:mm:ss", Locale.ROOT) + .format(record.getInstant().atZone(ZoneId.systemDefault())), + record.getLevel(), + record.getLoggerName(), + record.getMessage() + + (record.getThrown() == null ? "" : "\n" + toString(record.getThrown()))); + } + + private String toString(Throwable t) { + try (StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw)) { + t.printStackTrace(pw); + pw.flush(); + return sw.toString(); + } catch (IOException e) { + return "Could not dump stack trace: " + e.getMessage(); + } + } + } + + // Hook into live data from the circular log buffer and update the initial state. + Function formatter = + new LogRecordFormatter(); + CircularLogBufferHandler.LogUpdateListener updater = + records -> { + // Create an immutable copy of the logs to display in the gui thread. + ArrayList clonedCopy = + new ArrayList<>(records); + SwingUtilities.invokeLater( + () -> { + Level level = (Level) Objects.requireNonNull(logFilter.getSelectedItem()); + + String logContent = + clonedCopy.stream() + .filter(record -> record.getLevel().intValue() > level.intValue()) + .map(formatter::apply) + .collect(Collectors.joining("\n")); + + logTextArea.setText(logContent); + }); + }; + + var logBuffer = Objects.requireNonNull(LoggerFactory.circularBuffer); + + // Update state on filter change. + logFilter.addActionListener( + e -> { + updater.accept(logBuffer.getLogRecords()); + }); + + // Subscribe to log events and update state only when actually displayed. + logTextArea.addHierarchyListener( + (HierarchyEvent e) -> { + if (e.getComponent() == logTextArea + && (e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) { + if (logTextArea.isDisplayable()) { + logBuffer.addUpdateListener(updater); + updater.accept(logBuffer.getLogRecords()); + } else { + logBuffer.removeUpdateListener(updater); + } + } + }); + + return logTextArea; + } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LukeWindowProvider.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LukeWindowProvider.java index bbea489e937..a7a46a825ba 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LukeWindowProvider.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/LukeWindowProvider.java @@ -17,22 +17,9 @@ package org.apache.lucene.luke.app.desktop.components; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; +import java.awt.*; import java.io.IOException; -import javax.swing.BorderFactory; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JMenuBar; -import javax.swing.JPanel; -import javax.swing.JTabbedPane; -import javax.swing.JTextArea; -import javax.swing.WindowConstants; +import javax.swing.*; import org.apache.lucene.luke.app.DirectoryHandler; import org.apache.lucene.luke.app.DirectoryObserver; import org.apache.lucene.luke.app.IndexHandler; @@ -44,7 +31,6 @@ import org.apache.lucene.luke.app.desktop.PreferencesFactory; import org.apache.lucene.luke.app.desktop.util.FontUtils; import org.apache.lucene.luke.app.desktop.util.ImageUtils; import org.apache.lucene.luke.app.desktop.util.MessageUtils; -import org.apache.lucene.luke.app.desktop.util.TextAreaAppender; import org.apache.lucene.util.Version; /** Provider of the root window */ @@ -74,14 +60,9 @@ public final class LukeWindowProvider implements LukeWindowOperator { private JFrame frame = new JFrame(); public LukeWindowProvider() throws IOException { - // prepare log4j appender for Logs tab. - JTextArea logTextArea = new JTextArea(); - logTextArea.setEditable(false); - TextAreaAppender.setTextArea(logTextArea); - this.prefs = PreferencesFactory.getInstance(); this.menuBar = new MenuBarProvider().get(); - this.tabbedPane = new TabbedPaneProvider(logTextArea).get(); + this.tabbedPane = new TabbedPaneProvider().get(); this.messageBroker = MessageBroker.getInstance(); this.tabSwitcher = TabSwitcherProxy.getInstance(); diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/TabbedPaneProvider.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/TabbedPaneProvider.java index a64d89e6604..83468ab1f7f 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/TabbedPaneProvider.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/TabbedPaneProvider.java @@ -20,7 +20,6 @@ package org.apache.lucene.luke.app.desktop.components; import java.io.IOException; import javax.swing.JPanel; import javax.swing.JTabbedPane; -import javax.swing.JTextArea; import org.apache.lucene.luke.app.DirectoryHandler; import org.apache.lucene.luke.app.DirectoryObserver; import org.apache.lucene.luke.app.IndexHandler; @@ -35,7 +34,7 @@ public final class TabbedPaneProvider implements TabSwitcherProxy.TabSwitcher { private final MessageBroker messageBroker; - private final JTabbedPane tabbedPane = new JTabbedPane(); + private final JTabbedPane tabbedPane; private final JPanel overviewPanel; @@ -49,13 +48,15 @@ public final class TabbedPaneProvider implements TabSwitcherProxy.TabSwitcher { private final JPanel logsPanel; - public TabbedPaneProvider(JTextArea logTextArea) throws IOException { + public TabbedPaneProvider() throws IOException { + this.tabbedPane = new JTabbedPane(); + this.overviewPanel = new OverviewPanelProvider().get(); this.documentsPanel = new DocumentsPanelProvider().get(); this.searchPanel = new SearchPanelProvider().get(); this.analysisPanel = new AnalysisPanelProvider().get(); this.commitsPanel = new CommitsPanelProvider().get(); - this.logsPanel = new LogsPanelProvider(logTextArea).get(); + this.logsPanel = new LogsPanelProvider().get(); this.messageBroker = MessageBroker.getInstance(); diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/documents/AddDocumentDialogFactory.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/documents/AddDocumentDialogFactory.java index 535dcafece6..723cd21dbb1 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/documents/AddDocumentDialogFactory.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/documents/AddDocumentDialogFactory.java @@ -33,6 +33,8 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.swing.BorderFactory; @@ -51,7 +53,6 @@ import javax.swing.ListSelectionModel; import javax.swing.UIManager; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; -import org.apache.logging.log4j.Logger; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; @@ -399,15 +400,15 @@ public final class AddDocumentDialogFactory doc.add(toIndexableField(nf)); } } catch (NumberFormatException ex) { - log.error("Error converting field value", e); + log.log(Level.SEVERE, "Error converting field value", e); throw new LukeException("Invalid value: " + ex.getMessage(), ex); } catch (Exception ex) { - log.error("Error converting field value", e); + log.log(Level.SEVERE, "Error converting field value", e); throw new LukeException(ex.getMessage(), ex); } addDocument(doc); - log.info("Added document: {}", doc); + log.info("Added document: " + doc); } @SuppressWarnings("unchecked") diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CheckIndexDialogFactory.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CheckIndexDialogFactory.java index ba058c59b79..cd05bedaf34 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CheckIndexDialogFactory.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CheckIndexDialogFactory.java @@ -29,6 +29,8 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; @@ -39,7 +41,6 @@ import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTextArea; import javax.swing.SwingWorker; -import org.apache.logging.log4j.Logger; import org.apache.lucene.index.CheckIndex; import org.apache.lucene.luke.app.DirectoryHandler; import org.apache.lucene.luke.app.DirectoryObserver; @@ -304,7 +305,7 @@ public final class CheckIndexDialogFactory implements DialogOpener.DialogFactory } status = st; } catch (Exception e) { - log.error("Error checking index", e); + log.log(Level.SEVERE, "Error checking index", e); statusLbl.setText(MessageUtils.getLocalizedMessage("message.error.unknown")); } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CreateIndexDialogFactory.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CreateIndexDialogFactory.java index 995162e035b..223fc4fabf3 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CreateIndexDialogFactory.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/CreateIndexDialogFactory.java @@ -35,6 +35,8 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; @@ -47,7 +49,6 @@ import javax.swing.JSeparator; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingWorker; -import org.apache.logging.log4j.Logger; import org.apache.lucene.luke.app.IndexHandler; import org.apache.lucene.luke.app.desktop.Preferences; import org.apache.lucene.luke.app.desktop.PreferencesFactory; @@ -337,7 +338,7 @@ public class CreateIndexDialogFactory implements DialogOpener.DialogFactory { IOException ex2) { } - log.error("Cannot create index", ex); + log.log(Level.SEVERE, "Cannot create index", ex); String message = "See Logs tab or log file for more details."; JOptionPane.showMessageDialog( dialog, message, "Cannot create index", JOptionPane.ERROR_MESSAGE); diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/ExportTermsDialogFactory.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/ExportTermsDialogFactory.java index 87377e3bac8..3bf84a219d6 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/ExportTermsDialogFactory.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/ExportTermsDialogFactory.java @@ -31,6 +31,8 @@ import java.lang.invoke.MethodHandles; import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Stream; import javax.swing.BorderFactory; import javax.swing.BoxLayout; @@ -42,7 +44,6 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingWorker; -import org.apache.logging.log4j.Logger; import org.apache.lucene.luke.app.IndexHandler; import org.apache.lucene.luke.app.IndexObserver; import org.apache.lucene.luke.app.LukeState; @@ -249,11 +250,11 @@ public final class ExportTermsDialogFactory implements DialogOpener.DialogFactor try { filename = toolsModel.exportTerms(directory, field, selectedDelimiter); } catch (LukeException e) { - log.error("Error while exporting terms from field {}", field, e); + log.log(Level.SEVERE, "Error while exporting terms from field " + field, e); statusLbl.setText( MessageUtils.getLocalizedMessage("export.terms.label.error", e.getMessage())); } catch (Exception e) { - log.error("Error while exporting terms from field {}", field, e); + log.log(Level.SEVERE, "Error while exporting terms from field " + field, e); statusLbl.setText(MessageUtils.getLocalizedMessage("message.error.unknown")); throw e; } finally { diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/OpenIndexDialogFactory.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/OpenIndexDialogFactory.java index a523cd4b111..30e3d0bde59 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/OpenIndexDialogFactory.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/components/dialog/menubar/OpenIndexDialogFactory.java @@ -32,6 +32,8 @@ import java.nio.file.Paths; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; @@ -45,7 +47,6 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSeparator; -import org.apache.logging.log4j.Logger; import org.apache.lucene.luke.app.DirectoryHandler; import org.apache.lucene.luke.app.IndexHandler; import org.apache.lucene.luke.app.desktop.Preferences; @@ -345,7 +346,7 @@ public final class OpenIndexDialogFactory implements DialogOpener.DialogFactory MessageUtils.getLocalizedMessage("message.error.unknown"), "Unknown Error", JOptionPane.ERROR_MESSAGE); - log.error("Error opening index or directory", cause); + log.log(Level.SEVERE, "Error opening index or directory", cause); } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/ExceptionHandler.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/ExceptionHandler.java index 481047c631d..d02e4523185 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/ExceptionHandler.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/ExceptionHandler.java @@ -18,7 +18,8 @@ package org.apache.lucene.luke.app.desktop.util; import java.lang.invoke.MethodHandles; -import org.apache.logging.log4j.Logger; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.lucene.luke.app.desktop.MessageBroker; import org.apache.lucene.luke.models.LukeException; import org.apache.lucene.luke.util.LoggerFactory; @@ -32,10 +33,10 @@ public final class ExceptionHandler { if (t instanceof LukeException) { Throwable cause = t.getCause(); String message = (cause == null) ? t.getMessage() : t.getMessage() + " " + cause.getMessage(); - log.warn("Uncaught LukeException", t); + log.log(Level.WARNING, "Uncaught LukeException", t); messageBroker.showStatusMessage(message); } else { - log.error("Uncaught Exception", t); + log.log(Level.SEVERE, "Uncaught Exception", t); messageBroker.showUnknownErrorMessage(); } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/TextAreaAppender.java b/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/TextAreaAppender.java deleted file mode 100644 index 3d6964ae00c..00000000000 --- a/lucene/luke/src/java/org/apache/lucene/luke/app/desktop/util/TextAreaAppender.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.lucene.luke.app.desktop.util; - -import java.io.Serializable; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import javax.swing.JTextArea; -import javax.swing.SwingUtilities; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Core; -import org.apache.logging.log4j.core.Filter; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.StringLayout; -import org.apache.logging.log4j.core.appender.AbstractAppender; -import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender; -import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; - -/** Log appender for text areas */ -@Plugin( - name = "TextArea", - category = Core.CATEGORY_NAME, - elementType = Appender.ELEMENT_TYPE, - printObject = true) -public final class TextAreaAppender extends AbstractAppender { - - private static JTextArea textArea; - - private static final ReadWriteLock rwLock = new ReentrantReadWriteLock(); - private static final Lock readLock = rwLock.readLock(); - private static final Lock writeLock = rwLock.writeLock(); - - protected TextAreaAppender( - String name, - Filter filter, - org.apache.logging.log4j.core.Layout layout, - final boolean ignoreExceptions) { - super(name, filter, layout, ignoreExceptions, Property.EMPTY_ARRAY); - } - - public static void setTextArea(JTextArea ta) { - writeLock.lock(); - try { - if (textArea != null) { - throw new IllegalStateException("TextArea already set."); - } - textArea = ta; - } finally { - writeLock.unlock(); - } - } - - @Override - public void append(LogEvent event) { - readLock.lock(); - try { - if (textArea == null) { - // just ignore any events logged before the area is available - return; - } - - final String message = ((StringLayout) getLayout()).toSerializable(event); - SwingUtilities.invokeLater( - () -> { - textArea.append(message); - }); - } finally { - readLock.unlock(); - } - } - - /** - * Builds TextAreaAppender instances. - * - * @param The type to build - */ - public static class Builder> extends AbstractOutputStreamAppender.Builder - implements org.apache.logging.log4j.core.util.Builder { - - @Override - public TextAreaAppender build() { - return new TextAreaAppender(getName(), getFilter(), getOrCreateLayout(), true); - } - } - - @PluginBuilderFactory - public static > B newBuilder() { - return new Builder().asBuilder(); - } -} diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/commits/CommitsImpl.java b/lucene/luke/src/java/org/apache/lucene/luke/models/commits/CommitsImpl.java index 59b50a2b81d..a103eee9ce1 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/models/commits/CommitsImpl.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/models/commits/CommitsImpl.java @@ -26,8 +26,8 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.TreeMap; +import java.util.logging.Logger; import java.util.stream.Collectors; -import org.apache.logging.log4j.Logger; import org.apache.lucene.codecs.Codec; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexCommit; @@ -98,7 +98,7 @@ public final class CommitsImpl extends LukeModel implements Commits { if (ic == null) { String msg = String.format(Locale.ENGLISH, "Commit generation %d not exists.", commitGen); - log.warn(msg); + log.warning(msg); return Optional.empty(); } @@ -111,7 +111,7 @@ public final class CommitsImpl extends LukeModel implements Commits { if (ic == null) { String msg = String.format(Locale.ENGLISH, "Commit generation %d not exists.", commitGen); - log.warn(msg); + log.warning(msg); return Collections.emptyList(); } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/documents/DocumentsImpl.java b/lucene/luke/src/java/org/apache/lucene/luke/models/documents/DocumentsImpl.java index 84daec9cc2d..9e36d4ffaeb 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/models/documents/DocumentsImpl.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/models/documents/DocumentsImpl.java @@ -25,7 +25,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Optional; -import org.apache.logging.log4j.Logger; +import java.util.logging.Logger; import org.apache.lucene.document.Document; import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.IndexReader; @@ -80,7 +80,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { @Override public List getDocumentFields(int docid) { if (!isLive(docid)) { - log.info("Doc #{} was deleted", docid); + log.info("Doc #" + docid + " was deleted"); return Collections.emptyList(); } @@ -126,7 +126,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { // no such field? resetCurrentField(); resetTermsIterator(); - log.warn("Terms not available for field: {}.", field); + log.warning("Terms not available for field: " + field); return Optional.empty(); } else { setCurrentField(field); @@ -135,7 +135,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { if (tenum.next() == null) { // no term available for this field resetTermsIterator(); - log.warn("No term available for field: {}.", field); + log.warning("No term available for field: " + field); return Optional.empty(); } else { return Optional.of(new Term(curField, tenum.term())); @@ -156,7 +156,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { public Optional nextTerm() { if (tenum == null) { // terms enum not initialized - log.warn("Terms enum un-positioned."); + log.warning("Terms enum un-positioned."); return Optional.empty(); } @@ -164,7 +164,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { if (tenum.next() == null) { // end of the iterator resetTermsIterator(); - log.info("Reached the end of the term iterator for field: {}.", curField); + log.info("Reached the end of the term iterator for field: " + curField); return Optional.empty(); } else { @@ -186,7 +186,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { if (curField == null) { // field is not selected - log.warn("Field not selected."); + log.warning("Field not selected."); return Optional.empty(); } @@ -197,7 +197,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { if (tenum.seekCeil(new BytesRef(termText)) == TermsEnum.SeekStatus.END) { // reached to the end of the iterator resetTermsIterator(); - log.info("Reached the end of the term iterator for field: {}.", curField); + log.info("Reached the end of the term iterator for field: " + curField); return Optional.empty(); } else { return Optional.of(new Term(curField, tenum.term())); @@ -216,7 +216,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { public Optional firstTermDoc() { if (tenum == null) { // terms enum is not set - log.warn("Terms enum un-positioned."); + log.warning("Terms enum un-positioned."); return Optional.empty(); } @@ -226,10 +226,11 @@ public final class DocumentsImpl extends LukeModel implements Documents { if (penum.nextDoc() == PostingsEnum.NO_MORE_DOCS) { // no docs available for this term resetPostingsIterator(); - log.warn( - "No docs available for term: {} in field: {}.", - BytesRefUtils.decode(tenum.term()), - curField); + log.warning( + "No docs available for term: " + + BytesRefUtils.decode(tenum.term()) + + " in field: " + + curField); return Optional.empty(); } else { return Optional.of(penum.docID()); @@ -245,7 +246,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { public Optional nextTermDoc() { if (penum == null) { // postings enum is not initialized - log.warn("Postings enum un-positioned for field: {}.", curField); + log.warning("Postings enum un-positioned for field: " + curField); return Optional.empty(); } @@ -253,12 +254,11 @@ public final class DocumentsImpl extends LukeModel implements Documents { if (penum.nextDoc() == PostingsEnum.NO_MORE_DOCS) { // end of the iterator resetPostingsIterator(); - if (log.isInfoEnabled()) { - log.info( - "Reached the end of the postings iterator for term: {} in field: {}", - BytesRefUtils.decode(tenum.term()), - curField); - } + log.info( + "Reached the end of the postings iterator for term: " + + BytesRefUtils.decode(tenum.term()) + + " in field: " + + curField); return Optional.empty(); } else { return Optional.of(penum.docID()); @@ -274,7 +274,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { public List getTermPositions() { if (penum == null) { // postings enum is not initialized - log.warn("Postings enum un-positioned for field: {}.", curField); + log.warning("Postings enum un-positioned for field: " + curField); return Collections.emptyList(); } @@ -305,7 +305,7 @@ public final class DocumentsImpl extends LukeModel implements Documents { public Optional getDocFreq() { if (tenum == null) { // terms enum is not initialized - log.warn("Terms enum un-positioned for field: {}.", curField); + log.warning("Terms enum un-positioned for field: " + curField); return Optional.empty(); } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/documents/TermVectorsAdapter.java b/lucene/luke/src/java/org/apache/lucene/luke/models/documents/TermVectorsAdapter.java index 64d8552a464..bfdd227d023 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/models/documents/TermVectorsAdapter.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/models/documents/TermVectorsAdapter.java @@ -22,8 +22,9 @@ import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Objects; -import org.apache.logging.log4j.Logger; +import java.util.logging.Logger; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; @@ -53,7 +54,10 @@ final class TermVectorsAdapter { Terms termVector = reader.getTermVector(docid, field); if (termVector == null) { // no term vector available - log.warn("No term vector indexed for doc: #{} and field: {}", docid, field); + log.warning( + () -> + String.format( + Locale.ROOT, "No term vector indexed for doc: #%s and field: %s", docid, field)); return Collections.emptyList(); } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java b/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java index a1122a3118d..c4b96297d18 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java @@ -30,8 +30,8 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.logging.Logger; import java.util.stream.Collectors; -import org.apache.logging.log4j.Logger; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.DocValuesType; import org.apache.lucene.index.FieldInfo; @@ -230,7 +230,7 @@ public final class SearchImpl extends LukeModel implements Search { } else if (type == Float.class || type == Double.class) { pc = new PointsConfig(NumberFormat.getNumberInstance(Locale.ROOT), type); } else { - log.warn( + log.warning( String.format(Locale.ENGLISH, "Ignored invalid number type: %s.", type.getName())); continue; } @@ -344,7 +344,7 @@ public final class SearchImpl extends LukeModel implements Search { if (totalHits.value == 0 || (totalHits.relation == TotalHits.Relation.EQUAL_TO && currentPage * pageSize >= totalHits.value)) { - log.warn("No more next search results are available."); + log.warning("No more next search results are available."); return Optional.empty(); } @@ -375,7 +375,7 @@ public final class SearchImpl extends LukeModel implements Search { currentPage -= 1; if (currentPage < 0) { - log.warn("No more previous search results are available."); + log.warning("No more previous search results are available."); return Optional.empty(); } @@ -462,7 +462,7 @@ public final class SearchImpl extends LukeModel implements Search { Objects.requireNonNull(type); List candidates = guessSortTypes(name); if (candidates.isEmpty()) { - log.warn(String.format(Locale.ENGLISH, "No available sort types for: %s", name)); + log.warning(String.format(Locale.ENGLISH, "No available sort types for: %s", name)); return Optional.empty(); } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/util/IndexUtils.java b/lucene/luke/src/java/org/apache/lucene/luke/models/util/IndexUtils.java index a8c35f54819..c63ce4db0b6 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/models/util/IndexUtils.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/models/util/IndexUtils.java @@ -34,9 +34,10 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.StreamSupport; -import org.apache.logging.log4j.Logger; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.core.WhitespaceAnalyzer; import org.apache.lucene.codecs.CodecUtil; @@ -84,7 +85,7 @@ public final class IndexUtils { DirectoryReader dr = DirectoryReader.open(dir); readers.add(dr); } catch (IOException e) { - log.warn("Error opening directory", e); + log.log(Level.WARNING, "Error opening directory", e); } return FileVisitResult.CONTINUE; } @@ -94,14 +95,12 @@ public final class IndexUtils { throw new RuntimeException("No valid directory at the location: " + indexPath); } - if (log.isInfoEnabled()) { - log.info( - String.format( - Locale.ENGLISH, - "IndexReaders (%d leaf readers) successfully opened. Index path=%s", - readers.size(), - indexPath)); - } + log.info( + String.format( + Locale.ENGLISH, + "IndexReaders (%d leaf readers) successfully opened. Index path=%s", + readers.size(), + indexPath)); if (readers.size() == 1) { return readers.get(0); @@ -134,11 +133,9 @@ public final class IndexUtils { public static Directory openDirectory(String dirPath, String dirImpl) throws IOException { final Path path = FileSystems.getDefault().getPath(Objects.requireNonNull(dirPath)); Directory dir = openDirectory(path, dirImpl); - if (log.isInfoEnabled()) { - log.info( - String.format( - Locale.ENGLISH, "DirectoryReader successfully opened. Directory path=%s", dirPath)); - } + log.info( + String.format( + Locale.ENGLISH, "DirectoryReader successfully opened. Directory path=%s", dirPath)); return dir; } @@ -161,7 +158,7 @@ public final class IndexUtils { dir = (Directory) constr.newInstance(path, null); } } catch (Exception e) { - log.warn("Invalid directory implementation class: {}", dirImpl, e); + log.log(Level.WARNING, "Invalid directory implementation class: " + dirImpl, e); throw new IllegalArgumentException("Invalid directory implementation class: " + dirImpl); } } @@ -180,7 +177,7 @@ public final class IndexUtils { log.info("Directory successfully closed."); } } catch (IOException e) { - log.error("Error closing directory", e); + log.log(Level.SEVERE, "Error closing directory", e); } } @@ -201,7 +198,7 @@ public final class IndexUtils { } } } catch (IOException e) { - log.error("Error closing index reader", e); + log.log(Level.SEVERE, "Error closing index reader", e); } } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/util/twentynewsgroups/MessageFilesParser.java b/lucene/luke/src/java/org/apache/lucene/luke/models/util/twentynewsgroups/MessageFilesParser.java index c5b5d0db516..41db69b2f18 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/models/util/twentynewsgroups/MessageFilesParser.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/models/util/twentynewsgroups/MessageFilesParser.java @@ -28,7 +28,8 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; -import org.apache.logging.log4j.Logger; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.lucene.luke.util.LoggerFactory; /** @@ -56,10 +57,8 @@ public class MessageFilesParser extends SimpleFileVisitor { messages.add(parse(file)); } } - } catch ( - @SuppressWarnings("unused") - IOException e) { - log.warn("Invalid file? {}", file); + } catch (IOException e) { + log.log(Level.WARNING, "Invalid file? " + file, e); } return FileVisitResult.CONTINUE; } diff --git a/lucene/luke/src/java/org/apache/lucene/luke/util/CircularLogBufferHandler.java b/lucene/luke/src/java/org/apache/lucene/luke/util/CircularLogBufferHandler.java new file mode 100644 index 00000000000..e0ad6f7dcf3 --- /dev/null +++ b/lucene/luke/src/java/org/apache/lucene/luke/util/CircularLogBufferHandler.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.lucene.luke.util; + +import java.time.Instant; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +/** A {@link Handler} with a bounded buffer of recent log messages. */ +public class CircularLogBufferHandler extends Handler { + /** Provides an immutable clone of the required data from a {@link LogRecord} logged elsewhere. */ + public static final class ImmutableLogRecord { + private final String loggerName; + private final Level level; + private final String message; + private final Throwable thrown; + private final Instant instant; + + public ImmutableLogRecord(LogRecord record) { + this.loggerName = record.getLoggerName(); + this.level = record.getLevel(); + this.message = record.getMessage(); + this.thrown = record.getThrown(); + this.instant = record.getInstant(); + } + + public String getLoggerName() { + return loggerName; + } + + public Level getLevel() { + return level; + } + + public String getMessage() { + return message; + } + + public Throwable getThrown() { + return thrown; + } + + public Instant getInstant() { + return instant; + } + } + + /** Listeners receiving log state updates. */ + public interface LogUpdateListener extends Consumer> {} + + /** A bounded buffer of immutable log records that have been recently logged by the framework. */ + private final ArrayDeque buffer = new ArrayDeque<>(); + + /** + * Listeners interested in receiving log state updates. At the moment listeners receive an + * iterable with all log records in the circular buffer. We could make it incremental for each + * consumer but for Luke it really doesn't matter since the rate of updates is very small. + */ + private final List listeners = new CopyOnWriteArrayList<>(); + + @Override + public void publish(LogRecord record) { + synchronized (buffer) { + buffer.addLast(new ImmutableLogRecord(record)); + listeners.forEach(c -> c.accept(buffer)); + } + } + + @Override + public void flush() { + // Ignore. + } + + @Override + public void close() throws SecurityException { + // Ignore. + } + + public void addUpdateListener(LogUpdateListener listener) { + listeners.add(listener); + } + + public void removeUpdateListener(LogUpdateListener listener) { + listeners.remove(listener); + } + + /** @return Return a clone of the buffered records so far. */ + public Collection getLogRecords() { + synchronized (buffer) { + return new ArrayDeque<>(buffer); + } + } +} diff --git a/lucene/luke/src/java/org/apache/lucene/luke/util/LoggerFactory.java b/lucene/luke/src/java/org/apache/lucene/luke/util/LoggerFactory.java index a1a91848059..6f134a73a25 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/util/LoggerFactory.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/util/LoggerFactory.java @@ -17,54 +17,28 @@ package org.apache.lucene.luke.util; -import java.nio.charset.StandardCharsets; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.FileAppender; -import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; -import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; -import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; -import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.lucene.luke.app.desktop.util.TextAreaAppender; +import java.util.logging.Level; +import java.util.logging.Logger; -/** Logger factory. This programmatically configurates logger context (Appenders etc.) */ +/** Logger factory. This configures log interceptors for the GUI. */ public class LoggerFactory { + public static CircularLogBufferHandler circularBuffer; - public static void initGuiLogging(String logFile) { - ConfigurationBuilder builder = - ConfigurationBuilderFactory.newConfigurationBuilder(); - builder.add(builder.newRootLogger(Level.INFO)); - LoggerContext context = Configurator.initialize(builder.build()); + public static void initGuiLogging() { + if (circularBuffer != null) { + throw new RuntimeException("Double-initialization?"); + } - PatternLayout layout = - PatternLayout.newBuilder() - .withPattern("[%d{ISO8601}] %5p (%F:%L) - %m%n") - .withCharset(StandardCharsets.UTF_8) - .build(); + circularBuffer = new CircularLogBufferHandler(); + circularBuffer.setLevel(Level.FINEST); - Appender fileAppender = - FileAppender.newBuilder() - .setName("File") - .setLayout(layout) - .withFileName(logFile) - .withAppend(false) - .build(); - fileAppender.start(); - - Appender textAreaAppender = - TextAreaAppender.newBuilder().setName("TextArea").setLayout(layout).build(); - textAreaAppender.start(); - - context.getRootLogger().addAppender(fileAppender); - context.getRootLogger().addAppender(textAreaAppender); - context.updateLoggers(); + // Only capture events from Lucene logger hierarchy. + var luceneRoot = Logger.getLogger("org.apache.lucene"); + luceneRoot.setLevel(Level.FINEST); + luceneRoot.addHandler(circularBuffer); } public static Logger getLogger(Class clazz) { - return LogManager.getLogger(clazz); + return Logger.getLogger(clazz.getName()); } } diff --git a/lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/messages/messages.properties b/lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/messages/messages.properties index e8143297121..8e91e51bc5f 100644 --- a/lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/messages/messages.properties +++ b/lucene/luke/src/resources/org/apache/lucene/luke/app/desktop/messages/messages.properties @@ -280,7 +280,7 @@ commits.label.files=Files commits.label.segments=Segments (click rows for more details) commits.label.segdetails=Segment details # Logs -logs.label.see_also=See also: +logs.label.level=Log level: # Help dialogs help.fieldtype.TextField=A field that is indexed and tokenized, without term vectors.\n\n(Example Values)\n- Hello Lucene! help.fieldtype.StringField=A field that is indexed but not tokenized: the entire String value is indexed as a single token.\n\n(Example Values)\n- Java diff --git a/versions.lock b/versions.lock index 80f63aac0d0..87c5b3f55d2 100644 --- a/versions.lock +++ b/versions.lock @@ -12,8 +12,6 @@ org.antlr:antlr4-runtime:4.5.1-1 (1 constraints: 6a05b240) org.apache.commons:commons-compress:1.19 (1 constraints: df04fa30) org.apache.httpcomponents:httpclient:4.5.13 (1 constraints: 3f054e3b) org.apache.httpcomponents:httpcore:4.4.13 (1 constraints: 591016a2) -org.apache.logging.log4j:log4j-api:2.15.0 (1 constraints: bb0e1f76) -org.apache.logging.log4j:log4j-core:2.15.0 (1 constraints: 3a053e3b) org.apache.opennlp:opennlp-tools:1.9.1 (1 constraints: 0d050c36) org.carrot2:morfologik-fsa:2.1.8 (1 constraints: da0d9b36) org.carrot2:morfologik-polish:2.1.8 (1 constraints: 0d050036) diff --git a/versions.props b/versions.props index 185bcfcbccb..c0103925617 100644 --- a/versions.props +++ b/versions.props @@ -10,7 +10,6 @@ net.sourceforge.nekohtml:nekohtml=1.9.17 org.antlr:antlr4*=4.5.1-1 org.apache.commons:commons-compress=1.19 org.apache.httpcomponents:httpclient=4.5.13 -org.apache.logging.log4j:*=2.15.0 org.apache.opennlp:opennlp-tools=1.9.1 org.carrot2:morfologik-*=2.1.8 org.eclipse.jetty:*=9.4.41.v20210516