diff --git a/log4j-core-test/pom.xml b/log4j-core-test/pom.xml index fcb6329be83..071668d291d 100644 --- a/log4j-core-test/pom.xml +++ b/log4j-core-test/pom.xml @@ -182,13 +182,6 @@ true - - - org.fusesource.jansi - jansi - true - - org.junit.jupiter junit-jupiter-engine diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/TestConstants.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/TestConstants.java index 21a60e631d9..6ba7b9a19e4 100644 --- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/TestConstants.java +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/TestConstants.java @@ -67,8 +67,6 @@ private TestConstants() {} public static final String CONFIGURATION_USE_PRECISE_CLOCK = CONFIGURATION + "usePreciseClock"; - public static final String CONSOLE_JANSI_ENABLED = "log4j.console.jansiEnabled"; - private static final String GC = "log4j.gc."; public static final String GC_ENABLE_DIRECT_ENCODERS = GC + "enableDirectEncoders"; diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/categories/Layouts.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/categories/Layouts.java index 4b78f1fdc47..3838ab71d6e 100644 --- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/categories/Layouts.java +++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/categories/Layouts.java @@ -21,6 +21,4 @@ */ public interface Layouts { interface Csv {} - - interface Jansi {} } diff --git a/log4j-core-test/src/main/resources/Log4j-config.xsd b/log4j-core-test/src/main/resources/Log4j-config.xsd index c17d1c59e3f..3ff224097a0 100644 --- a/log4j-core-test/src/main/resources/Log4j-config.xsd +++ b/log4j-core-test/src/main/resources/Log4j-config.xsd @@ -696,7 +696,7 @@ Write directly to java.io.FileDescriptor and bypass java.lang.System.out/.err. Can give up to 10x performance boost when the - output is redirected to file or other process. Cannot be used with Jansi on Windows. Cannot be used with follow. + output is redirected to file or other process. Cannot be used with follow. @@ -704,7 +704,7 @@ Identifies whether the appender honors reassignments of System.out or System.err via System.setOut or System.setErr made after - configuration. Note that the follow attribute cannot be used with Jansi on Windows. Cannot be used with direct. + configuration. Cannot be used with direct. diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiMessagesMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiMessagesMain.java index 3088ca2bc1b..a44d064ab49 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiMessagesMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiMessagesMain.java @@ -30,7 +30,7 @@ *

* *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiMessagesMain log4j-core/target/test-classes/log4j2-console.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiMessagesMain log4j-core/target/test-classes/log4j2-console.xml
  * 
*/ public class ConsoleAppenderAnsiMessagesMain { @@ -38,8 +38,7 @@ public class ConsoleAppenderAnsiMessagesMain { private static final Logger LOG = LogManager.getLogger(ConsoleAppenderAnsiMessagesMain.class); public static void main(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - try (final LoggerContext ctx = Configurator.initialize( + try (final LoggerContext ignored = Configurator.initialize( ConsoleAppenderAnsiMessagesMain.class.getName(), "target/test-classes/log4j2-console.xml")) { LOG.fatal("\u001b[1;35mFatal message.\u001b[0m"); LOG.error("\u001b[1;31mError message.\u001b[0m"); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira180Main.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira180Main.java index dffc5b42893..bd8491c6667 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira180Main.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira180Main.java @@ -23,13 +23,13 @@ import org.apache.logging.log4j.core.config.Configurator; /** - * Tests https://issues.apache.org/jira/browse/LOG4J2-180 + * Tests LOG4J2-180 *

* Running from a Windows command line from the root of the project: *

* *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleJira180Main log4j-core/target/test-classes/log4j2-180.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleJira180Main log4j-core/target/test-classes/log4j2-180.xml
  * 
*/ public class ConsoleAppenderAnsiStyleJira180Main { @@ -37,10 +37,8 @@ public class ConsoleAppenderAnsiStyleJira180Main { private static final Logger LOG = LogManager.getLogger(ConsoleAppenderAnsiStyleJira180Main.class); public static void main(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - // System.out.println(System.getProperty("java.class.path")); final String config = args.length == 0 ? "target/test-classes/log4j2-180.xml" : args[0]; - try (final LoggerContext ctx = + try (final LoggerContext ignored = Configurator.initialize(ConsoleAppenderAnsiMessagesMain.class.getName(), config)) { LOG.fatal("Fatal message."); LOG.error("Error message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira272Main.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira272Main.java index 0f2844abe77..65a4ed1ee79 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira272Main.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira272Main.java @@ -23,12 +23,12 @@ import org.apache.logging.log4j.core.config.Configurator; /** - * Tests https://issues.apache.org/jira/browse/LOG4J2-272 + * Tests LOG4J2-272 *

* Running from a Windows command line from the root of the project: *

*
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleJira272Main log4j-core/target/test-classes/log4j2-272.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleJira272Main log4j-core/target/test-classes/log4j2-272.xml
  * 
*/ public class ConsoleAppenderAnsiStyleJira272Main { @@ -36,10 +36,8 @@ public class ConsoleAppenderAnsiStyleJira272Main { private static final Logger LOG = LogManager.getLogger(ConsoleAppenderAnsiStyleJira272Main.class); public static void main(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - // System.out.println(System.getProperty("java.class.path")); final String config = args.length == 0 ? "target/test-classes/log4j2-272.xml" : args[0]; - try (final LoggerContext ctx = + try (final LoggerContext ignored = Configurator.initialize(ConsoleAppenderAnsiMessagesMain.class.getName(), config)) { LOG.fatal("Fatal message."); LOG.error("Error message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira319Main.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira319Main.java index 48681a85f71..957a58e9bf6 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira319Main.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleJira319Main.java @@ -23,13 +23,13 @@ import org.apache.logging.log4j.core.config.Configurator; /** - * Tests https://issues.apache.org/jira/browse/LOG4J2-319 + * Tests LOG4J2-319 *

* Running from a Windows command line from the root of the project: *

* *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleJira319Main log4j-core/target/test-classes/log4j2-319.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleJira319Main log4j-core/target/test-classes/log4j2-319.xml
  * 
*/ public class ConsoleAppenderAnsiStyleJira319Main { @@ -37,10 +37,8 @@ public class ConsoleAppenderAnsiStyleJira319Main { private static final Logger LOG = LogManager.getLogger(ConsoleAppenderAnsiStyleJira319Main.class); public static void main(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - // System.out.println(System.getProperty("java.class.path")); final String config = args.length == 0 ? "target/test-classes/log4j2-319.xml" : args[0]; - try (final LoggerContext ctx = + try (final LoggerContext ignored = Configurator.initialize(ConsoleAppenderAnsiMessagesMain.class.getName(), config)) { LOG.fatal("Fatal message."); LOG.error("Error message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleLayoutMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleLayoutMain.java index 87730d9a5a4..2ef1c52c9fa 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleLayoutMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleLayoutMain.java @@ -35,7 +35,7 @@ * * or: *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleLayoutMain log4j-core/target/test-classes/log4j2-console-style-ansi.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiStyleLayoutMain log4j-core/target/test-classes/log4j2-console-style-ansi.xml
  * 
* */ @@ -54,11 +54,9 @@ public void test() { } public void test(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - // System.out.println(System.getProperty("java.class.path")); final String config = args == null || args.length == 0 ? "target/test-classes/log4j2-console-style-ansi.xml" : args[0]; - try (final LoggerContext ctx = + try (final LoggerContext ignored = Configurator.initialize(ConsoleAppenderAnsiMessagesMain.class.getName(), config)) { final Logger logger = LogManager.getLogger(ConsoleAppenderAnsiStyleLayoutMain.class); logger.fatal("Fatal message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleNameLayoutMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleNameLayoutMain.java index 9088b75d47a..5cdc81ee452 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleNameLayoutMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiStyleNameLayoutMain.java @@ -31,8 +31,7 @@ public class ConsoleAppenderAnsiStyleNameLayoutMain { private static final Logger LOG = LogManager.getLogger(ConsoleAppenderAnsiStyleNameLayoutMain.class); public static void main(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - try (final LoggerContext ctx = Configurator.initialize( + try (final LoggerContext ignored = Configurator.initialize( ConsoleAppenderAnsiMessagesMain.class.getName(), "target/test-classes/log4j2-console-style-name-ansi.xml")) { LOG.fatal("Fatal message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJAnsiXExceptionMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiXExceptionMain.java similarity index 78% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJAnsiXExceptionMain.java rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiXExceptionMain.java index d681e02c754..ee062add98e 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJAnsiXExceptionMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderAnsiXExceptionMain.java @@ -22,9 +22,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.test.categories.Layouts; import org.junit.Test; -import org.junit.experimental.categories.Category; /** * Shows how to use ANSI escape codes to color messages. Each message is printed to the console in color, but the rest @@ -34,21 +32,20 @@ *

* *
- * mvn -Dtest=org.apache.logging.log4j.core.appender.ConsoleAppenderJAnsiXExceptionMain test
+ * mvn -Dtest=org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiXExceptionMain test
  * 
* * or, on Windows: * *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%USERPROFILE%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderJAnsiXExceptionMain log4j-core/src/test/resources/log4j2-console-xex-ansi.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderAnsiXExceptionMain log4j-core/src/test/resources/log4j2-console-xex-ansi.xml
  * 
* */ -@Category(Layouts.Jansi.class) -public class ConsoleAppenderJAnsiXExceptionMain { +public class ConsoleAppenderAnsiXExceptionMain { public static void main(final String[] args) { - new ConsoleAppenderJAnsiXExceptionMain().test(args); + new ConsoleAppenderAnsiXExceptionMain().test(args); } /** @@ -60,12 +57,10 @@ public void test() { } public void test(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - // System.out.println(System.getProperty("java.class.path")); final String config = args == null || args.length == 0 ? "target/test-classes/log4j2-console-xex-ansi.xml" : args[0]; final LoggerContext ctx = Configurator.initialize(ConsoleAppenderAnsiMessagesMain.class.getName(), config); - final Logger logger = LogManager.getLogger(ConsoleAppenderJAnsiXExceptionMain.class); + final Logger logger = LogManager.getLogger(ConsoleAppenderAnsiXExceptionMain.class); try { Files.getFileStore(Paths.get("?BOGUS?")); } catch (final Exception e) { diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderDefaultSuppressedThrowable.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderDefaultSuppressedThrowable.java index 8553eb3f1d0..2432df32c93 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderDefaultSuppressedThrowable.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderDefaultSuppressedThrowable.java @@ -31,7 +31,7 @@ *

* *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderNoAnsiStyleLayoutMain log4j-core/target/test-classes/log4j2-console-style-ansi.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderNoAnsiStyleLayoutMain log4j-core/target/test-classes/log4j2-console-style-ansi.xml
  * 
*/ public class ConsoleAppenderDefaultSuppressedThrowable { @@ -41,12 +41,11 @@ public class ConsoleAppenderDefaultSuppressedThrowable { public static void main(final String[] args) { final String config = args.length == 0 ? "target/test-classes/log4j2-console-default-suppressed-throwable.xml" : args[0]; - test(args, config); + test(config); } - static void test(final String[] args, final String config) { - // System.out.println(System.getProperty("java.class.path")); - try (final LoggerContext ctx = + static void test(final String config) { + try (final LoggerContext ignored = Configurator.initialize(ConsoleAppenderDefaultSuppressedThrowable.class.getName(), config)) { final IOException ioEx = new IOException("test suppressed"); ioEx.addSuppressed(new IOException("test suppressed 1", new IOException("test 1"))); @@ -55,8 +54,6 @@ static void test(final String[] args, final String config) { ioEx.addSuppressed(new IOException("test suppressed 2", ioEx2)); final IOException e = new IOException("test", ioEx); LOG.error("Error message {}, suppressed?", "Hi", e); - System.out.println("printStackTrace"); - e.printStackTrace(); } } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutDefaultMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutDefaultMain.java index 7a1b7cf616e..d9b5eeba270 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutDefaultMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutDefaultMain.java @@ -31,8 +31,7 @@ public class ConsoleAppenderHighlightLayoutDefaultMain { private static final Logger LOG = LogManager.getLogger(ConsoleAppenderHighlightLayoutDefaultMain.class); public static void main(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - try (final LoggerContext ctx = Configurator.initialize( + try (final LoggerContext ignored = Configurator.initialize( ConsoleAppenderAnsiMessagesMain.class.getName(), "target/test-classes/log4j2-console-highlight-default.xml")) { LOG.fatal("Fatal message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutMain.java index dbb6958ea25..ad86c245707 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderHighlightLayoutMain.java @@ -31,8 +31,7 @@ public class ConsoleAppenderHighlightLayoutMain { private static final Logger LOG = LogManager.getLogger(ConsoleAppenderHighlightLayoutMain.class); public static void main(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - try (final LoggerContext ctx = Configurator.initialize( + try (final LoggerContext ignored = Configurator.initialize( ConsoleAppenderAnsiMessagesMain.class.getName(), "target/test-classes/log4j2-console-highlight.xml")) { LOG.fatal("Fatal message."); LOG.error("Error message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJAnsiMessageMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJAnsiMessageMain.java deleted file mode 100644 index 56cce35a74b..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJAnsiMessageMain.java +++ /dev/null @@ -1,84 +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.logging.log4j.core.appender; - -import static org.fusesource.jansi.Ansi.Color.CYAN; -import static org.fusesource.jansi.Ansi.Color.RED; -import static org.fusesource.jansi.Ansi.ansi; - -import java.util.Map.Entry; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configurator; -import org.apache.logging.log4j.core.test.categories.Layouts; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.jupiter.api.parallel.ResourceLock; -import org.junit.jupiter.api.parallel.Resources; - -/** - * Shows how to use ANSI escape codes to color messages. Each message is printed to the console in color, but the rest - * of the log entry (time stamp for example) is in the default color for that console. - *

- * Running from a Windows command line from the root of the project: - *

- * - *
- * mvn -Dtest=org.apache.logging.log4j.core.appender.ConsoleAppenderJAnsiMessageMain test
- * 
- * - * or, on Windows: - * - *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%USERPROFILE%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderJAnsiMessageMain log4j-core/src/test/resources/log4j2-console-msg-ansi.xml
- * 
- * - */ -@Category(Layouts.Jansi.class) -public class ConsoleAppenderJAnsiMessageMain { - - public static void main(final String[] args) { - new ConsoleAppenderJAnsiMessageMain().test(args); - } - - /** - * This is a @Test method to make it easy to run from a command line with {@code mvn -Dtest=FQCN test} - */ - @Test - @ResourceLock(Resources.SYSTEM_PROPERTIES) - public void test() { - test(null); - } - - public void test(final String[] args) { - System.setProperty("log4j.skipJansi", "false"); // LOG4J2-2087: explicitly enable - // System.out.println(System.getProperty("java.class.path")); - final String config = - args == null || args.length == 0 ? "target/test-classes/log4j2-console-msg-ansi.xml" : args[0]; - try (final LoggerContext ctx = - Configurator.initialize(ConsoleAppenderAnsiMessagesMain.class.getName(), config)) { - final Logger logger = LogManager.getLogger(ConsoleAppenderJAnsiMessageMain.class); - logger.info(ansi().fg(RED).a("Hello").fg(CYAN).a(" World").reset()); - // JAnsi format: - // logger.info("@|red Hello|@ @|cyan World|@"); - for (final Entry entry : System.getProperties().entrySet()) { - logger.info("@|KeyStyle {}|@ = @|ValueStyle {}|@", entry.getKey(), entry.getValue()); - } - } - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJira1002ShortThrowableLayoutMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJira1002ShortThrowableLayoutMain.java index b75e3e03259..b1177acdd25 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJira1002ShortThrowableLayoutMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderJira1002ShortThrowableLayoutMain.java @@ -21,7 +21,7 @@ */ public class ConsoleAppenderJira1002ShortThrowableLayoutMain { - public static void main(final String[] args) { - ConsoleAppenderNoAnsiStyleLayoutMain.test(args, "target/test-classes/log4j2-1002.xml"); + public static void main() { + ConsoleAppenderNoAnsiStyleLayoutMain.test("target/test-classes/log4j2-1002.xml"); } } diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderNoAnsiStyleLayoutMain.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderNoAnsiStyleLayoutMain.java index 1c35103862e..1165fc6a609 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderNoAnsiStyleLayoutMain.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderNoAnsiStyleLayoutMain.java @@ -30,7 +30,7 @@ *

* *
- * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.14\jansi-1.14.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderNoAnsiStyleLayoutMain log4j-core/target/test-classes/log4j2-console-style-ansi.xml
+ * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes org.apache.logging.log4j.core.appender.ConsoleAppenderNoAnsiStyleLayoutMain log4j-core/target/test-classes/log4j2-console-style-ansi.xml
  * 
*/ public class ConsoleAppenderNoAnsiStyleLayoutMain { @@ -43,12 +43,11 @@ private static void logThrowableFromMethod() { public static void main(final String[] args) { final String config = args.length == 0 ? "target/test-classes/log4j2-console-style-no-ansi.xml" : args[0]; - test(args, config); + test(config); } - static void test(final String[] args, final String config) { - // System.out.println(System.getProperty("java.class.path")); - try (final LoggerContext ctx = + static void test(final String config) { + try (final LoggerContext ignored = Configurator.initialize(ConsoleAppenderNoAnsiStyleLayoutMain.class.getName(), config)) { LOG.fatal("Fatal message."); LOG.error("Error message."); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java index 5eba5acbd73..4e77e0c4331 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java @@ -33,9 +33,7 @@ import org.apache.logging.log4j.core.appender.ConsoleAppender.Target; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.core.test.TestConstants; import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.test.junit.SetTestProperty; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -44,7 +42,6 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -@SetTestProperty(key = TestConstants.CONSOLE_JANSI_ENABLED, value = "false") public class ConsoleAppenderTest { ByteArrayOutputStream baos; diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/JansiConsoleAppenderJira965.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/JansiConsoleAppenderJira965.java deleted file mode 100644 index 8bdd3e13efe..00000000000 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/JansiConsoleAppenderJira965.java +++ /dev/null @@ -1,28 +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.logging.log4j.core.appender; - -import org.slf4j.LoggerFactory; - -public class JansiConsoleAppenderJira965 { - - public static void main(final String[] args) { - System.out.println("Able to print on Windows"); - LoggerFactory.getLogger(JansiConsoleAppenderJira965.class); - System.out.println("Unable to print on Windows"); - } -} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptionsTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptionsTest.java index 4719db85637..5323eace0ec 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptionsTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptionsTest.java @@ -16,26 +16,27 @@ */ package org.apache.logging.log4j.core.impl; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.apache.logging.log4j.util.Strings.toRootUpperCase; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; -import org.apache.logging.log4j.core.pattern.JAnsiTextRenderer; +import org.apache.logging.log4j.core.pattern.AnsiEscape; +import org.apache.logging.log4j.core.pattern.AnsiTextRenderer; import org.apache.logging.log4j.core.pattern.TextRenderer; import org.apache.logging.log4j.util.Strings; -import org.fusesource.jansi.AnsiRenderer.Code; import org.junit.jupiter.api.Test; /** * Unit tests for {@code ThrowableFormatOptions}. */ -public final class ThrowableFormatOptionsTest { +final class ThrowableFormatOptionsTest { /** * Runs a given test comparing against the expected values. @@ -71,7 +72,7 @@ private static ThrowableFormatOptions test( * Test {@code %throwable} with null options. */ @Test - public void testNull() { + void testNull() { test(null, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); } @@ -79,7 +80,7 @@ public void testNull() { * Test {@code %throwable} */ @Test - public void testEmpty() { + void testEmpty() { test(new String[] {}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); } @@ -87,7 +88,7 @@ public void testEmpty() { * Test {@code %throwable{} } with null option value. */ @Test - public void testOneNullElement() { + void testOneNullElement() { test(new String[] {null}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); } @@ -95,7 +96,7 @@ public void testOneNullElement() { * Test {@code %throwable{} } */ @Test - public void testOneEmptyElement() { + void testOneEmptyElement() { test(new String[] {""}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); } @@ -103,7 +104,7 @@ public void testOneEmptyElement() { * Test {@code %throwable{full} } */ @Test - public void testFull() { + void testFull() { test(new String[] {"full"}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); } @@ -111,7 +112,7 @@ public void testFull() { * Test {@code %throwable{full}{ansi} } */ @Test - public void testFullAnsi() { + void testFullAnsi() { final ThrowableFormatOptions tfo = test(new String[] {"full", "ansi"}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); testFullAnsiEmptyConfig(tfo); @@ -121,7 +122,7 @@ public void testFullAnsi() { * Test {@code %throwable{full}{ansi()} } */ @Test - public void testFullAnsiEmptyConfig() { + void testFullAnsiEmptyConfig() { final ThrowableFormatOptions tfo = test(new String[] {"full", "ansi()"}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); testFullAnsiEmptyConfig(tfo); @@ -130,34 +131,34 @@ public void testFullAnsiEmptyConfig() { private void testFullAnsiEmptyConfig(final ThrowableFormatOptions tfo) { final TextRenderer textRenderer = tfo.getTextRenderer(); assertNotNull(textRenderer); - assertTrue(textRenderer instanceof JAnsiTextRenderer); - final JAnsiTextRenderer jansiRenderer = (JAnsiTextRenderer) textRenderer; - final Map styleMap = jansiRenderer.getStyleMap(); + assertInstanceOf(AnsiTextRenderer.class, textRenderer); + final AnsiTextRenderer ansiRenderer = (AnsiTextRenderer) textRenderer; + final Map styleMap = ansiRenderer.getStyleMap(); // We have defaults assertFalse(styleMap.isEmpty()); - assertNotNull(styleMap.get("Name")); + assertNotNull(styleMap.get(toRootUpperCase("Name"))); } /** * Test {@code %throwable{full}{ansi(Warning=red))} } */ @Test - public void testFullAnsiWithCustomStyle() { + void testFullAnsiWithCustomStyle() { final ThrowableFormatOptions tfo = test(new String[] {"full", "ansi(Warning=red)"}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); final TextRenderer textRenderer = tfo.getTextRenderer(); assertNotNull(textRenderer); - assertTrue(textRenderer instanceof JAnsiTextRenderer); - final JAnsiTextRenderer jansiRenderer = (JAnsiTextRenderer) textRenderer; - final Map styleMap = jansiRenderer.getStyleMap(); - assertArrayEquals(new Code[] {Code.RED}, styleMap.get("Warning")); + assertInstanceOf(AnsiTextRenderer.class, textRenderer); + final AnsiTextRenderer ansiRenderer = (AnsiTextRenderer) textRenderer; + final Map styleMap = ansiRenderer.getStyleMap(); + assertThat(styleMap.get(toRootUpperCase("Warning"))).isEqualTo(AnsiEscape.createSequence("RED")); } /** * Test {@code %throwable{full}{ansi(Warning=red Key=blue Value=cyan))} } */ @Test - public void testFullAnsiWithCustomStyles() { + void testFullAnsiWithCustomStyles() { final ThrowableFormatOptions tfo = test( new String[] {"full", "ansi(Warning=red Key=blue Value=cyan)"}, Integer.MAX_VALUE, @@ -165,19 +166,19 @@ public void testFullAnsiWithCustomStyles() { null); final TextRenderer textRenderer = tfo.getTextRenderer(); assertNotNull(textRenderer); - assertTrue(textRenderer instanceof JAnsiTextRenderer); - final JAnsiTextRenderer jansiRenderer = (JAnsiTextRenderer) textRenderer; - final Map styleMap = jansiRenderer.getStyleMap(); - assertArrayEquals(new Code[] {Code.RED}, styleMap.get("Warning")); - assertArrayEquals(new Code[] {Code.BLUE}, styleMap.get("Key")); - assertArrayEquals(new Code[] {Code.CYAN}, styleMap.get("Value")); + assertInstanceOf(AnsiTextRenderer.class, textRenderer); + final AnsiTextRenderer ansiRenderer = (AnsiTextRenderer) textRenderer; + final Map styleMap = ansiRenderer.getStyleMap(); + assertThat(styleMap.get(toRootUpperCase("Warning"))).isEqualTo(AnsiEscape.createSequence("RED")); + assertThat(styleMap.get(toRootUpperCase("Key"))).isEqualTo(AnsiEscape.createSequence("BLUE")); + assertThat(styleMap.get(toRootUpperCase("Value"))).isEqualTo(AnsiEscape.createSequence("CYAN")); } /** * Test {@code %throwable{full}{ansi(Warning=red Key=blue,bg_red Value=cyan,bg_black,underline)} } */ @Test - public void testFullAnsiWithCustomComplexStyles() { + void testFullAnsiWithCustomComplexStyles() { final ThrowableFormatOptions tfo = test( new String[] {"full", "ansi(Warning=red Key=blue,bg_red Value=cyan,bg_black,underline)"}, Integer.MAX_VALUE, @@ -185,19 +186,20 @@ public void testFullAnsiWithCustomComplexStyles() { null); final TextRenderer textRenderer = tfo.getTextRenderer(); assertNotNull(textRenderer); - assertTrue(textRenderer instanceof JAnsiTextRenderer); - final JAnsiTextRenderer jansiRenderer = (JAnsiTextRenderer) textRenderer; - final Map styleMap = jansiRenderer.getStyleMap(); - assertArrayEquals(new Code[] {Code.RED}, styleMap.get("Warning")); - assertArrayEquals(new Code[] {Code.BLUE, Code.BG_RED}, styleMap.get("Key")); - assertArrayEquals(new Code[] {Code.CYAN, Code.BG_BLACK, Code.UNDERLINE}, styleMap.get("Value")); + assertInstanceOf(AnsiTextRenderer.class, textRenderer); + final AnsiTextRenderer ansiRenderer = (AnsiTextRenderer) textRenderer; + final Map styleMap = ansiRenderer.getStyleMap(); + assertThat(styleMap.get(toRootUpperCase("Warning"))).isEqualTo(AnsiEscape.createSequence("RED")); + assertThat(styleMap.get(toRootUpperCase("Key"))).isEqualTo(AnsiEscape.createSequence("BLUE", "BG_RED")); + assertThat(styleMap.get(toRootUpperCase("Value"))) + .isEqualTo(AnsiEscape.createSequence("CYAN", "BG_BLACK", "UNDERLINE")); } /** * Test {@code %throwable{none} } */ @Test - public void testNone() { + void testNone() { test(new String[] {"none"}, 0, Strings.LINE_SEPARATOR, null); } @@ -205,7 +207,7 @@ public void testNone() { * Test {@code %throwable{short} } */ @Test - public void testShort() { + void testShort() { test(new String[] {"short"}, 2, Strings.LINE_SEPARATOR, null); } @@ -213,7 +215,7 @@ public void testShort() { * Test {@code %throwable{10} } */ @Test - public void testDepth() { + void testDepth() { test(new String[] {"10"}, 10, Strings.LINE_SEPARATOR, null); } @@ -221,7 +223,7 @@ public void testDepth() { * Test {@code %throwable{separator(|)} } */ @Test - public void testSeparator() { + void testSeparator() { test(new String[] {"separator(|)"}, Integer.MAX_VALUE, "|", null); } @@ -229,7 +231,7 @@ public void testSeparator() { * Test {@code %throwable{separator()} } */ @Test - public void testSeparatorAsEmpty() { + void testSeparatorAsEmpty() { test(new String[] {"separator()"}, Integer.MAX_VALUE, Strings.EMPTY, null); } @@ -237,7 +239,7 @@ public void testSeparatorAsEmpty() { * Test {@code %throwable{separator(\n)} } */ @Test - public void testSeparatorAsDefaultLineSeparator() { + void testSeparatorAsDefaultLineSeparator() { test( new String[] {"separator(" + Strings.LINE_SEPARATOR + ')'}, Integer.MAX_VALUE, @@ -249,7 +251,7 @@ public void testSeparatorAsDefaultLineSeparator() { * Test {@code %throwable{separator( | )} } */ @Test - public void testSeparatorAsMultipleCharacters() { + void testSeparatorAsMultipleCharacters() { test(new String[] {"separator( | )"}, Integer.MAX_VALUE, " | ", null); } @@ -257,7 +259,7 @@ public void testSeparatorAsMultipleCharacters() { * Test {@code %throwable{full}{separator(|)} } */ @Test - public void testFullAndSeparator() { + void testFullAndSeparator() { test(new String[] {"full", "separator(|)"}, Integer.MAX_VALUE, "|", null); } @@ -265,7 +267,7 @@ public void testFullAndSeparator() { * Test {@code %throwable{full}{filters(org.junit)}{separator(|)} } */ @Test - public void testFullAndFiltersAndSeparator() { + void testFullAndFiltersAndSeparator() { test( new String[] {"full", "filters(org.junit)", "separator(|)"}, Integer.MAX_VALUE, @@ -277,7 +279,7 @@ public void testFullAndFiltersAndSeparator() { * Test {@code %throwable{none}{separator(|)} } */ @Test - public void testNoneAndSeparator() { + void testNoneAndSeparator() { test(new String[] {"none", "separator(|)"}, 0, "|", null); } @@ -285,7 +287,7 @@ public void testNoneAndSeparator() { * Test {@code %throwable{short}{separator(|)} } */ @Test - public void testShortAndSeparator() { + void testShortAndSeparator() { test(new String[] {"short", "separator(|)"}, 2, "|", null); } @@ -293,7 +295,7 @@ public void testShortAndSeparator() { * Test {@code %throwable{10}{separator(|)} } */ @Test - public void testDepthAndSeparator() { + void testDepthAndSeparator() { test(new String[] {"10", "separator(|)"}, 10, "|", null); } @@ -301,7 +303,7 @@ public void testDepthAndSeparator() { * Test {@code %throwable{filters(packages)} } */ @Test - public void testFilters() { + void testFilters() { test( new String[] {"filters(packages)"}, Integer.MAX_VALUE, @@ -313,7 +315,7 @@ public void testFilters() { * Test {@code %throwable{filters()} } */ @Test - public void testFiltersAsEmpty() { + void testFiltersAsEmpty() { test(new String[] {"filters()"}, Integer.MAX_VALUE, Strings.LINE_SEPARATOR, null); } @@ -321,7 +323,7 @@ public void testFiltersAsEmpty() { * Test {@code %throwable{filters(package1,package2)} } */ @Test - public void testFiltersAsMultiplePackages() { + void testFiltersAsMultiplePackages() { test( new String[] {"filters(package1,package2)"}, Integer.MAX_VALUE, @@ -333,7 +335,7 @@ public void testFiltersAsMultiplePackages() { * Test {@code %throwable{full}{filters(packages)} } */ @Test - public void testFullAndFilters() { + void testFullAndFilters() { test( new String[] {"full", "filters(packages)"}, Integer.MAX_VALUE, @@ -345,7 +347,7 @@ public void testFullAndFilters() { * Test {@code %throwable{none}{filters(packages)} } */ @Test - public void testNoneAndFilters() { + void testNoneAndFilters() { test( new String[] {"none", "filters(packages)"}, 0, @@ -357,7 +359,7 @@ public void testNoneAndFilters() { * Test {@code %throwable{short}{filters(packages)} } */ @Test - public void testShortAndFilters() { + void testShortAndFilters() { test( new String[] {"short", "filters(packages)"}, 2, @@ -369,7 +371,7 @@ public void testShortAndFilters() { * Test {@code %throwable{10}{filters(packages)} } */ @Test - public void testDepthAndFilters() { + void testDepthAndFilters() { test( new String[] {"10", "filters(packages)"}, 10, @@ -381,7 +383,7 @@ public void testDepthAndFilters() { * Test {@code %throwable{full}{separator(|)}{filters(packages)} } */ @Test - public void testFullAndSeparatorAndFilter() { + void testFullAndSeparatorAndFilter() { test( new String[] {"full", "separator(|)", "filters(packages)"}, Integer.MAX_VALUE, @@ -393,7 +395,7 @@ public void testFullAndSeparatorAndFilter() { * Test {@code %throwable{full}{separator(|)}{filters(package1,package2)} } */ @Test - public void testFullAndSeparatorAndFilters() { + void testFullAndSeparatorAndFilters() { test( new String[] {"full", "separator(|)", "filters(package1,package2)"}, Integer.MAX_VALUE, @@ -405,7 +407,7 @@ public void testFullAndSeparatorAndFilters() { * Test {@code %throwable{none}{separator(|)}{filters(packages)} } */ @Test - public void testNoneAndSeparatorAndFilters() { + void testNoneAndSeparatorAndFilters() { test(new String[] {"none", "separator(|)", "filters(packages)"}, 0, "|", Collections.singletonList("packages")); } @@ -413,7 +415,7 @@ public void testNoneAndSeparatorAndFilters() { * Test {@code %throwable{short}{separator(|)}{filters(packages)} } */ @Test - public void testShortAndSeparatorAndFilters() { + void testShortAndSeparatorAndFilters() { test( new String[] {"short", "separator(|)", "filters(packages)"}, 2, @@ -425,7 +427,7 @@ public void testShortAndSeparatorAndFilters() { * Test {@code %throwable{10}{separator(|)}{filters(packages)} } */ @Test - public void testDepthAndSeparatorAndFilters() { + void testDepthAndSeparatorAndFilters() { test(new String[] {"10", "separator(|)", "filters(packages)"}, 10, "|", Collections.singletonList("packages")); } @@ -433,7 +435,7 @@ public void testDepthAndSeparatorAndFilters() { * Test {@code %throwable{full,filters(packages)} } */ @Test - public void testSingleOptionFullAndFilters() { + void testSingleOptionFullAndFilters() { test( new String[] {"full,filters(packages)"}, Integer.MAX_VALUE, @@ -445,7 +447,7 @@ public void testSingleOptionFullAndFilters() { * Test {@code %throwable{none,filters(packages)} } */ @Test - public void testSingleOptionNoneAndFilters() { + void testSingleOptionNoneAndFilters() { test(new String[] {"none,filters(packages)"}, 0, Strings.LINE_SEPARATOR, Collections.singletonList("packages")); } @@ -453,7 +455,7 @@ public void testSingleOptionNoneAndFilters() { * Test {@code %throwable{short,filters(packages)} } */ @Test - public void testSingleOptionShortAndFilters() { + void testSingleOptionShortAndFilters() { test( new String[] {"short,filters(packages)"}, 2, @@ -465,7 +467,7 @@ public void testSingleOptionShortAndFilters() { * Test {@code %throwable{none,filters(packages)} } */ @Test - public void testSingleOptionDepthAndFilters() { + void testSingleOptionDepthAndFilters() { test(new String[] {"10,filters(packages)"}, 10, Strings.LINE_SEPARATOR, Collections.singletonList("packages")); } @@ -473,7 +475,7 @@ public void testSingleOptionDepthAndFilters() { * Test {@code %throwable{full,filters(package1,package2)} } */ @Test - public void testSingleOptionFullAndMultipleFilters() { + void testSingleOptionFullAndMultipleFilters() { test( new String[] {"full,filters(package1,package2)"}, Integer.MAX_VALUE, @@ -485,7 +487,7 @@ public void testSingleOptionFullAndMultipleFilters() { * Test {@code %throwable{none,filters(package1,package2)} } */ @Test - public void testSingleOptionNoneAndMultipleFilters() { + void testSingleOptionNoneAndMultipleFilters() { test( new String[] {"none,filters(package1,package2)"}, 0, @@ -497,7 +499,7 @@ public void testSingleOptionNoneAndMultipleFilters() { * Test {@code %throwable{short,filters(package1,package2)} } */ @Test - public void testSingleOptionShortAndMultipleFilters() { + void testSingleOptionShortAndMultipleFilters() { test( new String[] {"short,filters(package1,package2)"}, 2, @@ -509,7 +511,7 @@ public void testSingleOptionShortAndMultipleFilters() { * Test {@code %throwable{none,filters(package1,package2)} } */ @Test - public void testSingleOptionDepthAndMultipleFilters() { + void testSingleOptionDepthAndMultipleFilters() { test( new String[] {"10,filters(package1,package2)"}, 10, diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/AnsiTextRendererTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/AnsiTextRendererTest.java new file mode 100644 index 00000000000..17e590a86a2 --- /dev/null +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/AnsiTextRendererTest.java @@ -0,0 +1,58 @@ +/* + * 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.logging.log4j.core.pattern; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.presentation.HexadecimalRepresentation.HEXA_REPRESENTATION; + +import java.util.Map; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class AnsiTextRendererTest { + + public static Stream testRendering() { + return Stream.of( + // Use style names + Arguments.of( + "KeyStyle=white ValueStyle=cyan,bold", + "@|KeyStyle key|@ = @|ValueStyle some value|@", + "\u001b[37mkey\u001b[m = \u001b[36;1msome value\u001b[m"), + // Use AnsiEscape codes directly + Arguments.of( + "", + "@|white key|@ = @|cyan,bold some value|@", + "\u001b[37mkey\u001b[m = \u001b[36;1msome value\u001b[m"), + // Return broken escapes as is + Arguments.of("", "Hello @|crazy|@ world!", "Hello @|crazy|@ world!"), + Arguments.of("", "Hello @|world!", "Hello @|world!")); + } + + @ParameterizedTest + @MethodSource + void testRendering(final String format, final String text, final String expected) { + final AnsiTextRenderer renderer = new AnsiTextRenderer(new String[] {"ansi", format}, Map.of()); + final StringBuilder actual = new StringBuilder(); + renderer.render(new StringBuilder(text), actual); + assertThat(actual.toString()) + .as("Rendering text '%s'", text) + .withRepresentation(HEXA_REPRESENTATION) + .isEqualTo(expected); + } +} diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageJansiConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageAnsiConverterTest.java similarity index 94% rename from log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageJansiConverterTest.java rename to log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageAnsiConverterTest.java index 293db30ba99..670fefd097f 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageJansiConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageAnsiConverterTest.java @@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test; @LoggerContextSource("log4j-message-ansi.xml") -public class MessageJansiConverterTest { +public class MessageAnsiConverterTest { private static final String EXPECTED = "\u001B[31;1mWarning!\u001B[m Pants on \u001B[31mfire!\u001B[m" + Strings.LINE_SEPARATOR; @@ -47,7 +47,7 @@ public void setUp(final LoggerContext context, @Named("List") final ListAppender @Test public void testReplacement() { - // See org.fusesource.jansi.AnsiRenderer + // See https://www.javadoc.io/doc/org.jline/jline/latest/org/jline/jansi/AnsiRenderer.html logger.error("@|red,bold Warning!|@ Pants on @|red fire!|@"); final List msgs = app.getMessages(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageStyledConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageStyledConverterTest.java index 71fb6fbc77b..06ab681fedd 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageStyledConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/MessageStyledConverterTest.java @@ -47,7 +47,7 @@ public void setUp(final LoggerContext context, @Named("List") final ListAppender @Test public void testReplacement() { - // See org.fusesource.jansi.AnsiRenderer + // See https://www.javadoc.io/doc/org.jline/jline/latest/org/jline/jansi/AnsiRenderer.html logger.error("@|WarningStyle Warning!|@ Pants on @|WarningStyle fire!|@"); final List msgs = app.getMessages(); diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java index 6a5a77951fa..01b3f51d306 100644 --- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java +++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/StyleConverterTest.java @@ -26,19 +26,16 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.test.TestConstants; import org.apache.logging.log4j.core.test.appender.ListAppender; import org.apache.logging.log4j.core.test.junit.LoggerContextSource; import org.apache.logging.log4j.core.test.junit.Named; import org.apache.logging.log4j.test.ListStatusListener; -import org.apache.logging.log4j.test.junit.SetTestProperty; import org.apache.logging.log4j.test.junit.UsingStatusListener; import org.apache.logging.log4j.util.Strings; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -@SetTestProperty(key = TestConstants.CONSOLE_JANSI_ENABLED, value = "true") public class StyleConverterTest { private static final String EXPECTED = diff --git a/log4j-core-test/src/test/resources/log4j2-console-msg-ansi.xml b/log4j-core-test/src/test/resources/log4j2-console-msg-ansi.xml deleted file mode 100644 index d30b0fb406b..00000000000 --- a/log4j-core-test/src/test/resources/log4j2-console-msg-ansi.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 0062f543ff6..b2b00b30d82 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -43,10 +43,8 @@ org.jspecify.*;resolution:=optional, - - org.fusesource.jansi;resolution:=optional, - + java.lang.management;resolution:=optional, javax.management.*;resolution:=optional, @@ -64,7 +62,6 @@ java.sql;transitive=false, java.xml;transitive=false, jdk.unsupported;transitive=false, - org.fusesource.jansi;transitive=false, org.jspecify;transitive=false @@ -101,13 +98,6 @@ log4j-plugins
- - - org.fusesource.jansi - jansi - true - - diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java index 5077bba5ed7..4e6dbb47ae0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java @@ -20,29 +20,19 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.PrintStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Constructor; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.util.concurrent.atomic.AtomicInteger; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.impl.CoreProperties.ConsoleProperties; import org.apache.logging.log4j.core.util.CloseShieldOutputStream; -import org.apache.logging.log4j.core.util.Loader; -import org.apache.logging.log4j.core.util.Throwables; -import org.apache.logging.log4j.kit.env.PropertyEnvironment; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginFactory; import org.apache.logging.log4j.plugins.validation.constraints.Required; -import org.apache.logging.log4j.util.Chars; -import org.apache.logging.log4j.util.PropertiesUtil; /** * Appends log events to System.out or System.err using a layout specified by the user. The @@ -59,7 +49,6 @@ public final class ConsoleAppender extends AbstractOutputStreamAppender { public static final String PLUGIN_NAME = "Console"; - private static final String JANSI_CLASS = "org.fusesource.jansi.WindowsAnsiOutputStream"; private static final ConsoleManagerFactory factory = new ConsoleManagerFactory(); private static final Target DEFAULT_TARGET = Target.SYSTEM_OUT; private static final AtomicInteger COUNT = new AtomicInteger(); @@ -127,7 +116,7 @@ public static ConsoleAppender createDefaultAppenderForLayout(final Layout layout "DefaultConsole-" + COUNT.incrementAndGet(), layout, null, - getDefaultManager(DEFAULT_TARGET, false, false, layout), + getDefaultManager(layout), true, DEFAULT_TARGET, null); @@ -172,91 +161,43 @@ public B setDirect(final boolean shouldDirect) { @Override public ConsoleAppender build() { - if (follow && direct) { - throw new IllegalArgumentException( - "Cannot use both follow and direct on ConsoleAppender '" + getName() + "'"); + if (direct && follow) { + LOGGER.error("Cannot use both `direct` and `follow` on ConsoleAppender."); + return null; } final Layout layout = getOrCreateLayout(target.getDefaultCharset()); - final Configuration configuration = getConfiguration(); - final PropertyEnvironment propertyEnvironment = - configuration != null && configuration.getLoggerContext() != null - ? configuration.getLoggerContext().getEnvironment() - : PropertyEnvironment.getGlobal(); + + OutputStream stream = direct + ? getDirectOutputStream(target) + : follow ? getFollowOutputStream(target) : getDefaultOutputStream(target); + + final String managerName = target.name() + '.' + follow + '.' + direct; + final OutputStreamManager manager = + OutputStreamManager.getManager(managerName, new FactoryData(stream, managerName, layout), factory); return new ConsoleAppender( - getName(), - layout, - getFilter(), - getManager(target, follow, direct, layout, propertyEnvironment), - isIgnoreExceptions(), - target, - getPropertyArray()); + getName(), layout, getFilter(), manager, isIgnoreExceptions(), target, getPropertyArray()); } } - private static OutputStreamManager getDefaultManager( - final Target target, final boolean follow, final boolean direct, final Layout layout) { - final OutputStream os = getOutputStream(follow, direct, target, PropertyEnvironment.getGlobal()); - + private static OutputStreamManager getDefaultManager(final Layout layout) { + final OutputStream os = new CloseShieldOutputStream( + ConsoleAppender.DEFAULT_TARGET == Target.SYSTEM_ERR ? System.err : System.out); // LOG4J2-1176 DefaultConfiguration should not share OutputStreamManager instances to avoid memory leaks. - final String managerName = target.name() + '.' + follow + '.' + direct + "-" + COUNT.get(); + final String managerName = ConsoleAppender.DEFAULT_TARGET.name() + ".false.false-" + COUNT.get(); return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory); } - private static OutputStreamManager getManager( - final Target target, - final boolean follow, - final boolean direct, - final Layout layout, - final PropertyEnvironment properties) { - final OutputStream os = getOutputStream(follow, direct, target, properties); - final String managerName = target.name() + '.' + follow + '.' + direct; - return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory); + private static OutputStream getDefaultOutputStream(Target target) { + return new CloseShieldOutputStream(target == Target.SYSTEM_OUT ? System.out : System.err); } - private static OutputStream getOutputStream( - final boolean follow, final boolean direct, final Target target, final PropertyEnvironment properties) { - final String enc = Charset.defaultCharset().name(); - OutputStream outputStream; - try { - // @formatter:off - outputStream = target == Target.SYSTEM_OUT - ? direct - ? new FileOutputStream(FileDescriptor.out) - : (follow ? new PrintStream(new SystemOutStream(), true, enc) : System.out) - : direct - ? new FileOutputStream(FileDescriptor.err) - : (follow ? new PrintStream(new SystemErrStream(), true, enc) : System.err); - // @formatter:on - outputStream = new CloseShieldOutputStream(outputStream); - } catch (final UnsupportedEncodingException ex) { // should never happen - throw new IllegalStateException("Unsupported default encoding " + enc, ex); - } - if (!PropertiesUtil.getProperties().isOsWindows() - || !Boolean.FALSE.equals( - properties.getProperty(ConsoleProperties.class).jansiEnabled()) - || direct) { - return outputStream; - } - try { - // We type the parameter as a wildcard to avoid a hard reference to Jansi. - final Class clazz = Loader.loadClass(JANSI_CLASS); - final Constructor constructor = clazz.getConstructor(OutputStream.class); - return new CloseShieldOutputStream((OutputStream) constructor.newInstance(outputStream)); - } catch (final ClassNotFoundException cnfe) { - LOGGER.debug("Jansi is not installed, cannot find {}", JANSI_CLASS); - } catch (final NoSuchMethodException nsme) { - LOGGER.warn("{} is missing the proper constructor", JANSI_CLASS); - } catch (final Exception ex) { - LOGGER.warn( - "Unable to instantiate {} due to {}", - JANSI_CLASS, - clean(Throwables.getRootCause(ex).toString()).trim()); - } - return outputStream; + private static OutputStream getDirectOutputStream(Target target) { + return new CloseShieldOutputStream( + new FileOutputStream(target == Target.SYSTEM_OUT ? FileDescriptor.out : FileDescriptor.err)); } - private static String clean(final String string) { - return string.replace(Chars.NUL, Chars.SPACE); + private static OutputStream getFollowOutputStream(Target target) { + return target == Target.SYSTEM_OUT ? new SystemOutStream() : new SystemErrStream(); } /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/CoreProperties.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/CoreProperties.java index 27188eba778..82abc8733a1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/CoreProperties.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/CoreProperties.java @@ -107,12 +107,6 @@ public record ConfigurationProperties( boolean usePreciseClock, @Log4jProperty(defaultValue = "5000") long waitMillisBeforeStopOldConfig) {} - /** - * Properties to tune console output. - */ - @Log4jProperty(name = "console") - public record ConsoleProperties(@Nullable Boolean jansiEnabled) {} - /** * Properties to tune garbage collection. */ diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java index 832f7646e09..07a5d4ab249 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThrowableFormatOptions.java @@ -19,12 +19,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Scanner; -import org.apache.logging.log4j.core.pattern.JAnsiTextRenderer; +import org.apache.logging.log4j.core.pattern.AnsiTextRenderer; import org.apache.logging.log4j.core.pattern.PlainTextRenderer; import org.apache.logging.log4j.core.pattern.TextRenderer; -import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.core.util.Patterns; -import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Strings; /** @@ -289,17 +287,11 @@ public static ThrowableFormatOptions newInstance(String[] options) { || option.equalsIgnoreCase(LOCALIZED_MESSAGE)) { lines = 2; } else if (option.startsWith("ansi(") && option.endsWith(")") || option.equals("ansi")) { - if (Loader.isJansiAvailable()) { - final String styleMapStr = option.equals("ansi") - ? Strings.EMPTY - : option.substring("ansi(".length(), option.length() - 1); - ansiRenderer = new JAnsiTextRenderer( - new String[] {null, styleMapStr}, JAnsiTextRenderer.DefaultExceptionStyleMap); - } else { - StatusLogger.getLogger() - .warn( - "You requested ANSI exception rendering but JANSI is not on the classpath. Please see https://logging.apache.org/log4j/2.x/runtime-dependencies.html"); - } + final String styleMapStr = option.equals("ansi") + ? Strings.EMPTY + : option.substring("ansi(".length(), option.length() - 1); + ansiRenderer = new AnsiTextRenderer( + new String[] {null, styleMapStr}, AnsiTextRenderer.DEFAULT_EXCEPTION_STYLE_MAP); } else if (option.startsWith("S(") && option.endsWith(")")) { suffix = option.substring("S(".length(), option.length() - 1); } else if (option.startsWith("suffix(") && option.endsWith(")")) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java index 24ce2d345a5..b9b3f9f7dc9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java @@ -16,8 +16,6 @@ */ package org.apache.logging.log4j.core.layout; -import static java.lang.Boolean.TRUE; - import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; @@ -27,20 +25,17 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; -import org.apache.logging.log4j.core.impl.CoreProperties; import org.apache.logging.log4j.core.pattern.FormattingInfo; import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; import org.apache.logging.log4j.core.pattern.PatternFormatter; import org.apache.logging.log4j.core.pattern.PatternParser; import org.apache.logging.log4j.core.pattern.RegexReplacement; -import org.apache.logging.log4j.kit.env.PropertyEnvironment; import org.apache.logging.log4j.kit.recycler.Recycler; import org.apache.logging.log4j.plugins.Configurable; import org.apache.logging.log4j.plugins.Plugin; import org.apache.logging.log4j.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.plugins.PluginElement; import org.apache.logging.log4j.plugins.PluginFactory; -import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Strings; /** @@ -577,7 +572,7 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui private boolean alwaysWriteExceptions = true; @PluginBuilderAttribute - private boolean disableAnsi = !useAnsiEscapeCodes(); + private boolean disableAnsi; @PluginBuilderAttribute private boolean noConsoleNoAnsi; @@ -590,16 +585,6 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui private Builder() {} - private boolean useAnsiEscapeCodes() { - final PropertyEnvironment properties = PropertyEnvironment.getGlobal(); - final boolean isPlatformSupportsAnsi = - !PropertiesUtil.getProperties().isOsWindows(); - final boolean isJansiRequested = TRUE.equals(PropertyEnvironment.getGlobal() - .getProperty(CoreProperties.ConsoleProperties.class) - .jansiEnabled()); - return isPlatformSupportsAnsi || isJansiRequested; - } - /** * @param pattern * The pattern. If not specified, defaults to DEFAULT_CONVERSION_PATTERN. @@ -659,8 +644,7 @@ public Builder setAlwaysWriteExceptions(final boolean alwaysWriteExceptions) { /** * @param disableAnsi - * If {@code "true"} (default is value of system property `log4j.skipJansi`, or `true` if undefined), - * do not output ANSI escape codes + * If {@code true}, do not output ANSI escape codes. */ public Builder setDisableAnsi(final boolean disableAnsi) { this.disableAnsi = disableAnsi; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java index be655ca0fe4..d51d5e7c824 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiEscape.java @@ -420,6 +420,11 @@ public static Map createMap(final String values, final String[] * @return a new map */ public static Map createMap(final String[] values, final String[] dontEscapeKeys) { + return createMap(values, dontEscapeKeys, "\\s"); + } + + static Map createMap( + final String[] values, final String[] dontEscapeKeys, final String separatorRegex) { final String[] sortedIgnoreKeys = dontEscapeKeys != null ? dontEscapeKeys.clone() : Strings.EMPTY_ARRAY; Arrays.sort(sortedIgnoreKeys); final Map map = new HashMap<>(); @@ -429,7 +434,7 @@ public static Map createMap(final String[] values, final String[ final String key = toRootUpperCase(keyValue[0]); final String value = keyValue[1]; final boolean escape = Arrays.binarySearch(sortedIgnoreKeys, key) < 0; - map.put(key, escape ? createSequence(value.split("\\s")) : value); + map.put(key, escape ? createSequence(value.split(separatorRegex)) : value); } } return map; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiTextRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiTextRenderer.java new file mode 100644 index 00000000000..84382815b5e --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/AnsiTextRenderer.java @@ -0,0 +1,294 @@ +/* + * 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.logging.log4j.core.pattern; + +import static org.apache.logging.log4j.core.pattern.AnsiEscape.BG_RED; +import static org.apache.logging.log4j.core.pattern.AnsiEscape.BOLD; +import static org.apache.logging.log4j.core.pattern.AnsiEscape.RED; +import static org.apache.logging.log4j.core.pattern.AnsiEscape.WHITE; +import static org.apache.logging.log4j.core.pattern.AnsiEscape.YELLOW; +import static org.apache.logging.log4j.util.Strings.toRootUpperCase; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; + +/** + * Renders an input as ANSI escaped output. + *

+ * Uses the + * JLine AnsiRenderer syntax + * to render a message into an ANSI escaped string. + *

+ *

+ * The default syntax for embedded ANSI codes is: + *

+ *
+ *   @|code(,code)* text|@
+ * 
+ * + * For example, to render the message {@code "Hello"} in green, use: + * + *
+ *   @|green Hello|@
+ * 
+ * + * To render the message {@code "Hello"} in bold and red, use: + * + *
+ *   @|bold,red Warning!|@
+ * 
+ * + * You can also define custom style names in the configuration with the syntax: + * + *
+ * %message{ansi}{StyleName=value(,value)*( StyleName=value(,value)*)*}%n
+ * 
+ * + * For example: + * + *
+ * %message{ansi}{WarningStyle=red,bold KeyStyle=white ValueStyle=blue}%n
+ * 
+ * + * The call site can look like this: + * + *
+ * logger.info("@|KeyStyle {}|@ = @|ValueStyle {}|@", entry.getKey(), entry.getValue());
+ * 
+ * + *

+ * Note: this class was originally copied and then heavily modified from + * JAnsi/JLine AnsiRenderer, + * licensed under an Apache Software License, version 2.0. + *

+ */ +public final class AnsiTextRenderer implements TextRenderer { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + public static final Map DEFAULT_EXCEPTION_STYLE_MAP; + static final Map DEFAULT_MESSAGE_STYLE_MAP; + private static final Map> PREFEDINED_STYLE_MAPS; + + private static final String BEGIN_TOKEN = "@|"; + private static final String END_TOKEN = "|@"; + // The length of AnsiEscape.CSI + private static final int CSI_LENGTH = 2; + + private static Map.Entry entry(final String name, final AnsiEscape... codes) { + final StringBuilder sb = new StringBuilder(AnsiEscape.CSI.getCode()); + for (final AnsiEscape code : codes) { + sb.append(code.getCode()); + } + return Map.entry(name, sb.toString()); + } + + static { + // Default style: Spock + final Map spock = Map.ofEntries( + entry("Prefix", WHITE), + entry("Name", BG_RED, WHITE), + entry("NameMessageSeparator", BG_RED, WHITE), + entry("Message", BG_RED, WHITE, BOLD), + entry("At", WHITE), + entry("CauseLabel", WHITE), + entry("Text", WHITE), + entry("More", WHITE), + entry("Suppressed", WHITE), + // StackTraceElement + entry("StackTraceElement.ClassName", YELLOW), + entry("StackTraceElement.ClassMethodSeparator", YELLOW), + entry("StackTraceElement.MethodName", YELLOW), + entry("StackTraceElement.NativeMethod", YELLOW), + entry("StackTraceElement.FileName", RED), + entry("StackTraceElement.LineNumber", RED), + entry("StackTraceElement.Container", RED), + entry("StackTraceElement.ContainerSeparator", WHITE), + entry("StackTraceElement.UnknownSource", RED), + // ExtraClassInfo + entry("ExtraClassInfo.Inexact", YELLOW), + entry("ExtraClassInfo.Container", YELLOW), + entry("ExtraClassInfo.ContainerSeparator", YELLOW), + entry("ExtraClassInfo.Location", YELLOW), + entry("ExtraClassInfo.Version", YELLOW)); + + // Style: Kirk + final Map kirk = Map.ofEntries( + entry("Prefix", WHITE), + entry("Name", BG_RED, YELLOW, BOLD), + entry("NameMessageSeparator", BG_RED, YELLOW), + entry("Message", BG_RED, WHITE, BOLD), + entry("At", WHITE), + entry("CauseLabel", WHITE), + entry("Text", WHITE), + entry("More", WHITE), + entry("Suppressed", WHITE), + // StackTraceElement + entry("StackTraceElement.ClassName", BG_RED, WHITE), + entry("StackTraceElement.ClassMethodSeparator", BG_RED, YELLOW), + entry("StackTraceElement.MethodName", BG_RED, YELLOW), + entry("StackTraceElement.NativeMethod", BG_RED, YELLOW), + entry("StackTraceElement.FileName", RED), + entry("StackTraceElement.LineNumber", RED), + entry("StackTraceElement.Container", RED), + entry("StackTraceElement.ContainerSeparator", WHITE), + entry("StackTraceElement.UnknownSource", RED), + // ExtraClassInfo + entry("ExtraClassInfo.Inexact", YELLOW), + entry("ExtraClassInfo.Container", WHITE), + entry("ExtraClassInfo.ContainerSeparator", WHITE), + entry("ExtraClassInfo.Location", YELLOW), + entry("ExtraClassInfo.Version", YELLOW)); + + // Save + DEFAULT_EXCEPTION_STYLE_MAP = spock; + DEFAULT_MESSAGE_STYLE_MAP = Map.of(); + PREFEDINED_STYLE_MAPS = Map.of("Spock", spock, "Kirk", kirk); + } + + private final String beginToken; + private final int beginTokenLen; + private final String endToken; + private final int endTokenLen; + private final Map styleMap; + + public AnsiTextRenderer(final String[] formats, final Map defaultStyleMap) { + // The format string is a list of whitespace-separated expressions: + // Key=AnsiEscape(,AnsiEscape)* + if (formats.length > 1) { + final String stylesStr = formats[1]; + final Map map = AnsiEscape.createMap( + stylesStr.split("\\s", -1), new String[] {"BeginToken", "EndToken", "Style"}, ","); + + // Handle the special tokens + beginToken = Objects.toString(map.remove("BeginToken"), BEGIN_TOKEN); + endToken = Objects.toString(map.remove("EndToken"), END_TOKEN); + final String predefinedStyle = map.remove("Style"); + + // Create style map + final Map styleMap = new HashMap<>(map.size() + defaultStyleMap.size()); + defaultStyleMap.forEach((k, v) -> styleMap.put(toRootUpperCase(k), v)); + if (predefinedStyle != null) { + final Map predefinedMap = PREFEDINED_STYLE_MAPS.get(predefinedStyle); + if (predefinedMap != null) { + map.putAll(predefinedMap); + } else { + LOGGER.warn( + "Unknown predefined map name {}, pick one of {}", + predefinedStyle, + PREFEDINED_STYLE_MAPS.keySet()); + } + } + styleMap.putAll(map); + this.styleMap = Collections.unmodifiableMap(styleMap); + } else { + beginToken = BEGIN_TOKEN; + endToken = END_TOKEN; + this.styleMap = Collections.unmodifiableMap(defaultStyleMap); + } + beginTokenLen = beginToken.length(); + endTokenLen = endToken.length(); + } + + /** + * Renders the given input with the given names which can be ANSI code names or Log4j style names. + * + * @param input + * The input to render + * @param styleNames + * ANSI code names or Log4j style names. + */ + private void render(final String input, final StringBuilder output, final String... styleNames) { + boolean first = true; + for (final String styleName : styleNames) { + final String escape = styleMap.get(toRootUpperCase(styleName)); + if (escape != null) { + merge(escape, output, first); + } else { + merge(AnsiEscape.createSequence(styleName), output, first); + } + first = false; + } + output.append(input).append(AnsiEscape.getDefaultStyle()); + } + + private static void merge(final String escapeSequence, final StringBuilder output, final boolean first) { + if (first) { + output.append(escapeSequence); + } else { + // Delete the trailing AnsiEscape.SUFFIX + output.setLength(output.length() - 1); + output.append(AnsiEscape.SEPARATOR.getCode()); + output.append(escapeSequence.substring(CSI_LENGTH)); + } + } + + // EXACT COPY OF StringBuilder version of the method but typed as String for input + @Override + public void render(final String input, final StringBuilder output, final String styleName) + throws IllegalArgumentException { + render(input, output, styleName.split(",", -1)); + } + + @Override + public void render(final StringBuilder input, final StringBuilder output) throws IllegalArgumentException { + int pos = 0; + int beginTokenPos, endTokenPos; + + while (true) { + beginTokenPos = input.indexOf(beginToken, pos); + if (beginTokenPos == -1) { + output.append(pos == 0 ? input : input.substring(pos, input.length())); + return; + } + output.append(input.substring(pos, beginTokenPos)); + endTokenPos = input.indexOf(endToken, beginTokenPos); + + if (endTokenPos == -1) { + LOGGER.warn( + "Missing matching end token {} for token at position {}: '{}'", endToken, beginTokenPos, input); + output.append(beginTokenPos == 0 ? input : input.substring(beginTokenPos, input.length())); + return; + } + beginTokenPos += beginTokenLen; + final String spec = input.substring(beginTokenPos, endTokenPos); + + final String[] items = spec.split("\\s", 2); + if (items.length == 1) { + LOGGER.warn("Missing argument in ANSI escape specification '{}'", spec); + output.append(beginToken).append(spec).append(endToken); + } else { + render(items[1], output, items[0].split(",", -1)); + } + pos = endTokenPos + endTokenLen; + } + } + + public Map getStyleMap() { + return styleMap; + } + + @Override + public String toString() { + return "AnsiMessageRenderer [beginToken=" + beginToken + ", beginTokenLen=" + beginTokenLen + ", endToken=" + + endToken + ", endTokenLen=" + endTokenLen + ", styleMap=" + styleMap + "]"; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/JAnsiTextRenderer.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/JAnsiTextRenderer.java deleted file mode 100644 index 58d4afa46cd..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/JAnsiTextRenderer.java +++ /dev/null @@ -1,338 +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.logging.log4j.core.pattern; - -import static org.apache.logging.log4j.util.Strings.toRootUpperCase; -import static org.fusesource.jansi.AnsiRenderer.Code.BG_RED; -import static org.fusesource.jansi.AnsiRenderer.Code.BOLD; -import static org.fusesource.jansi.AnsiRenderer.Code.RED; -import static org.fusesource.jansi.AnsiRenderer.Code.WHITE; -import static org.fusesource.jansi.AnsiRenderer.Code.YELLOW; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import org.apache.logging.log4j.status.StatusLogger; -import org.fusesource.jansi.Ansi; -import org.fusesource.jansi.AnsiRenderer; -import org.fusesource.jansi.AnsiRenderer.Code; - -/** - * Renders an input as ANSI escaped output. - * - * Uses the JAnsi rendering syntax as the default to render a message into an ANSI escaped string. - * - * The default syntax for embedded ANSI codes is: - * - *
- *   @|code(,code)* text|@
- * 
- * - * For example, to render the message {@code "Hello"} in green, use: - * - *
- *   @|green Hello|@
- * 
- * - * To render the message {@code "Hello"} in bold and red, use: - * - *
- *   @|bold,red Warning!|@
- * 
- * - * You can also define custom style names in the configuration with the syntax: - * - *
- * %message{ansi}{StyleName=value(,value)*( StyleName=value(,value)*)*}%n
- * 
- * - * For example: - * - *
- * %message{ansi}{WarningStyle=red,bold KeyStyle=white ValueStyle=blue}%n
- * 
- * - * The call site can look like this: - * - *
- * logger.info("@|KeyStyle {}|@ = @|ValueStyle {}|@", entry.getKey(), entry.getValue());
- * 
- * - * Note: This class originally copied and then heavily modified code from JAnsi's AnsiRenderer (which is licensed as - * Apache 2.0.) - * - * @see AnsiRenderer - */ -public final class JAnsiTextRenderer implements TextRenderer { - - public static final Map DefaultExceptionStyleMap; - static final Map DefaultMessageStyleMap; - private static final Map> PrefedinedStyleMaps; - - private static void put(final Map map, final String name, final Code... codes) { - map.put(name, codes); - } - - static { - final Map> tempPreDefs = new HashMap<>(); - // Default style: Spock - { - // TODO Should the keys be in an enum? - final Map map = new HashMap<>(); - put(map, "Prefix", WHITE); - put(map, "Name", BG_RED, WHITE); - put(map, "NameMessageSeparator", BG_RED, WHITE); - put(map, "Message", BG_RED, WHITE, BOLD); - put(map, "At", WHITE); - put(map, "CauseLabel", WHITE); - put(map, "Text", WHITE); - put(map, "More", WHITE); - put(map, "Suppressed", WHITE); - // StackTraceElement - put(map, "StackTraceElement.ClassName", YELLOW); - put(map, "StackTraceElement.ClassMethodSeparator", YELLOW); - put(map, "StackTraceElement.MethodName", YELLOW); - put(map, "StackTraceElement.NativeMethod", YELLOW); - put(map, "StackTraceElement.FileName", RED); - put(map, "StackTraceElement.LineNumber", RED); - put(map, "StackTraceElement.Container", RED); - put(map, "StackTraceElement.ContainerSeparator", WHITE); - put(map, "StackTraceElement.UnknownSource", RED); - // ExtraClassInfo - put(map, "ExtraClassInfo.Inexact", YELLOW); - put(map, "ExtraClassInfo.Container", YELLOW); - put(map, "ExtraClassInfo.ContainerSeparator", YELLOW); - put(map, "ExtraClassInfo.Location", YELLOW); - put(map, "ExtraClassInfo.Version", YELLOW); - // Save - DefaultExceptionStyleMap = Collections.unmodifiableMap(map); - tempPreDefs.put("Spock", DefaultExceptionStyleMap); - } - // Style: Kirk - { - // TODO Should the keys be in an enum? - final Map map = new HashMap<>(); - put(map, "Prefix", WHITE); - put(map, "Name", BG_RED, YELLOW, BOLD); - put(map, "NameMessageSeparator", BG_RED, YELLOW); - put(map, "Message", BG_RED, WHITE, BOLD); - put(map, "At", WHITE); - put(map, "CauseLabel", WHITE); - put(map, "Text", WHITE); - put(map, "More", WHITE); - put(map, "Suppressed", WHITE); - // StackTraceElement - put(map, "StackTraceElement.ClassName", BG_RED, WHITE); - put(map, "StackTraceElement.ClassMethodSeparator", BG_RED, YELLOW); - put(map, "StackTraceElement.MethodName", BG_RED, YELLOW); - put(map, "StackTraceElement.NativeMethod", BG_RED, YELLOW); - put(map, "StackTraceElement.FileName", RED); - put(map, "StackTraceElement.LineNumber", RED); - put(map, "StackTraceElement.Container", RED); - put(map, "StackTraceElement.ContainerSeparator", WHITE); - put(map, "StackTraceElement.UnknownSource", RED); - // ExtraClassInfo - put(map, "ExtraClassInfo.Inexact", YELLOW); - put(map, "ExtraClassInfo.Container", WHITE); - put(map, "ExtraClassInfo.ContainerSeparator", WHITE); - put(map, "ExtraClassInfo.Location", YELLOW); - put(map, "ExtraClassInfo.Version", YELLOW); - // Save - tempPreDefs.put("Kirk", Collections.unmodifiableMap(map)); - } - { - final Map temp = new HashMap<>(); - // TODO - DefaultMessageStyleMap = Collections.unmodifiableMap(temp); - } - PrefedinedStyleMaps = Collections.unmodifiableMap(tempPreDefs); - } - - private final String beginToken; - private final int beginTokenLen; - private final String endToken; - private final int endTokenLen; - private final Map styleMap; - - public JAnsiTextRenderer(final String[] formats, final Map defaultStyleMap) { - String tempBeginToken = AnsiRenderer.BEGIN_TOKEN; - String tempEndToken = AnsiRenderer.END_TOKEN; - final Map map; - if (formats.length > 1) { - final String allStylesStr = formats[1]; - // Style def split - final String[] allStyleAssignmentsArr = allStylesStr.split(" "); - map = new HashMap<>(allStyleAssignmentsArr.length + defaultStyleMap.size()); - map.putAll(defaultStyleMap); - for (final String styleAssignmentStr : allStyleAssignmentsArr) { - final String[] styleAssignmentArr = styleAssignmentStr.split("="); - if (styleAssignmentArr.length != 2) { - StatusLogger.getLogger() - .warn( - "{} parsing style \"{}\", expected format: StyleName=Code(,Code)*", - getClass().getSimpleName(), - styleAssignmentStr); - } else { - final String styleName = styleAssignmentArr[0]; - final String codeListStr = styleAssignmentArr[1]; - final String[] codeNames = codeListStr.split(","); - if (codeNames.length == 0) { - StatusLogger.getLogger() - .warn( - "{} parsing style \"{}\", expected format: StyleName=Code(,Code)*", - getClass().getSimpleName(), - styleAssignmentStr); - } else { - switch (styleName) { - case "BeginToken": - tempBeginToken = codeNames[0]; - break; - case "EndToken": - tempEndToken = codeNames[0]; - break; - case "StyleMapName": - final String predefinedMapName = codeNames[0]; - final Map predefinedMap = PrefedinedStyleMaps.get(predefinedMapName); - if (predefinedMap != null) { - map.putAll(predefinedMap); - } else { - StatusLogger.getLogger() - .warn( - "Unknown predefined map name {}, pick one of {}", - predefinedMapName, - null); - } - break; - default: - final Code[] codes = new Code[codeNames.length]; - for (int i = 0; i < codes.length; i++) { - codes[i] = toCode(codeNames[i]); - } - map.put(styleName, codes); - } - } - } - } - } else { - map = defaultStyleMap; - } - styleMap = map; - beginToken = tempBeginToken; - endToken = tempEndToken; - beginTokenLen = tempBeginToken.length(); - endTokenLen = tempEndToken.length(); - } - - public Map getStyleMap() { - return styleMap; - } - - private void render(final Ansi ansi, final Code code) { - if (code.isColor()) { - if (code.isBackground()) { - ansi.bg(code.getColor()); - } else { - ansi.fg(code.getColor()); - } - } else if (code.isAttribute()) { - ansi.a(code.getAttribute()); - } - } - - private void render(final Ansi ansi, final Code... codes) { - for (final Code code : codes) { - render(ansi, code); - } - } - - /** - * Renders the given text with the given names which can be ANSI code names or Log4j style names. - * - * @param text - * The text to render - * @param names - * ANSI code names or Log4j style names. - * @return A rendered string containing ANSI codes. - */ - private String render(final String text, final String... names) { - final Ansi ansi = Ansi.ansi(); - for (final String name : names) { - final Code[] codes = styleMap.get(name); - if (codes != null) { - render(ansi, codes); - } else { - render(ansi, toCode(name)); - } - } - return ansi.a(text).reset().toString(); - } - - // EXACT COPY OF StringBuilder version of the method but typed as String for input - @Override - public void render(final String input, final StringBuilder output, final String styleName) - throws IllegalArgumentException { - output.append(render(input, styleName)); - } - - @Override - public void render(final StringBuilder input, final StringBuilder output) throws IllegalArgumentException { - int i = 0; - int j, k; - - while (true) { - j = input.indexOf(beginToken, i); - if (j == -1) { - if (i == 0) { - output.append(input); - return; - } - output.append(input.substring(i, input.length())); - return; - } - output.append(input.substring(i, j)); - k = input.indexOf(endToken, j); - - if (k == -1) { - output.append(input); - return; - } - j += beginTokenLen; - final String spec = input.substring(j, k); - - final String[] items = spec.split(AnsiRenderer.CODE_TEXT_SEPARATOR, 2); - if (items.length == 1) { - output.append(input); - return; - } - final String replacement = render(items[1], items[0].split(",")); - - output.append(replacement); - - i = k + endTokenLen; - } - } - - private Code toCode(final String name) { - return Code.valueOf(toRootUpperCase(name)); - } - - @Override - public String toString() { - return "JAnsiMessageRenderer [beginToken=" + beginToken + ", beginTokenLen=" + beginTokenLen + ", endToken=" - + endToken + ", endTokenLen=" + endTokenLen + ", styleMap=" + styleMap + "]"; - } -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java index 1408d4d9e6a..f323dd93064 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/MessagePatternConverter.java @@ -22,12 +22,10 @@ import java.util.List; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MultiformatMessage; import org.apache.logging.log4j.plugins.Namespace; import org.apache.logging.log4j.plugins.Plugin; -import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.MultiFormatStringBuilderFormattable; import org.apache.logging.log4j.util.PerformanceSensitive; import org.apache.logging.log4j.util.StringBuilderFormattable; @@ -54,12 +52,7 @@ private static TextRenderer loadMessageRenderer(final String[] options) { for (final String option : options) { switch (toRootUpperCase(option)) { case "ANSI": - if (Loader.isJansiAvailable()) { - return new JAnsiTextRenderer(options, JAnsiTextRenderer.DefaultMessageStyleMap); - } - StatusLogger.getLogger() - .warn("You requested ANSI message rendering but JANSI is not on the classpath."); - return null; + return new AnsiTextRenderer(options, AnsiTextRenderer.DEFAULT_MESSAGE_STYLE_MAP); case "HTML": return new HtmlTextRenderer(options); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java index 84667ce9483..2e86daf2ca3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Loader.java @@ -275,26 +275,6 @@ public static T newInstanceOf(final Class clazz) } } - /** - * Determines if a named Class can be loaded or not. - * - * @param className The class name. - * @return {@code true} if the class could be found or {@code false} otherwise. - */ - public static boolean isClassAvailable(final String className) { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(getClassLoader()); - return LoaderUtil.isClassAvailable(className); - } finally { - Thread.currentThread().setContextClassLoader(contextClassLoader); - } - } - - public static boolean isJansiAvailable() { - return isClassAvailable("org.fusesource.jansi.AnsiRenderer"); - } - /** * Loads a class by name. This method respects the {@link LoaderProperties#ignoreTccl()} Log4j property. If this * property is diff --git a/log4j-core/src/main/resources/Log4j-config.xsd b/log4j-core/src/main/resources/Log4j-config.xsd index c17d1c59e3f..3ff224097a0 100644 --- a/log4j-core/src/main/resources/Log4j-config.xsd +++ b/log4j-core/src/main/resources/Log4j-config.xsd @@ -696,7 +696,7 @@ Write directly to java.io.FileDescriptor and bypass java.lang.System.out/.err. Can give up to 10x performance boost when the - output is redirected to file or other process. Cannot be used with Jansi on Windows. Cannot be used with follow. + output is redirected to file or other process. Cannot be used with follow. @@ -704,7 +704,7 @@ Identifies whether the appender honors reassignments of System.out or System.err via System.setOut or System.setErr made after - configuration. Note that the follow attribute cannot be used with Jansi on Windows. Cannot be used with direct. + configuration. Cannot be used with direct. diff --git a/log4j-parent/pom.xml b/log4j-parent/pom.xml index fb8f3993001..1da3976381c 100644 --- a/log4j-parent/pom.xml +++ b/log4j-parent/pom.xml @@ -113,7 +113,6 @@ 2.2.2 2.7.3 2.18.0 - 2.4.0 2.0.1 3.3.4 4.0.5 @@ -352,12 +351,6 @@ ${hsqldb.version}
- - org.fusesource.jansi - jansi - ${jansi.version} - - com.google.code.java-allocation-instrumenter diff --git a/pom.xml b/pom.xml index 5b4e43691f2..2b37e957625 100644 --- a/pom.xml +++ b/pom.xml @@ -343,7 +343,6 @@ 1.3.4 1.2.21 1.11.0 - 1.18 18.3.12 3.0.0-beta2 3.0.0-alpha1 @@ -816,12 +815,6 @@ ${site-flume.version} - - org.fusesource.jansi - jansi - ${site-jansi.version} - - com.sleepycat je diff --git a/src/changelog/.3.x.x/1736_split_jansi_support.xml b/src/changelog/.3.x.x/1736_split_jansi_support.xml new file mode 100644 index 00000000000..1005cb42a05 --- /dev/null +++ b/src/changelog/.3.x.x/1736_split_jansi_support.xml @@ -0,0 +1,8 @@ + + + + Remove JAnsi library support, since Windows console supports ANSI escapes now. + diff --git a/src/changelog/.3.x.x/2916_rewrite_jansi_renderer.xml b/src/changelog/.3.x.x/2916_rewrite_jansi_renderer.xml new file mode 100644 index 00000000000..7fad82b6d5b --- /dev/null +++ b/src/changelog/.3.x.x/2916_rewrite_jansi_renderer.xml @@ -0,0 +1,8 @@ + + + + Rewrite `JAnsiTextRenderer` to work without JAnsi library. + diff --git a/src/site/antora/antora.tmpl.yml b/src/site/antora/antora.tmpl.yml index 632124c8676..b568da3457c 100644 --- a/src/site/antora/antora.tmpl.yml +++ b/src/site/antora/antora.tmpl.yml @@ -59,7 +59,6 @@ asciidoc: disruptor-version: "${site-disruptor.version}" flume-version: "${site-flume.version}" jackson-version: "${site-jackson.version}" - jansi-version: "${site-jansi.version}" je-version: "${site-je.version}" log4j-api-version: "${log4j-api.version}" log4j-core-version: "${site-log4j-core.version}" diff --git a/src/site/antora/antora.yml b/src/site/antora/antora.yml index 9fbdd43fcac..e4d86990b46 100644 --- a/src/site/antora/antora.yml +++ b/src/site/antora/antora.yml @@ -59,7 +59,6 @@ asciidoc: disruptor-version: "1.2.3-disruptor" flume-version: "1.2.3-flume" jackson-version: "1.2.3-jackson" - jansi-version: "1.2.3-jansi" je-version: "1.2.3-je" log4j-api-version: "1.2.3-api" log4j-core-version: "1.2.3-core" diff --git a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc index a25db96530b..aee25f66224 100644 --- a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc @@ -214,7 +214,7 @@ They are documented in separate pages based on their target resource: === Console Appender As one might expect, the Console Appender writes its output to either the standard output or standard error output. -The appender supports four different ways to access the output streams: +The appender supports three different ways to access the output streams: `direct`:: This mode gives the best performance. @@ -234,39 +234,6 @@ This setting might be useful in multi-application environments. Some application servers modify `System.out` and `System.err` to always point to the currently running application. ==== -`JANSI`:: -If the application is running on Windows and the -https://fusesource.github.io/jansi/[JANSI library] -is available, the Console appender will use JANSI to emulate ANSI sequence support. -This mode can be enabled by setting the -xref:manual/systemproperties.adoc#log4j.console.jansiEnabled[`log4j.console.jansiEnabled`] -configuration attribute to `true`. -+ -Additional runtime dependencies are required to use JANSI: -+ -[tabs] -==== -Maven:: -+ -[source,xml,subs="+attributes"] ----- - - org.fusesource.jansi - jansi - {jansi-version} - - ----- - -Gradle:: -+ -[source,groovy,subs="+attributes"] ----- -runtimeOnly 'org.fusesource.jansi:jansi:{jansi-version}' ----- - -==== - [#ConsoleAppender-attributes] .Console Appender configuration attributes [cols="1m,1,1,5"] @@ -311,9 +278,7 @@ If other logging backends or the application itself uses `System.out/System.err` ==== This setting is incompatible with the -<> -and -xref:manual/systemproperties.adoc#log4j.console.jansiEnabled[JANSI support]. +<>. | [[ConsoleAppender-attr-follow]] follow @@ -328,9 +293,7 @@ https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#setOut-java.io.P Otherwise, the value of `System.out` (resp. `System.err`) at configuration time will be used. This setting is incompatible with the -<> -and -xref:manual/systemproperties.adoc#log4j.console.jansiEnabled[JANSI support]. +<>. | [[ConsoleAppender-attr-ignoreExceptions]] ignoreExceptions diff --git a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc index a65b931604f..57c29d892f8 100644 --- a/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/pattern-layout.adoc @@ -209,7 +209,7 @@ The optional footer to include at the bottom of each log file |Default value |`false` |=== -If `true`, do not output ANSI escape codes +If `true`, do not output ANSI escape codes. [#plugin-attr-noConsoleNoAnsi] ==== `noConsoleNoAnsi` @@ -220,7 +220,7 @@ If `true`, do not output ANSI escape codes |Default value |`false` |=== -If `true` and `System.console()` is null, do not output ANSI escape codes +If `true` and `System.console()` is `null`, do not output ANSI escape codes [#plugin-elements] === Plugin elements @@ -739,7 +739,7 @@ fqcn ==== Highlight Adds ANSI colors to the result of the enclosed pattern based on the current event's {log4j2-url}/manual/customloglevels.html[logging level]. -Windows users should refer to <>. +Windows users should refer to <>. .link:../javadoc/log4j-core/org/apache/logging/log4j/core/pattern/HighlightConverter.html[`HighlightConverter`] specifier grammar [source,text] @@ -1041,7 +1041,7 @@ message{lookups}{ansi} ---- Add `\{ansi}` to render messages with ANSI escape codes. -Windows users should refer to <>. +Windows users should refer to <>. The default syntax for embedded ANSI codes is: @@ -1235,7 +1235,7 @@ The counter is a static variable, so will only be unique within applications tha Use ANSI escape sequences to style the result of the enclosed pattern. The syntax of the `style_expression` parameter is described in <>. -Windows users should also refer to <>. +Windows users should also refer to <>. .link:../javadoc/log4j-core/org/apache/logging/log4j/core/pattern/StyleConverter.html[`StyleConverter`] specifier grammar [source,text] @@ -1585,22 +1585,17 @@ If your terminal supports 24-bit colors, you can specify: * the text color using the `#rrggbb` syntax, e.g. `#dc143c` will color your text crimson, * the background color using the `bg_#rrggbb` syntax, e.g. `bg_#87ceeb` will use a sky blue background. -[#jansi] +[#ansi-windows] ==== ANSI styling on Windows -ANSI escape sequences are supported natively on many platforms, but not by default on Windows. -To enable ANSI support add the -http://fusesource.github.io/jansi/[Jansi] -dependency to your application, and set xref:manual/systemproperties.adoc#log4j.console.jansiEnabled[the `log4j.console.jansiEnabled` system property] to `true`. -This allows Log4j to use Jansi to add ANSI escape codes when writing to the console. +ANSI escape sequences are supported natively on many platforms, but is disabled by default in `cmd.exe` on Windows. +To enable ANSI escape sequences, create a registry key of name `HKEY_CURRENT_USER\Console\VirtualTerminalLevel` of type `DWORD` and set its value to `0x1`. -[NOTE] -==== -Before Log4j 2.10, Jansi was enabled by default. -The fact that Jansi requires native code means that Jansi can only be loaded by a single class loader. -For web applications, this means the Jansi jar has to be in the web container's classpath. -To avoid causing problems for web applications, Log4j no longer automatically tries to load Jansi without explicit configuration from Log4j 2.10 onward. -==== +See +https://devblogs.microsoft.com/commandline/understanding-windows-console-host-settings/[Understanding Windows Console Host Settings] +and +https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences[Console Virtual Terminal Sequences] +Microsoft documentation for more details. [#garbage-free] === Garbage-free configuration diff --git a/src/site/antora/modules/ROOT/pages/manual/systemproperties.adoc b/src/site/antora/modules/ROOT/pages/manual/systemproperties.adoc index 941748710c3..ebbe0f2174d 100644 --- a/src/site/antora/modules/ROOT/pages/manual/systemproperties.adoc +++ b/src/site/antora/modules/ROOT/pages/manual/systemproperties.adoc @@ -170,13 +170,6 @@ include::partial$manual/systemproperties/properties-log-event.adoc[leveloffset=+ include::partial$manual/systemproperties/properties-garbage-collection.adoc[leveloffset=+2] -[id=properties-jansi] -=== JANSI - -If the https://fusesource.github.io/jansi/[JANSI] library is on the runtime classpath of the application, the following property can be used to control its usage: - -include::partial$manual/systemproperties/properties-jansi.adoc[leveloffset=+2] - [id=properties-log4j-core-thread-context] === Thread context diff --git a/src/site/antora/modules/ROOT/partials/manual/systemproperties/properties-jansi.adoc b/src/site/antora/modules/ROOT/partials/manual/systemproperties/properties-jansi.adoc deleted file mode 100644 index 0aefd398320..00000000000 --- a/src/site/antora/modules/ROOT/partials/manual/systemproperties/properties-jansi.adoc +++ /dev/null @@ -1,32 +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. -//// -[id=log4j.console.jansiEnabled] -== `log4j.console.jansiEnabled` - -[cols="1h,5"] -|=== -| Env. variable | `LOG4J_CONSOLE_JANSI_ENABLED` -| Type | `boolean` -| Default value | `false` -|=== - -If the following conditions are satisfied: - -* Log4j runs on Windows, -* this property is set to `true`, - -Log4j will use the JANSI library to color the output of the console appender. \ No newline at end of file