From ba658a0fa6c18952e2ae110eee286182b3605d7b Mon Sep 17 00:00:00 2001 From: rpopma Date: Sun, 28 Jan 2018 23:50:13 +0900 Subject: [PATCH 0001/2347] LOG4J2-2225 move time-related classes from core.util to core.time.internal package --- .../cassandra/ClockTimestampGenerator.java | 2 +- .../rolling/action/IfLastModified.java | 2 +- .../logging/log4j/core/async/AsyncLogger.java | 2 +- .../core/config/AbstractConfiguration.java | 2 +- .../logging/log4j/core/filter/TimeFilter.java | 2 +- .../log4j/core/impl/Log4jLogEvent.java | 2 + .../core/impl/ReusableLogEventFactory.java | 2 +- .../log4j/core/pattern/PatternParser.java | 2 +- .../{util => time/internal}/CachedClock.java | 5 +- .../{util => time/internal}/ClockFactory.java | 8 +- .../internal}/CoarseCachedClock.java | 5 +- .../internal}/DummyNanoClock.java | 4 +- .../{util => time/internal}/SystemClock.java | 4 +- .../internal}/SystemMillisClock.java | 4 +- .../internal}/SystemNanoClock.java | 68 ++++++++-------- .../log4j/core/TimestampMessageTest.java | 4 +- .../JsonCompleteFileAppenderTest.java | 5 +- .../log4j/core/async/AsyncLoggerTest.java | 2 +- .../core/async/AsyncLoggerTestNanoTime.java | 4 +- .../AsyncLoggerTimestampMessageTest.java | 4 +- .../core/async/RingBufferLogEventTest.java | 2 +- .../log4j/core/filter/TimeFilterTest.java | 4 +- .../core/impl/Log4jLogEventNanoTimeTest.java | 4 +- .../log4j/core/impl/Log4jLogEventTest.java | 6 +- .../log4j/core/pattern/PatternParserTest.java | 4 +- .../internal}/ClockFactoryTest.java | 7 +- .../internal}/DummyNanoClockTest.java | 79 +++++++++--------- .../internal}/SystemClockTest.java | 3 +- .../internal}/SystemNanoClockTest.java | 80 ++++++++++--------- .../log4j/perf/jmh/ClocksBenchmark.java | 6 +- 30 files changed, 176 insertions(+), 152 deletions(-) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util => time/internal}/CachedClock.java (95%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util => time/internal}/ClockFactory.java (90%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util => time/internal}/CoarseCachedClock.java (94%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util => time/internal}/DummyNanoClock.java (93%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util => time/internal}/SystemClock.java (91%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util => time/internal}/SystemMillisClock.java (92%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util => time/internal}/SystemNanoClock.java (91%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util => time/internal}/ClockFactoryTest.java (90%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util => time/internal}/DummyNanoClockTest.java (90%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util => time/internal}/SystemClockTest.java (92%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util => time/internal}/SystemNanoClockTest.java (88%) diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java index 1c7328ba793..50d7bc4ae85 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java @@ -18,7 +18,7 @@ import com.datastax.driver.core.TimestampGenerator; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactory; /** * A {@link TimestampGenerator} implementation using the configured {@link Clock}. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java index 4a4c7179e21..66902d7d501 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactory; import org.apache.logging.log4j.status.StatusLogger; /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java index 358422c20ae..fd7c6f6acb8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactory; import org.apache.logging.log4j.core.util.NanoClock; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java index 3c0e81089f9..98f072ab645 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java @@ -62,7 +62,7 @@ import org.apache.logging.log4j.core.script.ScriptManager; import org.apache.logging.log4j.core.script.ScriptRef; import org.apache.logging.log4j.core.util.Constants; -import org.apache.logging.log4j.core.util.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.core.util.NameUtil; import org.apache.logging.log4j.core.util.NanoClock; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java index 3d01e358bc4..8cab11fc9ec 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.PerformanceSensitive; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java index 2fe5a9be91c..48076d838f8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java @@ -29,6 +29,8 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.ContextDataInjector; +import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.util.*; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java index 0ecefedb62a..44a2572952e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java @@ -26,7 +26,7 @@ import org.apache.logging.log4j.core.async.ThreadNameCachingStrategy; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.StringMap; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java index 91c11ecb498..ac6940a3128 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java @@ -29,7 +29,7 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.util.PluginManager; import org.apache.logging.log4j.core.config.plugins.util.PluginType; -import org.apache.logging.log4j.core.util.SystemNanoClock; +import org.apache.logging.log4j.core.time.internal.SystemNanoClock; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Strings; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CachedClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CachedClock.java similarity index 95% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/CachedClock.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CachedClock.java index f6d51ab0857..9ff7ebdba64 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CachedClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CachedClock.java @@ -14,7 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; + +import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.util.Log4jThread; import java.util.concurrent.locks.LockSupport; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/ClockFactory.java similarity index 90% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/ClockFactory.java index 8b965b6873a..415e903cbfd 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/ClockFactory.java @@ -14,9 +14,11 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; import org.apache.logging.log4j.core.time.PreciseClock; +import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Supplier; @@ -73,8 +75,8 @@ private static Map> aliases() { result.put("SystemMillisClock", new Supplier() { @Override public Clock get() { return new SystemMillisClock(); } }); result.put("CachedClock", new Supplier() { @Override public Clock get() { return CachedClock.instance(); } }); result.put("CoarseCachedClock", new Supplier() { @Override public Clock get() { return CoarseCachedClock.instance(); } }); - result.put("org.apache.logging.log4j.core.util.CachedClock", new Supplier() { @Override public Clock get() { return CachedClock.instance(); } }); - result.put("org.apache.logging.log4j.core.util.CoarseCachedClock", new Supplier() { @Override public Clock get() { return CoarseCachedClock.instance(); } }); + result.put("org.apache.logging.log4j.core.time.internal.CachedClock", new Supplier() { @Override public Clock get() { return CachedClock.instance(); } }); + result.put("org.apache.logging.log4j.core.time.internal.CoarseCachedClock", new Supplier() { @Override public Clock get() { return CoarseCachedClock.instance(); } }); return result; } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CoarseCachedClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CoarseCachedClock.java similarity index 94% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/CoarseCachedClock.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CoarseCachedClock.java index 144f4709232..bbbc1bd1f2f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CoarseCachedClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CoarseCachedClock.java @@ -14,7 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; + +import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.util.Log4jThread; import java.util.concurrent.locks.LockSupport; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/DummyNanoClock.java similarity index 93% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyNanoClock.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/DummyNanoClock.java index e3d6c2b39e5..f89f6d8d228 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DummyNanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/DummyNanoClock.java @@ -14,7 +14,9 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; + +import org.apache.logging.log4j.core.util.NanoClock; /** * Implementation of the {@code NanoClock} interface that always returns a fixed value. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java similarity index 91% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java index 6dab5575972..0626149d0cf 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java @@ -14,7 +14,9 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; + +import org.apache.logging.log4j.core.util.Clock; /** * Implementation of the {@code Clock} interface that returns the system time. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java similarity index 92% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java index f267320834a..49b7ffccabd 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemMillisClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java @@ -14,7 +14,9 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; + +import org.apache.logging.log4j.core.util.Clock; /** * Implementation of the {@code Clock} interface that returns the system time in millisecond granularity. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemNanoClock.java similarity index 91% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemNanoClock.java index 9310e6cc2c7..1cd1a6ffb2e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemNanoClock.java @@ -1,33 +1,35 @@ -/* - * 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.util; - -/** - * Implementation of the {@code NanoClock} interface that returns the system nano time. - */ -public final class SystemNanoClock implements NanoClock { - - /** - * Returns the system high-resolution time. - * @return the result of calling {@code System.nanoTime()} - */ - @Override - public long nanoTime() { - return System.nanoTime(); - } - -} +/* + * 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.time.internal; + +import org.apache.logging.log4j.core.util.NanoClock; + +/** + * Implementation of the {@code NanoClock} interface that returns the system nano time. + */ +public final class SystemNanoClock implements NanoClock { + + /** + * Returns the system high-resolution time. + * @return the result of calling {@code System.nanoTime()} + */ + @Override + public long nanoTime() { + return System.nanoTime(); + } + +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java index 60d643b2a31..a2c02fbc8f2 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java @@ -20,8 +20,8 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; -import org.apache.logging.log4j.core.util.ClockFactoryTest; +import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.message.Message; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java index 323ca13a83d..fcbd40c7c4f 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java @@ -16,20 +16,17 @@ */ package org.apache.logging.log4j.core.appender; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.categories.Layouts; -import org.apache.logging.log4j.core.filter.TimeFilterTest; import org.apache.logging.log4j.core.impl.Log4jLogEventTest; import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.selector.CoreContextSelectors; -import org.apache.logging.log4j.core.util.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactory; import org.apache.logging.log4j.junit.CleanFiles; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.AfterClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java index aad8ce75bd2..afea7037566 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTest.java @@ -25,7 +25,7 @@ import org.apache.logging.log4j.core.CoreLoggerContexts; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Constants; -import org.apache.logging.log4j.core.util.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.util.Strings; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java index d9e15d0e82d..628e68598af 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java @@ -26,8 +26,8 @@ import org.apache.logging.log4j.core.CoreLoggerContexts; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Constants; -import org.apache.logging.log4j.core.util.DummyNanoClock; -import org.apache.logging.log4j.core.util.SystemNanoClock; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.SystemNanoClock; import org.apache.logging.log4j.util.Strings; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java index f797daf5978..4c9a00f48cc 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java @@ -26,8 +26,8 @@ import org.apache.logging.log4j.core.CoreLoggerContexts; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; -import org.apache.logging.log4j.core.util.ClockFactoryTest; +import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java index e3920f7df2a..cc50b425ca2 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.categories.AsyncLoggers; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.util.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.time.internal.FixedPreciseClock; import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.StringMap; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java index 4ac0b40e48f..9b026acbb2b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java @@ -24,8 +24,8 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; -import org.apache.logging.log4j.core.util.ClockFactoryTest; +import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java index 93d60c4e99b..5355774739b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java @@ -26,8 +26,8 @@ import org.apache.logging.log4j.core.CoreLoggerContexts; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Constants; -import org.apache.logging.log4j.core.util.DummyNanoClock; -import org.apache.logging.log4j.core.util.SystemNanoClock; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.SystemNanoClock; import org.apache.logging.log4j.util.Strings; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java index 9a8fa7caad8..eab49491e4f 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java @@ -39,9 +39,9 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.convert.Base64Converter; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.ClockFactory; -import org.apache.logging.log4j.core.util.ClockFactoryTest; -import org.apache.logging.log4j.core.util.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ObjectMessage; import org.apache.logging.log4j.message.ReusableMessage; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java index 1c150919a8b..5b61b69fc95 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java @@ -33,8 +33,8 @@ import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; -import org.apache.logging.log4j.core.util.DummyNanoClock; -import org.apache.logging.log4j.core.util.SystemNanoClock; +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; +import org.apache.logging.log4j.core.time.internal.SystemNanoClock; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ClockFactoryTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/ClockFactoryTest.java similarity index 90% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/ClockFactoryTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/ClockFactoryTest.java index 309cc77a2b4..2db66f21629 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ClockFactoryTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/ClockFactoryTest.java @@ -14,13 +14,18 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; import java.lang.reflect.Field; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.logging.log4j.core.async.AsyncLogger; import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.time.internal.CachedClock; +import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.internal.CoarseCachedClock; +import org.apache.logging.log4j.core.time.internal.SystemClock; +import org.apache.logging.log4j.core.util.Clock; import org.junit.Before; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/DummyNanoClockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/DummyNanoClockTest.java similarity index 90% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/DummyNanoClockTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/DummyNanoClockTest.java index 8fc16b6ac60..04f8956da70 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/DummyNanoClockTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/DummyNanoClockTest.java @@ -1,39 +1,40 @@ -/* - * 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.util; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Tests the DummyNanoClock. - */ -public class DummyNanoClockTest { - - @Test - public void testReturnsZeroByDefault() { - assertEquals(0, new DummyNanoClock().nanoTime()); - } - - @Test - public void testReturnsConstructorValue() { - assertEquals(123, new DummyNanoClock(123).nanoTime()); - } - -} +/* + * 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.time.internal; + +import org.apache.logging.log4j.core.time.internal.DummyNanoClock; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Tests the DummyNanoClock. + */ +public class DummyNanoClockTest { + + @Test + public void testReturnsZeroByDefault() { + assertEquals(0, new DummyNanoClock().nanoTime()); + } + + @Test + public void testReturnsConstructorValue() { + assertEquals(123, new DummyNanoClock(123).nanoTime()); + } + +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemClockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemClockTest.java similarity index 92% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemClockTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemClockTest.java index 5421a7df634..dd4b5c111be 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemClockTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemClockTest.java @@ -14,8 +14,9 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util; +package org.apache.logging.log4j.core.time.internal; +import org.apache.logging.log4j.core.time.internal.SystemClock; import org.junit.Test; import static org.junit.Assert.*; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemNanoClockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemNanoClockTest.java similarity index 88% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemNanoClockTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemNanoClockTest.java index 9adea85a4f5..7b729522015 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/SystemNanoClockTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemNanoClockTest.java @@ -1,39 +1,41 @@ -/* - * 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.util; - -import java.util.concurrent.TimeUnit; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Tests the SystemNanoClock. - */ -public class SystemNanoClockTest { - - @Test - public void testReturnsSystemNanoTime() { - final NanoClock clock = new SystemNanoClock(); - final long expected = System.nanoTime(); - final long actual = clock.nanoTime(); - assertTrue("smal difference", actual - expected < TimeUnit.SECONDS.toNanos(1)); - } - -} +/* + * 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.time.internal; + +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.core.time.internal.SystemNanoClock; +import org.apache.logging.log4j.core.util.NanoClock; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Tests the SystemNanoClock. + */ +public class SystemNanoClockTest { + + @Test + public void testReturnsSystemNanoTime() { + final NanoClock clock = new SystemNanoClock(); + final long expected = System.nanoTime(); + final long actual = clock.nanoTime(); + assertTrue("smal difference", actual - expected < TimeUnit.SECONDS.toNanos(1)); + } + +} diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java index 3eb207fbb73..5872c5afaa7 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java @@ -20,10 +20,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; -import org.apache.logging.log4j.core.util.CachedClock; +import org.apache.logging.log4j.core.time.internal.CachedClock; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.CoarseCachedClock; -import org.apache.logging.log4j.core.util.SystemClock; +import org.apache.logging.log4j.core.time.internal.CoarseCachedClock; +import org.apache.logging.log4j.core.time.internal.SystemClock; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Level; From 91f927f8c5b697ff207ca2b4915f33354e25bb67 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 08:44:08 -0700 Subject: [PATCH 0002/2347] Add missing serialVersionUID. --- .../java/org/apache/logging/log4j/core/time/MutableInstant.java | 1 + 1 file changed, 1 insertion(+) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java index 2e49a961bd6..4ec26ad1c70 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java @@ -34,6 +34,7 @@ @PerformanceSensitive("allocation") public class MutableInstant implements Instant, Serializable { + private static final long serialVersionUID = 1L; private static final int MILLIS_PER_SECOND = 1000; private static final int NANOS_PER_MILLI = 1000_000; private static final int NANOS_PER_SECOND = MILLIS_PER_SECOND * NANOS_PER_MILLI; From 0295bcb4776c0885f26aab6ae39c5cff498be5a2 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 08:45:14 -0700 Subject: [PATCH 0003/2347] In-line mutable local vars. --- .../org/apache/logging/log4j/core/time/MutableInstant.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java index 4ec26ad1c70..09b0d39d383 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java @@ -55,15 +55,14 @@ public int getNanoOfSecond() { @Override public long getEpochMillisecond() { final int millis = nanoOfSecond / NANOS_PER_MILLI; - long epochMillisecond = epochSecond * MILLIS_PER_SECOND + millis; - return epochMillisecond; + return epochSecond * MILLIS_PER_SECOND + millis; } @Override public int getNanoOfMillisecond() { final int millis = nanoOfSecond / NANOS_PER_MILLI; - int nanoOfMillisecond = nanoOfSecond - (millis * NANOS_PER_MILLI); // cheaper than nanoOfSecond % NANOS_PER_MILLI - return nanoOfMillisecond; + // cheaper than nanoOfSecond % NANOS_PER_MILLI + return nanoOfSecond - (millis * NANOS_PER_MILLI); } public void initFrom(final Instant other) { From 2f3724591c8cdb59cb8b2e10289b3365585afee8 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 08:57:15 -0700 Subject: [PATCH 0004/2347] [LOG4J2-2228] Split off ZeroMq/JeroMq support into a new module log4j-jeromq. --- log4j-core/pom.xml | 6 - .../appender/mom/jeromq/package-info.java | 23 - log4j-jeromq/pom.xml | 165 +++++++ .../appender/mom/jeromq/JeroMqAppender.java | 0 .../appender/mom/jeromq/JeroMqManager.java | 444 +++++++++--------- log4j-jeromq/src/site/manual/index.md | 33 ++ log4j-jeromq/src/site/site.xml | 52 ++ .../mom/jeromq/JeroMqAppenderTest.java | 0 .../appender/mom/jeromq/JeroMqTestClient.java | 108 ++--- .../appender/db/jpa/log4j2-h2-jpa-base.xml | 38 ++ .../appender/db/jpa/log4j2-h2-jpa-basic.xml | 38 ++ .../db/jpa/log4j2-hsqldb-jpa-base.xml | 38 ++ .../db/jpa/log4j2-hsqldb-jpa-basic.xml | 38 ++ pom.xml | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/appenders.xml | 3 + 16 files changed, 685 insertions(+), 305 deletions(-) delete mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java create mode 100644 log4j-jeromq/pom.xml rename {log4j-core => log4j-jeromq}/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java (100%) rename {log4j-core => log4j-jeromq}/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java (97%) create mode 100644 log4j-jeromq/src/site/manual/index.md create mode 100644 log4j-jeromq/src/site/site.xml rename {log4j-core => log4j-jeromq}/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java (100%) rename {log4j-core => log4j-jeromq}/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java (97%) create mode 100644 log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml create mode 100644 log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml create mode 100644 log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml create mode 100644 log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 4ae808ac28b..ef854c1d378 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -126,12 +126,6 @@ kafka-clients true - - - org.zeromq - jeromq - true - org.apache.commons diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java deleted file mode 100644 index b1df1e7724d..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/package-info.java +++ /dev/null @@ -1,23 +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. - */ - -/** - * Classes and interfaces for ZeroMQ/JeroMQ support. - * - * @since 2.4 - */ -package org.apache.logging.log4j.core.appender.mom.jeromq; diff --git a/log4j-jeromq/pom.xml b/log4j-jeromq/pom.xml new file mode 100644 index 00000000000..77f47758bfd --- /dev/null +++ b/log4j-jeromq/pom.xml @@ -0,0 +1,165 @@ + + + + + + org.apache.logging.log4j + log4j + 2.10.1-SNAPSHOT + + 4.0.0 + + log4j-jeromq + Apache Log4j JeroMQ + + Apache Log4j ZeroMQ using JeroMQ. + + + ${basedir}/.. + Log4j ZeroMQ using JeroMQ Documentation + /log4j-jpa + org.apache.logging.log4j.jeromq + + + + + org.apache.logging.log4j + log4j-core + + + + org.zeromq + jeromq + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.core.appender.mom.jeromq + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]>
+ + false + true +
+ + + non-aggregate + + javadoc + + + +
+ + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + +
+
+
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java rename to log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java rename to log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java index a438faf0752..0326ebe8ca2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java +++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java @@ -1,222 +1,222 @@ -/* - * 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.mom.jeromq; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.appender.AbstractManager; -import org.apache.logging.log4j.core.appender.ManagerFactory; -import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.zeromq.ZMQ; - -/** - * Manager for publishing messages via JeroMq. - * - * @since 2.6 - */ -public class JeroMqManager extends AbstractManager { - - /** - * System property to enable shutdown hook. - */ - public static final String SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK = "log4j.jeromq.enableShutdownHook"; - - /** - * System property to control JeroMQ I/O thread count. - */ - public static final String SYS_PROPERTY_IO_THREADS = "log4j.jeromq.ioThreads"; - - private static final JeroMqManagerFactory FACTORY = new JeroMqManagerFactory(); - private static final ZMQ.Context CONTEXT; - - static { - LOGGER.trace("JeroMqManager using ZMQ version {}", ZMQ.getVersionString()); - - final int ioThreads = PropertiesUtil.getProperties().getIntegerProperty(SYS_PROPERTY_IO_THREADS, 1); - LOGGER.trace("JeroMqManager creating ZMQ context with ioThreads = {}", ioThreads); - CONTEXT = ZMQ.context(ioThreads); - - final boolean enableShutdownHook = PropertiesUtil.getProperties().getBooleanProperty( - SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK, true); - if (enableShutdownHook) { - ((ShutdownCallbackRegistry) LogManager.getFactory()).addShutdownCallback(new Runnable() { - @Override - public void run() { - CONTEXT.close(); - } - }); - } - } - - private final ZMQ.Socket publisher; - - private JeroMqManager(final String name, final JeroMqConfiguration config) { - super(null, name); - publisher = CONTEXT.socket(ZMQ.PUB); - publisher.setAffinity(config.affinity); - publisher.setBacklog(config.backlog); - publisher.setDelayAttachOnConnect(config.delayAttachOnConnect); - if (config.identity != null) { - publisher.setIdentity(config.identity); - } - publisher.setIPv4Only(config.ipv4Only); - publisher.setLinger(config.linger); - publisher.setMaxMsgSize(config.maxMsgSize); - publisher.setRcvHWM(config.rcvHwm); - publisher.setReceiveBufferSize(config.receiveBufferSize); - publisher.setReceiveTimeOut(config.receiveTimeOut); - publisher.setReconnectIVL(config.reconnectIVL); - publisher.setReconnectIVLMax(config.reconnectIVLMax); - publisher.setSendBufferSize(config.sendBufferSize); - publisher.setSendTimeOut(config.sendTimeOut); - publisher.setSndHWM(config.sndHwm); - publisher.setTCPKeepAlive(config.tcpKeepAlive); - publisher.setTCPKeepAliveCount(config.tcpKeepAliveCount); - publisher.setTCPKeepAliveIdle(config.tcpKeepAliveIdle); - publisher.setTCPKeepAliveInterval(config.tcpKeepAliveInterval); - publisher.setXpubVerbose(config.xpubVerbose); - for (final String endpoint : config.endpoints) { - publisher.bind(endpoint); - } - LOGGER.debug("Created JeroMqManager with {}", config); - } - - public boolean send(final byte[] data) { - return publisher.send(data); - } - - @Override - protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) { - publisher.close(); - return true; - } - - public static JeroMqManager getJeroMqManager(final String name, final long affinity, final long backlog, - final boolean delayAttachOnConnect, final byte[] identity, - final boolean ipv4Only, final long linger, final long maxMsgSize, - final long rcvHwm, final long receiveBufferSize, - final int receiveTimeOut, final long reconnectIVL, - final long reconnectIVLMax, final long sendBufferSize, - final int sendTimeOut, final long sndHwm, final int tcpKeepAlive, - final long tcpKeepAliveCount, final long tcpKeepAliveIdle, - final long tcpKeepAliveInterval, final boolean xpubVerbose, - final List endpoints) { - return getManager(name, FACTORY, - new JeroMqConfiguration(affinity, backlog, delayAttachOnConnect, identity, ipv4Only, linger, maxMsgSize, - rcvHwm, receiveBufferSize, receiveTimeOut, reconnectIVL, reconnectIVLMax, sendBufferSize, sendTimeOut, - sndHwm, tcpKeepAlive, tcpKeepAliveCount, tcpKeepAliveIdle, tcpKeepAliveInterval, xpubVerbose, - endpoints)); - } - - public static ZMQ.Context getContext() { - return CONTEXT; - } - - private static class JeroMqConfiguration { - private final long affinity; - private final long backlog; - private final boolean delayAttachOnConnect; - private final byte[] identity; - private final boolean ipv4Only; - private final long linger; - private final long maxMsgSize; - private final long rcvHwm; - private final long receiveBufferSize; - private final int receiveTimeOut; - private final long reconnectIVL; - private final long reconnectIVLMax; - private final long sendBufferSize; - private final int sendTimeOut; - private final long sndHwm; - private final int tcpKeepAlive; - private final long tcpKeepAliveCount; - private final long tcpKeepAliveIdle; - private final long tcpKeepAliveInterval; - private final boolean xpubVerbose; - private final List endpoints; - - private JeroMqConfiguration(final long affinity, final long backlog, final boolean delayAttachOnConnect, - final byte[] identity, final boolean ipv4Only, final long linger, - final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, - final int receiveTimeOut, final long reconnectIVL, final long reconnectIVLMax, - final long sendBufferSize, final int sendTimeOut, final long sndHwm, - final int tcpKeepAlive, final long tcpKeepAliveCount, final long tcpKeepAliveIdle, - final long tcpKeepAliveInterval, final boolean xpubVerbose, - final List endpoints) { - this.affinity = affinity; - this.backlog = backlog; - this.delayAttachOnConnect = delayAttachOnConnect; - this.identity = identity; - this.ipv4Only = ipv4Only; - this.linger = linger; - this.maxMsgSize = maxMsgSize; - this.rcvHwm = rcvHwm; - this.receiveBufferSize = receiveBufferSize; - this.receiveTimeOut = receiveTimeOut; - this.reconnectIVL = reconnectIVL; - this.reconnectIVLMax = reconnectIVLMax; - this.sendBufferSize = sendBufferSize; - this.sendTimeOut = sendTimeOut; - this.sndHwm = sndHwm; - this.tcpKeepAlive = tcpKeepAlive; - this.tcpKeepAliveCount = tcpKeepAliveCount; - this.tcpKeepAliveIdle = tcpKeepAliveIdle; - this.tcpKeepAliveInterval = tcpKeepAliveInterval; - this.xpubVerbose = xpubVerbose; - this.endpoints = endpoints; - } - - @Override - public String toString() { - return "JeroMqConfiguration{" + - "affinity=" + affinity + - ", backlog=" + backlog + - ", delayAttachOnConnect=" + delayAttachOnConnect + - ", identity=" + Arrays.toString(identity) + - ", ipv4Only=" + ipv4Only + - ", linger=" + linger + - ", maxMsgSize=" + maxMsgSize + - ", rcvHwm=" + rcvHwm + - ", receiveBufferSize=" + receiveBufferSize + - ", receiveTimeOut=" + receiveTimeOut + - ", reconnectIVL=" + reconnectIVL + - ", reconnectIVLMax=" + reconnectIVLMax + - ", sendBufferSize=" + sendBufferSize + - ", sendTimeOut=" + sendTimeOut + - ", sndHwm=" + sndHwm + - ", tcpKeepAlive=" + tcpKeepAlive + - ", tcpKeepAliveCount=" + tcpKeepAliveCount + - ", tcpKeepAliveIdle=" + tcpKeepAliveIdle + - ", tcpKeepAliveInterval=" + tcpKeepAliveInterval + - ", xpubVerbose=" + xpubVerbose + - ", endpoints=" + endpoints + - '}'; - } - } - - private static class JeroMqManagerFactory implements ManagerFactory { - @Override - public JeroMqManager createManager(final String name, final JeroMqConfiguration data) { - return new JeroMqManager(name, data); - } - } -} +/* + * 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.mom.jeromq; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.appender.AbstractManager; +import org.apache.logging.log4j.core.appender.ManagerFactory; +import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry; +import org.apache.logging.log4j.util.PropertiesUtil; +import org.zeromq.ZMQ; + +/** + * Manager for publishing messages via JeroMq. + * + * @since 2.6 + */ +public class JeroMqManager extends AbstractManager { + + /** + * System property to enable shutdown hook. + */ + public static final String SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK = "log4j.jeromq.enableShutdownHook"; + + /** + * System property to control JeroMQ I/O thread count. + */ + public static final String SYS_PROPERTY_IO_THREADS = "log4j.jeromq.ioThreads"; + + private static final JeroMqManagerFactory FACTORY = new JeroMqManagerFactory(); + private static final ZMQ.Context CONTEXT; + + static { + LOGGER.trace("JeroMqManager using ZMQ version {}", ZMQ.getVersionString()); + + final int ioThreads = PropertiesUtil.getProperties().getIntegerProperty(SYS_PROPERTY_IO_THREADS, 1); + LOGGER.trace("JeroMqManager creating ZMQ context with ioThreads = {}", ioThreads); + CONTEXT = ZMQ.context(ioThreads); + + final boolean enableShutdownHook = PropertiesUtil.getProperties().getBooleanProperty( + SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK, true); + if (enableShutdownHook) { + ((ShutdownCallbackRegistry) LogManager.getFactory()).addShutdownCallback(new Runnable() { + @Override + public void run() { + CONTEXT.close(); + } + }); + } + } + + private final ZMQ.Socket publisher; + + private JeroMqManager(final String name, final JeroMqConfiguration config) { + super(null, name); + publisher = CONTEXT.socket(ZMQ.PUB); + publisher.setAffinity(config.affinity); + publisher.setBacklog(config.backlog); + publisher.setDelayAttachOnConnect(config.delayAttachOnConnect); + if (config.identity != null) { + publisher.setIdentity(config.identity); + } + publisher.setIPv4Only(config.ipv4Only); + publisher.setLinger(config.linger); + publisher.setMaxMsgSize(config.maxMsgSize); + publisher.setRcvHWM(config.rcvHwm); + publisher.setReceiveBufferSize(config.receiveBufferSize); + publisher.setReceiveTimeOut(config.receiveTimeOut); + publisher.setReconnectIVL(config.reconnectIVL); + publisher.setReconnectIVLMax(config.reconnectIVLMax); + publisher.setSendBufferSize(config.sendBufferSize); + publisher.setSendTimeOut(config.sendTimeOut); + publisher.setSndHWM(config.sndHwm); + publisher.setTCPKeepAlive(config.tcpKeepAlive); + publisher.setTCPKeepAliveCount(config.tcpKeepAliveCount); + publisher.setTCPKeepAliveIdle(config.tcpKeepAliveIdle); + publisher.setTCPKeepAliveInterval(config.tcpKeepAliveInterval); + publisher.setXpubVerbose(config.xpubVerbose); + for (final String endpoint : config.endpoints) { + publisher.bind(endpoint); + } + LOGGER.debug("Created JeroMqManager with {}", config); + } + + public boolean send(final byte[] data) { + return publisher.send(data); + } + + @Override + protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) { + publisher.close(); + return true; + } + + public static JeroMqManager getJeroMqManager(final String name, final long affinity, final long backlog, + final boolean delayAttachOnConnect, final byte[] identity, + final boolean ipv4Only, final long linger, final long maxMsgSize, + final long rcvHwm, final long receiveBufferSize, + final int receiveTimeOut, final long reconnectIVL, + final long reconnectIVLMax, final long sendBufferSize, + final int sendTimeOut, final long sndHwm, final int tcpKeepAlive, + final long tcpKeepAliveCount, final long tcpKeepAliveIdle, + final long tcpKeepAliveInterval, final boolean xpubVerbose, + final List endpoints) { + return getManager(name, FACTORY, + new JeroMqConfiguration(affinity, backlog, delayAttachOnConnect, identity, ipv4Only, linger, maxMsgSize, + rcvHwm, receiveBufferSize, receiveTimeOut, reconnectIVL, reconnectIVLMax, sendBufferSize, sendTimeOut, + sndHwm, tcpKeepAlive, tcpKeepAliveCount, tcpKeepAliveIdle, tcpKeepAliveInterval, xpubVerbose, + endpoints)); + } + + public static ZMQ.Context getContext() { + return CONTEXT; + } + + private static class JeroMqConfiguration { + private final long affinity; + private final long backlog; + private final boolean delayAttachOnConnect; + private final byte[] identity; + private final boolean ipv4Only; + private final long linger; + private final long maxMsgSize; + private final long rcvHwm; + private final long receiveBufferSize; + private final int receiveTimeOut; + private final long reconnectIVL; + private final long reconnectIVLMax; + private final long sendBufferSize; + private final int sendTimeOut; + private final long sndHwm; + private final int tcpKeepAlive; + private final long tcpKeepAliveCount; + private final long tcpKeepAliveIdle; + private final long tcpKeepAliveInterval; + private final boolean xpubVerbose; + private final List endpoints; + + private JeroMqConfiguration(final long affinity, final long backlog, final boolean delayAttachOnConnect, + final byte[] identity, final boolean ipv4Only, final long linger, + final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, + final int receiveTimeOut, final long reconnectIVL, final long reconnectIVLMax, + final long sendBufferSize, final int sendTimeOut, final long sndHwm, + final int tcpKeepAlive, final long tcpKeepAliveCount, final long tcpKeepAliveIdle, + final long tcpKeepAliveInterval, final boolean xpubVerbose, + final List endpoints) { + this.affinity = affinity; + this.backlog = backlog; + this.delayAttachOnConnect = delayAttachOnConnect; + this.identity = identity; + this.ipv4Only = ipv4Only; + this.linger = linger; + this.maxMsgSize = maxMsgSize; + this.rcvHwm = rcvHwm; + this.receiveBufferSize = receiveBufferSize; + this.receiveTimeOut = receiveTimeOut; + this.reconnectIVL = reconnectIVL; + this.reconnectIVLMax = reconnectIVLMax; + this.sendBufferSize = sendBufferSize; + this.sendTimeOut = sendTimeOut; + this.sndHwm = sndHwm; + this.tcpKeepAlive = tcpKeepAlive; + this.tcpKeepAliveCount = tcpKeepAliveCount; + this.tcpKeepAliveIdle = tcpKeepAliveIdle; + this.tcpKeepAliveInterval = tcpKeepAliveInterval; + this.xpubVerbose = xpubVerbose; + this.endpoints = endpoints; + } + + @Override + public String toString() { + return "JeroMqConfiguration{" + + "affinity=" + affinity + + ", backlog=" + backlog + + ", delayAttachOnConnect=" + delayAttachOnConnect + + ", identity=" + Arrays.toString(identity) + + ", ipv4Only=" + ipv4Only + + ", linger=" + linger + + ", maxMsgSize=" + maxMsgSize + + ", rcvHwm=" + rcvHwm + + ", receiveBufferSize=" + receiveBufferSize + + ", receiveTimeOut=" + receiveTimeOut + + ", reconnectIVL=" + reconnectIVL + + ", reconnectIVLMax=" + reconnectIVLMax + + ", sendBufferSize=" + sendBufferSize + + ", sendTimeOut=" + sendTimeOut + + ", sndHwm=" + sndHwm + + ", tcpKeepAlive=" + tcpKeepAlive + + ", tcpKeepAliveCount=" + tcpKeepAliveCount + + ", tcpKeepAliveIdle=" + tcpKeepAliveIdle + + ", tcpKeepAliveInterval=" + tcpKeepAliveInterval + + ", xpubVerbose=" + xpubVerbose + + ", endpoints=" + endpoints + + '}'; + } + } + + private static class JeroMqManagerFactory implements ManagerFactory { + @Override + public JeroMqManager createManager(final String name, final JeroMqConfiguration data) { + return new JeroMqManager(name, data); + } + } +} diff --git a/log4j-jeromq/src/site/manual/index.md b/log4j-jeromq/src/site/manual/index.md new file mode 100644 index 00000000000..66fe24fe304 --- /dev/null +++ b/log4j-jeromq/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j ZeroMQ using JeroMQ module + +As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires the jeromq JAR. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-jeromq/src/site/site.xml b/log4j-jeromq/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-jeromq/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java b/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java rename to log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java b/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java similarity index 97% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java rename to log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java index ddd06abcf43..b84cc729f72 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java +++ b/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java @@ -1,55 +1,55 @@ -/* - * 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.mom.jeromq; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -import org.zeromq.ZMQ; - -class JeroMqTestClient implements Callable> { - - private final ZMQ.Context context; - - private final String endpoint; - private final List messages; - private final int receiveCount; - - JeroMqTestClient(final ZMQ.Context context, final String endpoint, final int receiveCount) { - super(); - this.context = context; - this.endpoint = endpoint; - this.receiveCount = receiveCount; - this.messages = new ArrayList<>(receiveCount); - } - - @Override - public List call() throws Exception { - try (ZMQ.Socket subscriber = context.socket(ZMQ.SUB)) { - subscriber.connect(endpoint); - subscriber.subscribe(new byte[0]); - for (int messageNum = 0; messageNum < receiveCount - && !Thread.currentThread().isInterrupted(); messageNum++) { - // Use trim to remove the tailing '0' character - messages.add(subscriber.recvStr(0).trim()); - } - } - return messages; - } +/* + * 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.mom.jeromq; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +import org.zeromq.ZMQ; + +class JeroMqTestClient implements Callable> { + + private final ZMQ.Context context; + + private final String endpoint; + private final List messages; + private final int receiveCount; + + JeroMqTestClient(final ZMQ.Context context, final String endpoint, final int receiveCount) { + super(); + this.context = context; + this.endpoint = endpoint; + this.receiveCount = receiveCount; + this.messages = new ArrayList<>(receiveCount); + } + + @Override + public List call() throws Exception { + try (ZMQ.Socket subscriber = context.socket(ZMQ.SUB)) { + subscriber.connect(endpoint); + subscriber.subscribe(new byte[0]); + for (int messageNum = 0; messageNum < receiveCount + && !Thread.currentThread().isInterrupted(); messageNum++) { + // Use trim to remove the tailing '0' character + messages.add(subscriber.recvStr(0).trim()); + } + } + return messages; + } } \ No newline at end of file diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml new file mode 100644 index 00000000000..ad22f659779 --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml new file mode 100644 index 00000000000..af3a0b74620 --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml new file mode 100644 index 00000000000..3f6e50a0367 --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml new file mode 100644 index 00000000000..8215ea3a2b9 --- /dev/null +++ b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 362eb419ff9..34bb67020c9 100644 --- a/pom.xml +++ b/pom.xml @@ -1336,6 +1336,7 @@ log4j-bom log4j-jdbc-dbcp2 log4j-jpa + log4j-jeromq log4j-couchdb log4j-mongodb2 log4j-mongodb3 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 431e665de11..aea4e1c678c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -164,6 +164,9 @@ Update Jackson from 2.9.3 to 2.9.4. + + Split off ZeroMq/JeroMq support into a new module log4j-jeromq. + diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index a6401bb8159..bcd77368b74 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -5218,6 +5218,9 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { +

+ As of Log4j 2.11.0, ZeroMQ/JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq. +

The ZeroMQ appender uses the JeroMQ library to send log events to one or more ZeroMQ endpoints. From 2deb32280549966205f8a9d5cbb8f0e7b937880f Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 11:13:17 -0700 Subject: [PATCH 0005/2347] Javadoc tweaks. --- .../java/org/apache/logging/log4j/core/util/Instant.java | 2 +- .../apache/logging/log4j/core/util/MutableInstant.java | 2 +- .../org/apache/logging/log4j/core/util/PreciseClock.java | 4 ++-- .../org/apache/logging/log4j/core/util/SystemClock.java | 2 +- .../main/java/org/apache/logging/log4j/core/LogEvent.java | 2 +- .../org/apache/logging/log4j/core/impl/Log4jLogEvent.java | 2 +- .../java/org/apache/logging/log4j/core/time/Instant.java | 8 +++++--- .../apache/logging/log4j/core/time/MutableInstant.java | 2 +- .../org/apache/logging/log4j/core/time/PreciseClock.java | 4 ++-- .../log4j/core/time/internal/FixedPreciseClock.java | 2 +- .../log4j/core/time/internal/SystemMillisClock.java | 2 +- .../apache/logging/log4j/flume/appender/FlumeEvent.java | 2 +- 12 files changed, 18 insertions(+), 16 deletions(-) diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java index cd4ac9db467..829e486d1ca 100644 --- a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java +++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/Instant.java @@ -32,7 +32,7 @@ *

* This class bridges these two time APIs. *

- * @since 2.11 + * @since 2.11.0 */ public interface Instant { /** diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java index 8960fc53f53..a8851019393 100644 --- a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java +++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/MutableInstant.java @@ -31,7 +31,7 @@ * Instances of this class are not thread-safe and should not be shared between threads. *

* - * @since 2.11 + * @since 2.11.0 */ @PerformanceSensitive("allocation") public class MutableInstant implements Instant, Serializable { diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java index 3d1f314ee60..7dc0700f0ef 100644 --- a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java +++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/PreciseClock.java @@ -23,14 +23,14 @@ * Extension of the {@link Clock} interface that is able to provide more accurate time information than milliseconds * since the epoch. {@code PreciseClock} implementations are free to return millisecond-precision time * if that is the most accurate time information available on this platform. - * @since 2.11 + * @since 2.11.0 */ public interface PreciseClock extends Clock { /** * Initializes the specified instant with time information as accurate as available on this platform. * @param mutableInstant the container to be initialized with the accurate time information - * @since 2.11 + * @since 2.11.0 */ void init(final MutableInstant mutableInstant); } diff --git a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java index a74a1fde110..6eb2379534a 100644 --- a/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java +++ b/log4j-core-java9/src/main/java/org/apache/logging/log4j/core/util/SystemClock.java @@ -20,7 +20,7 @@ /** * Implementation of the {@code Clock} interface that returns the system time. - * @since 2.11 + * @since 2.11.0 */ public final class SystemClock implements Clock, PreciseClock { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java index 0879f40a1b3..017eb2e69ff 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java @@ -141,7 +141,7 @@ public interface LogEvent extends Serializable { *

* * @return the {@code Instant} holding timestamp details for this log event - * @since 2.11 + * @since 2.11.0 */ Instant getInstant(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java index 48076d838f8..d7da56ca4b9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java @@ -581,7 +581,7 @@ public long getTimeMillis() { /** * {@inheritDoc} - * @since 2.11 + * @since 2.11.0 */ @Override public Instant getInstant() { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java index ab50da11a69..c9609cd02a5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java @@ -25,14 +25,16 @@ * Provides methods for obtaining high precision time information similar to the * Instant class introduced in Java 8, * while also supporting the legacy millisecond precision API. - *

+ *

+ *

* Depending on the platform, time sources ({@link Clock} implementations) may produce high precision or millisecond * precision time values. At the same time, some time value consumers (for example timestamp formatters) may only be * able to consume time values of millisecond precision, while some others may require a high precision time value. - *

+ *

+ *

* This class bridges these two time APIs. *

- * @since 2.11 + * @since 2.11.0 */ public interface Instant extends StringBuilderFormattable { /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java index 09b0d39d383..6e27dd80cc4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java @@ -29,7 +29,7 @@ * Instances of this class are not thread-safe and should not be shared between threads. *

* - * @since 2.11 + * @since 2.11.0 */ @PerformanceSensitive("allocation") public class MutableInstant implements Instant, Serializable { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java index c2416f62ef8..a0ae3f6f51d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java @@ -22,14 +22,14 @@ * Extension of the {@link Clock} interface that is able to provide more accurate time information than milliseconds * since the epoch. {@code PreciseClock} implementations are free to return millisecond-precision time * if that is the most accurate time information available on this platform. - * @since 2.11 + * @since 2.11.0 */ public interface PreciseClock extends Clock { /** * Initializes the specified instant with time information as accurate as available on this platform. * @param mutableInstant the container to be initialized with the accurate time information - * @since 2.11 + * @since 2.11.0 */ void init(final MutableInstant mutableInstant); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/FixedPreciseClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/FixedPreciseClock.java index 868cdbe8464..eae268b8f8a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/FixedPreciseClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/FixedPreciseClock.java @@ -21,7 +21,7 @@ /** * Implementation of the {@code PreciseClock} interface that always returns a fixed time value. - * @since 2.11 + * @since 2.11.0 */ public class FixedPreciseClock implements PreciseClock { private final long currentTimeMillis; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java index 49b7ffccabd..af266330670 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java @@ -20,7 +20,7 @@ /** * Implementation of the {@code Clock} interface that returns the system time in millisecond granularity. - * @since 2.11 + * @since 2.11.0 */ public final class SystemMillisClock implements Clock { diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java index cee5d9cf7fa..a471004c8b4 100644 --- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java +++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeEvent.java @@ -296,7 +296,7 @@ public long getTimeMillis() { /** * {@inheritDoc} - * @since 2.11 + * @since 2.11.0 */ @Override public Instant getInstant() { From 103496b4303f1a3ab526d051acd4635ed14a8fb8 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 11:25:31 -0700 Subject: [PATCH 0006/2347] Fix test fixture to avoid ERROR messages on the console. --- .../src/test/resources/log4j-scriptFile-filters.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/test/resources/log4j-scriptFile-filters.properties b/log4j-core/src/test/resources/log4j-scriptFile-filters.properties index 0daab515929..31b1e04751b 100644 --- a/log4j-core/src/test/resources/log4j-scriptFile-filters.properties +++ b/log4j-core/src/test/resources/log4j-scriptFile-filters.properties @@ -37,7 +37,7 @@ logger.javascriptFilter.additivity = false logger.javascriptFilter.appenderRef.list.ref = List logger.javascriptFilter.filter.script.type = ScriptFilter logger.javascriptFilter.filter.script.onMatch = ACCEPT -logger.javascriptFilter.filter.script.onMisMatch = DENY +logger.javascriptFilter.filter.script.onMismatch = DENY logger.javascriptFilter.filter.script.ref.type = ScriptRef logger.javascriptFilter.filter.script.ref.ref = filter.js @@ -47,7 +47,7 @@ logger.groovyFilter.additivity = false logger.groovyFilter.appenderRef.list.ref = List logger.groovyFilter.filter.script.type = ScriptFilter logger.groovyFilter.filter.script.onMatch = ACCEPT -logger.groovyFilter.filter.script.onMisMatch = DENY +logger.groovyFilter.filter.script.onMismatch = DENY logger.groovyFilter.filter.script.ref.type = ScriptRef logger.groovyFilter.filter.script.ref.ref = filter.groovy From f77ade5ff3646520cc5cd0321ff4af7520a3d35b Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 12:54:02 -0700 Subject: [PATCH 0007/2347] [LOG4J2-2227] Split off Kafka support into a new module log4j-kafka. --- log4j-core/pom.xml | 6 - .../core/appender/mom/kafka/package-info.java | 23 --- .../builder/ConfigurationAssemblerTest.java | 10 +- .../builder/ConfigurationBuilderTest.java | 13 -- .../builder/CustomConfigurationFactory.java | 15 +- log4j-kafka/pom.xml | 170 ++++++++++++++++++ .../kafka/DefaultKafkaProducerFactory.java | 0 .../appender/mom/kafka/KafkaAppender.java | 0 .../core/appender/mom/kafka/KafkaManager.java | 0 .../mom/kafka/KafkaProducerFactory.java | 0 log4j-kafka/src/site/manual/index.md | 33 ++++ log4j-kafka/src/site/site.xml | 52 ++++++ .../kafka/KafkaAppenderCloseTimeoutTest.java | 0 .../appender/mom/kafka/KafkaAppenderTest.java | 0 .../builder/ConfigurationAssemblerTest.java | 116 ++++++++++++ .../builder/ConfigurationBuilderTest.java | 120 +++++++++++++ .../builder/CustomConfigurationFactory.java | 86 +++++++++ .../appender/db/jpa/log4j2-h2-jpa-base.xml | 38 ++++ .../appender/db/jpa/log4j2-h2-jpa-basic.xml | 38 ++++ .../db/jpa/log4j2-hsqldb-jpa-base.xml | 38 ++++ .../db/jpa/log4j2-hsqldb-jpa-basic.xml | 38 ++++ pom.xml | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/appenders.xml | 4 + 24 files changed, 747 insertions(+), 57 deletions(-) delete mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/package-info.java create mode 100644 log4j-kafka/pom.xml rename {log4j-core => log4j-kafka}/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java (100%) rename {log4j-core => log4j-kafka}/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java (100%) rename {log4j-core => log4j-kafka}/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java (100%) rename {log4j-core => log4j-kafka}/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java (100%) create mode 100644 log4j-kafka/src/site/manual/index.md create mode 100644 log4j-kafka/src/site/site.xml rename {log4j-core => log4j-kafka}/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java (100%) rename {log4j-core => log4j-kafka}/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java (100%) create mode 100644 log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java create mode 100644 log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java create mode 100644 log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java create mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml create mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml create mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml create mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index ef854c1d378..e5e434a2f90 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -120,12 +120,6 @@ provided true - - - org.apache.kafka - kafka-clients - true - org.apache.commons diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/package-info.java deleted file mode 100644 index 60f4dcf09e7..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/package-info.java +++ /dev/null @@ -1,23 +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. - */ - -/** - * Classes and interfaces for Kafka appender support. - * - * @since 2.4 - */ -package org.apache.logging.log4j.core.appender.mom.kafka; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java index ec4f541bd34..3859393f87a 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.mom.kafka.KafkaAppender; +import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.Configurator; @@ -41,7 +41,7 @@ import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; import org.apache.logging.log4j.core.filter.ThresholdFilter; -import org.apache.logging.log4j.core.layout.GelfLayout; +import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.Constants; import org.junit.Test; @@ -89,9 +89,9 @@ private void validate(final Configuration config) { assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED); final Map appenders = config.getAppenders(); assertNotNull(appenders); - assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 2); - final KafkaAppender kafkaAppender = (KafkaAppender)appenders.get("Kafka"); - final GelfLayout gelfLayout = (GelfLayout)kafkaAppender.getLayout(); + assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 1); + final ConsoleAppender consoleAppender = (ConsoleAppender)appenders.get("Stdout"); + final PatternLayout gelfLayout = (PatternLayout)consoleAppender.getLayout(); final Map loggers = config.getLoggers(); assertNotNull(loggers); assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java index bbb7f104141..a620c30008e 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java @@ -50,13 +50,6 @@ private void addTestFixtures(final String name, final ConfigurationBuilder" + EOL + INDENT + INDENT + INDENT + "" + EOL + INDENT + INDENT + "" + EOL + - INDENT + INDENT + "" + EOL + - INDENT + INDENT + INDENT + "localhost:9092" + EOL + - INDENT + INDENT + INDENT + "" + EOL + - INDENT + INDENT + INDENT + INDENT + "" + EOL + - INDENT + INDENT + INDENT + "" + EOL + - INDENT + INDENT + "" + EOL + INDENT + "" + EOL + INDENT + "" + EOL + INDENT + INDENT + "" + EOL + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java index 847f79e75e0..c8ba5aed73e 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java @@ -45,19 +45,14 @@ static Configuration addTestFixtures(final String name, final ConfigurationBuild .addAttribute("level", Level.DEBUG)); final AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); - appenderBuilder.add(builder.newLayout("PatternLayout"). + appenderBuilder.add(builder. + newLayout("PatternLayout"). addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")); - appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, - Filter.Result.NEUTRAL).addAttribute("marker", "FLOW")); + appenderBuilder.add(builder. + newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL). + addAttribute("marker", "FLOW")); builder.add(appenderBuilder); - final AppenderComponentBuilder appenderBuilder2 = builder.newAppender("Kafka", "Kafka").addAttribute("topic", "my-topic"); - appenderBuilder2.addComponent(builder.newProperty("bootstrap.servers", "localhost:9092")); - appenderBuilder2.add(builder.newLayout("GelfLayout"). - addAttribute("host", "my-host"). - addComponent(builder.newKeyValuePair("extraField", "extraValue"))); - builder.add(appenderBuilder2); - builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG, true). add(builder.newAppenderRef("Stdout")). addAttribute("additivity", false)); diff --git a/log4j-kafka/pom.xml b/log4j-kafka/pom.xml new file mode 100644 index 00000000000..73df1a5f22f --- /dev/null +++ b/log4j-kafka/pom.xml @@ -0,0 +1,170 @@ + + + + + + org.apache.logging.log4j + log4j + 2.10.1-SNAPSHOT + + 4.0.0 + + log4j-kafka + Apache Log4j Kafka + + Apache Log4j Kafka. + + + ${basedir}/.. + Log4j Kafka Documentation + /log4j-kafka + org.apache.logging.log4j.kafka + + + + + org.apache.logging.log4j + log4j-core + + + + org.apache.kafka + kafka-clients + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + + com.lmax + disruptor + test + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.core.appender.mom.kafka + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]>
+ + false + true +
+ + + non-aggregate + + javadoc + + + +
+ + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + +
+
+
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java diff --git a/log4j-kafka/src/site/manual/index.md b/log4j-kafka/src/site/manual/index.md new file mode 100644 index 00000000000..d70256ab56f --- /dev/null +++ b/log4j-kafka/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j Kafka module + +As of Log4j 2.11.0, Kafka support has moved from the existing module logj-core to the new module log4j-kafka. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires the Kafka client JAR. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-kafka/src/site/site.xml b/log4j-kafka/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-kafka/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java rename to log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java rename to log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java new file mode 100644 index 00000000000..ec4f541bd34 --- /dev/null +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java @@ -0,0 +1,116 @@ +/* + * 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.config.builder; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Map; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LifeCycle; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.mom.kafka.KafkaAppender; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.config.CustomLevelConfig; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; +import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; +import org.apache.logging.log4j.core.filter.ThresholdFilter; +import org.apache.logging.log4j.core.layout.GelfLayout; +import org.apache.logging.log4j.core.util.Constants; +import org.junit.Test; + +/** + * + */ +public class ConfigurationAssemblerTest { + + @Test + public void testBuildConfiguration() throws Exception { + try { + System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, + "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"); + final ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder(); + CustomConfigurationFactory.addTestFixtures("config name", builder); + final Configuration configuration = builder.build(); + try (LoggerContext ctx = Configurator.initialize(configuration)) { + validate(configuration); + } + } finally { + System.getProperties().remove(Constants.LOG4J_CONTEXT_SELECTOR); + } + } + + @Test + public void testCustomConfigurationFactory() throws Exception { + try { + System.setProperty(ConfigurationFactory.CONFIGURATION_FACTORY_PROPERTY, + "org.apache.logging.log4j.core.config.builder.CustomConfigurationFactory"); + System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, + "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"); + final Configuration config = ((LoggerContext) LogManager.getContext(false)).getConfiguration(); + validate(config); + } finally { + System.getProperties().remove(Constants.LOG4J_CONTEXT_SELECTOR); + System.getProperties().remove(ConfigurationFactory.CONFIGURATION_FACTORY_PROPERTY); + } + } + + private void validate(final Configuration config) { + assertNotNull(config); + assertNotNull(config.getName()); + assertFalse(config.getName().isEmpty()); + assertNotNull("No configuration created", config); + assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED); + final Map appenders = config.getAppenders(); + assertNotNull(appenders); + assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 2); + final KafkaAppender kafkaAppender = (KafkaAppender)appenders.get("Kafka"); + final GelfLayout gelfLayout = (GelfLayout)kafkaAppender.getLayout(); + final Map loggers = config.getLoggers(); + assertNotNull(loggers); + assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2); + final LoggerConfig rootLoggerConfig = loggers.get(""); + assertEquals(Level.ERROR, rootLoggerConfig.getLevel()); + assertFalse(rootLoggerConfig.isIncludeLocation()); + final LoggerConfig loggerConfig = loggers.get("org.apache.logging.log4j"); + assertEquals(Level.DEBUG, loggerConfig.getLevel()); + assertTrue(loggerConfig.isIncludeLocation()); + final Filter filter = config.getFilter(); + assertNotNull("No Filter", filter); + assertTrue("Not a Threshold Filter", filter instanceof ThresholdFilter); + final List customLevels = config.getCustomLevels(); + assertNotNull("No CustomLevels", filter); + assertEquals(1, customLevels.size()); + final CustomLevelConfig customLevel = customLevels.get(0); + assertEquals("Panic", customLevel.getLevelName()); + assertEquals(17, customLevel.getIntLevel()); + final Logger logger = LogManager.getLogger(getClass()); + logger.info("Welcome to Log4j!"); + } +} diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java new file mode 100644 index 00000000000..bbb7f104141 --- /dev/null +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java @@ -0,0 +1,120 @@ +/* + * 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.config.builder; + +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; +import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.junit.Assume.assumeTrue; + +public class ConfigurationBuilderTest { + + private static final String INDENT = " "; + private static final String EOL = System.lineSeparator(); + + private void addTestFixtures(final String name, final ConfigurationBuilder builder) { + builder.setConfigurationName(name); + builder.setStatusLevel(Level.ERROR); + builder.setShutdownTimeout(5000, TimeUnit.MILLISECONDS); + builder.add(builder.newScriptFile("target/test-classes/scripts/filter.groovy").addIsWatched(true)); + builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL) + .addAttribute("level", Level.DEBUG)); + + final AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); + appenderBuilder.add(builder.newLayout("PatternLayout"). + addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")); + appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, + Filter.Result.NEUTRAL).addAttribute("marker", "FLOW")); + builder.add(appenderBuilder); + + final AppenderComponentBuilder appenderBuilder2 = builder.newAppender("Kafka", "Kafka").addAttribute("topic", "my-topic"); + appenderBuilder2.addComponent(builder.newProperty("bootstrap.servers", "localhost:9092")); + appenderBuilder2.add(builder.newLayout("GelfLayout"). + addAttribute("host", "my-host"). + addComponent(builder.newKeyValuePair("extraField", "extraValue"))); + builder.add(appenderBuilder2); + + builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG, true). + add(builder.newAppenderRef("Stdout")). + addAttribute("additivity", false)); + builder.add(builder.newLogger("org.apache.logging.log4j.core"). + add(builder.newAppenderRef("Stdout"))); + builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout"))); + + builder.addProperty("MyKey", "MyValue"); + builder.add(builder.newCustomLevel("Panic", 17)); + builder.setPackages("foo,bar"); + } + + private final static String expectedXml = + "" + EOL + + "" + EOL + + INDENT + "" + EOL + + INDENT + INDENT + "MyValue" + EOL + + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + "localhost:9092" + EOL + + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + INDENT + INDENT + "" + EOL + + INDENT + INDENT + "" + EOL + + INDENT + "" + EOL + + "" + EOL; + + // TODO make test run properly on Windows + @Test + public void testXmlConstructing() throws Exception { + assumeTrue(System.lineSeparator().length() == 1); // Only run test on platforms with single character line endings (such as Linux), not on Windows + final ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder(); + addTestFixtures("config name", builder); + final String xmlConfiguration = builder.toXmlConfiguration(); + assertEquals(expectedXml, xmlConfiguration); + } + +} diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java new file mode 100644 index 00000000000..847f79e75e0 --- /dev/null +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java @@ -0,0 +1,86 @@ +/* + * 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.config.builder; + +import java.net.URI; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder; +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder; +import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; + +/** + * Normally this would be a plugin. However, we don't want it used for everything so it will be defined + * via a system property. + */ +//@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY) +//@Order(50) +public class CustomConfigurationFactory extends ConfigurationFactory { + + static Configuration addTestFixtures(final String name, final ConfigurationBuilder builder) { + builder.setConfigurationName(name); + builder.setStatusLevel(Level.ERROR); + builder.add(builder.newScriptFile("target/test-classes/scripts/filter.groovy").addIsWatched(true)); + builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL) + .addAttribute("level", Level.DEBUG)); + + final AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); + appenderBuilder.add(builder.newLayout("PatternLayout"). + addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")); + appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, + Filter.Result.NEUTRAL).addAttribute("marker", "FLOW")); + builder.add(appenderBuilder); + + final AppenderComponentBuilder appenderBuilder2 = builder.newAppender("Kafka", "Kafka").addAttribute("topic", "my-topic"); + appenderBuilder2.addComponent(builder.newProperty("bootstrap.servers", "localhost:9092")); + appenderBuilder2.add(builder.newLayout("GelfLayout"). + addAttribute("host", "my-host"). + addComponent(builder.newKeyValuePair("extraField", "extraValue"))); + builder.add(appenderBuilder2); + + builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG, true). + add(builder.newAppenderRef("Stdout")). + addAttribute("additivity", false)); + builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout"))); + + builder.add(builder.newCustomLevel("Panic", 17)); + + return builder.build(); + } + + @Override + public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) { + return getConfiguration(loggerContext, source.toString(), null); + } + + @Override + public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) { + final ConfigurationBuilder builder = newConfigurationBuilder(); + return addTestFixtures(name, builder); + } + + @Override + protected String[] getSupportedTypes() { + return new String[] {"*"}; + } +} diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml new file mode 100644 index 00000000000..ad22f659779 --- /dev/null +++ b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml new file mode 100644 index 00000000000..af3a0b74620 --- /dev/null +++ b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml new file mode 100644 index 00000000000..3f6e50a0367 --- /dev/null +++ b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml new file mode 100644 index 00000000000..8215ea3a2b9 --- /dev/null +++ b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 34bb67020c9..86fa736dcc2 100644 --- a/pom.xml +++ b/pom.xml @@ -1337,6 +1337,7 @@ log4j-jdbc-dbcp2 log4j-jpa log4j-jeromq + log4j-kafka log4j-couchdb log4j-mongodb2 log4j-mongodb3 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index aea4e1c678c..fd8dbaf2cd8 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -167,6 +167,9 @@ Split off ZeroMq/JeroMq support into a new module log4j-jeromq. + + Split off Kafka support into a new module log4j-kafka. + diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index bcd77368b74..9ca133d33cd 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -1884,6 +1884,10 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { +

+ As of Log4j 2.11.0, Apache Kafka support has moved from the + existing module logj-core to the new module log4j-kafka. +

The KafkaAppender logs events to an Apache Kafka topic. Each log event is sent as a Kafka record. From fcdfe68c52bb67af28e74a4c7618be47defdd26c Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 13:11:41 -0700 Subject: [PATCH 0008/2347] [LOG4J2-2227] Split off Kafka support into a new module log4j-kafka. --- .../appender/db/jpa/log4j2-h2-jpa-base.xml | 38 ------------------- .../appender/db/jpa/log4j2-h2-jpa-basic.xml | 38 ------------------- .../db/jpa/log4j2-hsqldb-jpa-base.xml | 38 ------------------- .../db/jpa/log4j2-hsqldb-jpa-basic.xml | 38 ------------------- 4 files changed, 152 deletions(-) delete mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml delete mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml delete mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml delete mode 100644 log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml deleted file mode 100644 index ad22f659779..00000000000 --- a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml deleted file mode 100644 index af3a0b74620..00000000000 --- a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml deleted file mode 100644 index 3f6e50a0367..00000000000 --- a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml b/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml deleted file mode 100644 index 8215ea3a2b9..00000000000 --- a/log4j-kafka/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - From 7418f9b223bb263024745809e065c4f43d70af80 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 13:25:55 -0700 Subject: [PATCH 0009/2347] [LOG4J2-2228] Split off ZeroMq/JeroMq support into a new module log4j-jeromq. --- log4j-bom/pom.xml | 6 ++++++ log4j-core/pom.xml | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index 281572a9acf..5af6d738bb0 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -66,6 +66,12 @@ log4j-taglib ${project.version} + + + org.apache.logging.log4j + log4j-jeromq + ${project.version} + org.apache.logging.log4j diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index e5e434a2f90..d1f3f108f68 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -107,12 +107,6 @@ jansi true - - - com.sun.mail - javax.mail - true - org.jboss.spec.javax.jms From 9625776530f7f37ce1c6ad7cfcf9c543e086fea7 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 13:27:07 -0700 Subject: [PATCH 0010/2347] [LOG4J2-2227] Split off Kafka support into a new module log4j-kafka. --- log4j-bom/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index 5af6d738bb0..7efc698265c 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -114,6 +114,12 @@ log4j-cassandra ${project.version} + + + org.apache.logging.log4j + log4j-kafka + ${project.version} + org.apache.logging.log4j From b667d0e17db00e68d41307c525bf689ad9b463a7 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 14:40:10 -0700 Subject: [PATCH 0011/2347] [LOG4J2-2230] Split off SMTP support into a new module log4j-smtp. --- log4j-bom/pom.xml | 6 + log4j-smtp/pom.xml | 165 +++++++ .../log4j/core/appender/SmtpAppender.java | 0 .../log4j/core/net/MimeMessageBuilder.java | 0 .../logging/log4j/core/net/SmtpManager.java | 0 log4j-smtp/src/site/manual/index.md | 33 ++ log4j-smtp/src/site/site.xml | 52 ++ .../dumbster/smtp/SimpleSmtpServer.java | 0 .../logging/dumbster/smtp/SmtpActionType.java | 404 +++++++-------- .../logging/dumbster/smtp/SmtpMessage.java | 0 .../logging/dumbster/smtp/SmtpRequest.java | 464 +++++++++--------- .../logging/dumbster/smtp/SmtpResponse.java | 150 +++--- .../logging/dumbster/smtp/SmtpState.java | 242 ++++----- .../apache/logging/dumbster/smtp/readme.txt | 0 .../core/appender/SmtpAppenderAsyncTest.java | 0 .../log4j/core/appender/SmtpAppenderTest.java | 0 .../test/resources/SmtpAppenderAsyncTest.xml | 42 ++ pom.xml | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/appenders.xml | 4 + 20 files changed, 936 insertions(+), 630 deletions(-) create mode 100644 log4j-smtp/pom.xml rename {log4j-core => log4j-smtp}/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java (100%) rename {log4j-core => log4j-smtp}/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java (100%) rename {log4j-core => log4j-smtp}/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java (100%) create mode 100644 log4j-smtp/src/site/manual/index.md create mode 100644 log4j-smtp/src/site/site.xml rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/dumbster/smtp/SimpleSmtpServer.java (100%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/dumbster/smtp/SmtpActionType.java (96%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/dumbster/smtp/SmtpMessage.java (100%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/dumbster/smtp/SmtpRequest.java (97%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/dumbster/smtp/SmtpResponse.java (96%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/dumbster/smtp/SmtpState.java (96%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/dumbster/smtp/readme.txt (100%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java (100%) rename {log4j-core => log4j-smtp}/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java (100%) create mode 100644 log4j-smtp/src/test/resources/SmtpAppenderAsyncTest.xml diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index 7efc698265c..b3554f1be8d 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -144,6 +144,12 @@ log4j-liquibase ${project.version} + + + org.apache.logging.log4j + log4j-smtp + ${project.version} + diff --git a/log4j-smtp/pom.xml b/log4j-smtp/pom.xml new file mode 100644 index 00000000000..203db56de7a --- /dev/null +++ b/log4j-smtp/pom.xml @@ -0,0 +1,165 @@ + + + + + + org.apache.logging.log4j + log4j + 2.10.1-SNAPSHOT + + 4.0.0 + + log4j-smtp + Apache Log4j SMTP + + Apache Log4j Simple Mail Transfer Protocol (SMTP) Appender. + + + ${basedir}/.. + Log4j SMTP Appender Documentation + /log4j-smtp + org.apache.logging.log4j.smtp + + + + + org.apache.logging.log4j + log4j-core + + + + com.sun.mail + javax.mail + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.core.appender.mom.jeromq + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]> + + false + true + + + + non-aggregate + + javadoc + + + + + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + + + + diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java rename to log4j-smtp/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java rename to log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java rename to log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java diff --git a/log4j-smtp/src/site/manual/index.md b/log4j-smtp/src/site/manual/index.md new file mode 100644 index 00000000000..318d365b451 --- /dev/null +++ b/log4j-smtp/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j Simple Mail Transfer Protocol module + +As of Log4j 2.11.0, Simple Mail Transfer Protocol (SMTP) support has moved from the existing module logj-core to the new module log4j-smtp. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires the jeromq JAR. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-smtp/src/site/site.xml b/log4j-smtp/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-smtp/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SimpleSmtpServer.java b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SimpleSmtpServer.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SimpleSmtpServer.java rename to log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SimpleSmtpServer.java diff --git a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpActionType.java b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpActionType.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpActionType.java rename to log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpActionType.java index 9397ebb4b8f..8709e8c5ffb 100644 --- a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpActionType.java +++ b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpActionType.java @@ -1,202 +1,202 @@ -/* - * 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.dumbster.smtp; - -/** - * Represents an SMTP action or command. - */ -public class SmtpActionType { - /** - * Internal value for the action type. - */ - private final byte value; - - /** - * Internal representation of the CONNECT action. - */ - private static final byte CONNECT_BYTE = (byte) 1; - /** - * Internal representation of the EHLO action. - */ - private static final byte EHLO_BYTE = (byte) 2; - /** - * Internal representation of the MAIL FROM action. - */ - private static final byte MAIL_BYTE = (byte) 3; - /** - * Internal representation of the RCPT action. - */ - private static final byte RCPT_BYTE = (byte) 4; - /** - * Internal representation of the DATA action. - */ - private static final byte DATA_BYTE = (byte) 5; - /** - * Internal representation of the DATA END (.) action. - */ - private static final byte DATA_END_BYTE = (byte) 6; - /** - * Internal representation of the QUIT action. - */ - private static final byte QUIT_BYTE = (byte) 7; - /** - * Internal representation of an unrecognized action: body text gets this action type. - */ - private static final byte UNREC_BYTE = (byte) 8; - /** - * Internal representation of the blank line action: separates headers and body text. - */ - private static final byte BLANK_LINE_BYTE = (byte) 9; - - /** - * Internal representation of the stateless RSET action. - */ - private static final byte RSET_BYTE = (byte) -1; - /** - * Internal representation of the stateless VRFY action. - */ - private static final byte VRFY_BYTE = (byte) -2; - /** - * Internal representation of the stateless EXPN action. - */ - private static final byte EXPN_BYTE = (byte) -3; - /** - * Internal representation of the stateless HELP action. - */ - private static final byte HELP_BYTE = (byte) -4; - /** - * Internal representation of the stateless NOOP action. - */ - private static final byte NOOP_BYTE = (byte) -5; - - /** - * CONNECT action. - */ - public static final SmtpActionType CONNECT = new SmtpActionType(CONNECT_BYTE); - /** - * EHLO action. - */ - public static final SmtpActionType EHLO = new SmtpActionType(EHLO_BYTE); - /** - * MAIL action. - */ - public static final SmtpActionType MAIL = new SmtpActionType(MAIL_BYTE); - /** - * RCPT action. - */ - public static final SmtpActionType RCPT = new SmtpActionType(RCPT_BYTE); - /** - * DATA action. - */ - public static final SmtpActionType DATA = new SmtpActionType(DATA_BYTE); - /** - * "." action. - */ - public static final SmtpActionType DATA_END = new SmtpActionType(DATA_END_BYTE); - /** - * Body text action. - */ - public static final SmtpActionType UNRECOG = new SmtpActionType(UNREC_BYTE); - /** - * QUIT action. - */ - public static final SmtpActionType QUIT = new SmtpActionType(QUIT_BYTE); - /** - * Header/body separator action. - */ - public static final SmtpActionType BLANK_LINE = new SmtpActionType(BLANK_LINE_BYTE); - - /** - * Stateless RSET action. - */ - public static final SmtpActionType RSET = new SmtpActionType(RSET_BYTE); - /** - * Stateless VRFY action. - */ - public static final SmtpActionType VRFY = new SmtpActionType(VRFY_BYTE); - /** - * Stateless EXPN action. - */ - public static final SmtpActionType EXPN = new SmtpActionType(EXPN_BYTE); - /** - * Stateless HELP action. - */ - public static final SmtpActionType HELP = new SmtpActionType(HELP_BYTE); - /** - * Stateless NOOP action. - */ - public static final SmtpActionType NOOP = new SmtpActionType(NOOP_BYTE); - - /** - * Create a new SMTP action type. Private to ensure no invalid values. - * - * @param value one of the _BYTE values - */ - private SmtpActionType(final byte value) { - this.value = value; - } - - /** - * Indicates whether the action is stateless or not. - * - * @return true iff the action is stateless - */ - public boolean isStateless() { - return value < 0; - } - - /** - * String representation of this SMTP action type. - * - * @return a String - */ - @Override - public String toString() { - switch (value) { - case CONNECT_BYTE: - return "Connect"; - case EHLO_BYTE: - return "EHLO"; - case MAIL_BYTE: - return "MAIL"; - case RCPT_BYTE: - return "RCPT"; - case DATA_BYTE: - return "DATA"; - case DATA_END_BYTE: - return "."; - case QUIT_BYTE: - return "QUIT"; - case RSET_BYTE: - return "RSET"; - case VRFY_BYTE: - return "VRFY"; - case EXPN_BYTE: - return "EXPN"; - case HELP_BYTE: - return "HELP"; - case NOOP_BYTE: - return "NOOP"; - case UNREC_BYTE: - return "Unrecognized command / data"; - case BLANK_LINE_BYTE: - return "Blank line"; - default: - return "Unknown"; - } - } -} +/* + * 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.dumbster.smtp; + +/** + * Represents an SMTP action or command. + */ +public class SmtpActionType { + /** + * Internal value for the action type. + */ + private final byte value; + + /** + * Internal representation of the CONNECT action. + */ + private static final byte CONNECT_BYTE = (byte) 1; + /** + * Internal representation of the EHLO action. + */ + private static final byte EHLO_BYTE = (byte) 2; + /** + * Internal representation of the MAIL FROM action. + */ + private static final byte MAIL_BYTE = (byte) 3; + /** + * Internal representation of the RCPT action. + */ + private static final byte RCPT_BYTE = (byte) 4; + /** + * Internal representation of the DATA action. + */ + private static final byte DATA_BYTE = (byte) 5; + /** + * Internal representation of the DATA END (.) action. + */ + private static final byte DATA_END_BYTE = (byte) 6; + /** + * Internal representation of the QUIT action. + */ + private static final byte QUIT_BYTE = (byte) 7; + /** + * Internal representation of an unrecognized action: body text gets this action type. + */ + private static final byte UNREC_BYTE = (byte) 8; + /** + * Internal representation of the blank line action: separates headers and body text. + */ + private static final byte BLANK_LINE_BYTE = (byte) 9; + + /** + * Internal representation of the stateless RSET action. + */ + private static final byte RSET_BYTE = (byte) -1; + /** + * Internal representation of the stateless VRFY action. + */ + private static final byte VRFY_BYTE = (byte) -2; + /** + * Internal representation of the stateless EXPN action. + */ + private static final byte EXPN_BYTE = (byte) -3; + /** + * Internal representation of the stateless HELP action. + */ + private static final byte HELP_BYTE = (byte) -4; + /** + * Internal representation of the stateless NOOP action. + */ + private static final byte NOOP_BYTE = (byte) -5; + + /** + * CONNECT action. + */ + public static final SmtpActionType CONNECT = new SmtpActionType(CONNECT_BYTE); + /** + * EHLO action. + */ + public static final SmtpActionType EHLO = new SmtpActionType(EHLO_BYTE); + /** + * MAIL action. + */ + public static final SmtpActionType MAIL = new SmtpActionType(MAIL_BYTE); + /** + * RCPT action. + */ + public static final SmtpActionType RCPT = new SmtpActionType(RCPT_BYTE); + /** + * DATA action. + */ + public static final SmtpActionType DATA = new SmtpActionType(DATA_BYTE); + /** + * "." action. + */ + public static final SmtpActionType DATA_END = new SmtpActionType(DATA_END_BYTE); + /** + * Body text action. + */ + public static final SmtpActionType UNRECOG = new SmtpActionType(UNREC_BYTE); + /** + * QUIT action. + */ + public static final SmtpActionType QUIT = new SmtpActionType(QUIT_BYTE); + /** + * Header/body separator action. + */ + public static final SmtpActionType BLANK_LINE = new SmtpActionType(BLANK_LINE_BYTE); + + /** + * Stateless RSET action. + */ + public static final SmtpActionType RSET = new SmtpActionType(RSET_BYTE); + /** + * Stateless VRFY action. + */ + public static final SmtpActionType VRFY = new SmtpActionType(VRFY_BYTE); + /** + * Stateless EXPN action. + */ + public static final SmtpActionType EXPN = new SmtpActionType(EXPN_BYTE); + /** + * Stateless HELP action. + */ + public static final SmtpActionType HELP = new SmtpActionType(HELP_BYTE); + /** + * Stateless NOOP action. + */ + public static final SmtpActionType NOOP = new SmtpActionType(NOOP_BYTE); + + /** + * Create a new SMTP action type. Private to ensure no invalid values. + * + * @param value one of the _BYTE values + */ + private SmtpActionType(final byte value) { + this.value = value; + } + + /** + * Indicates whether the action is stateless or not. + * + * @return true iff the action is stateless + */ + public boolean isStateless() { + return value < 0; + } + + /** + * String representation of this SMTP action type. + * + * @return a String + */ + @Override + public String toString() { + switch (value) { + case CONNECT_BYTE: + return "Connect"; + case EHLO_BYTE: + return "EHLO"; + case MAIL_BYTE: + return "MAIL"; + case RCPT_BYTE: + return "RCPT"; + case DATA_BYTE: + return "DATA"; + case DATA_END_BYTE: + return "."; + case QUIT_BYTE: + return "QUIT"; + case RSET_BYTE: + return "RSET"; + case VRFY_BYTE: + return "VRFY"; + case EXPN_BYTE: + return "EXPN"; + case HELP_BYTE: + return "HELP"; + case NOOP_BYTE: + return "NOOP"; + case UNREC_BYTE: + return "Unrecognized command / data"; + case BLANK_LINE_BYTE: + return "Blank line"; + default: + return "Unknown"; + } + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpMessage.java b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpMessage.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpMessage.java rename to log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpMessage.java diff --git a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpRequest.java b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpRequest.java similarity index 97% rename from log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpRequest.java rename to log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpRequest.java index d877292640b..7f4a9655dc3 100644 --- a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpRequest.java +++ b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpRequest.java @@ -1,232 +1,232 @@ -/* - * 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.dumbster.smtp; - -import org.apache.logging.log4j.util.Strings; - -/** - * Contains an SMTP client request. Handles state transitions using the following state transition table. - *
- * -----------+-------------------------------------------------------------------------------------------------
- * |                                 State
- * Action    +-------------+-----------+-----------+--------------+---------------+---------------+------------
- * | CONNECT     | GREET     | MAIL      | RCPT         | DATA_HDR      | DATA_BODY     | QUIT
- * -----------+-------------+-----------+-----------+--------------+---------------+---------------+------------
- * connect    | 220/GREET   | 503/GREET | 503/MAIL  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
- * ehlo       | 503/CONNECT | 250/MAIL  | 503/MAIL  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
- * mail       | 503/CONNECT | 503/GREET | 250/RCPT  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 250/RCPT
- * rcpt       | 503/CONNECT | 503/GREET | 503/MAIL  | 250/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
- * data       | 503/CONNECT | 503/GREET | 503/MAIL  | 354/DATA_HDR | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
- * data_end   | 503/CONNECT | 503/GREET | 503/MAIL  | 503/RCPT     | 250/QUIT      | 250/QUIT      | 503/QUIT
- * unrecog    | 500/CONNECT | 500/GREET | 500/MAIL  | 500/RCPT     | ---/DATA_HDR  | ---/DATA_BODY | 500/QUIT
- * quit       | 503/CONNECT | 503/GREET | 503/MAIL  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 250/CONNECT
- * blank_line | 503/CONNECT | 503/GREET | 503/MAIL  | 503/RCPT     | ---/DATA_BODY | ---/DATA_BODY | 503/QUIT
- * rset       | 250/GREET   | 250/GREET | 250/GREET | 250/GREET    | 250/GREET     | 250/GREET     | 250/GREET
- * vrfy       | 252/CONNECT | 252/GREET | 252/MAIL  | 252/RCPT     | 252/DATA_HDR  | 252/DATA_BODY | 252/QUIT
- * expn       | 252/CONNECT | 252/GREET | 252/MAIL  | 252/RCPT     | 252/DATA_HDR  | 252/DATA_BODY | 252/QUIT
- * help       | 211/CONNECT | 211/GREET | 211/MAIL  | 211/RCPT     | 211/DATA_HDR  | 211/DATA_BODY | 211/QUIT
- * noop       | 250/CONNECT | 250/GREET | 250/MAIL  | 250/RCPT     | 250|DATA_HDR  | 250/DATA_BODY | 250/QUIT
- * 
- */ -public class SmtpRequest { - /** - * SMTP action received from client. - */ - private final SmtpActionType action; - /** - * Current state of the SMTP state table. - */ - private final SmtpState state; - /** - * Additional information passed from the client with the SMTP action. - */ - private final String params; - - /** - * Create a new SMTP client request. - * - * @param actionType type of action/command - * @param params remainder of command line once command is removed - * @param state current SMTP server state - */ - public SmtpRequest(final SmtpActionType actionType, final String params, final SmtpState state) { - this.action = actionType; - this.state = state; - this.params = params; - } - - /** - * Execute the SMTP request returning a response. This method models the state transition table for the SMTP server. - * - * @return reponse to the request - */ - public SmtpResponse execute() { - SmtpResponse response = null; - if (action.isStateless()) { - if (SmtpActionType.EXPN == action || SmtpActionType.VRFY == action) { - response = new SmtpResponse(252, "Not supported", this.state); - } else if (SmtpActionType.HELP == action) { - response = new SmtpResponse(211, "No help available", this.state); - } else if (SmtpActionType.NOOP == action) { - response = new SmtpResponse(250, "OK", this.state); - } else if (SmtpActionType.VRFY == action) { - response = new SmtpResponse(252, "Not supported", this.state); - } else if (SmtpActionType.RSET == action) { - response = new SmtpResponse(250, "OK", SmtpState.GREET); - } else { - response = new SmtpResponse(500, "Command not recognized", this.state); - } - } else { // Stateful commands - if (SmtpActionType.CONNECT == action) { - if (SmtpState.CONNECT == state) { - response = new SmtpResponse(220, "localhost Dumbster SMTP service ready", SmtpState.GREET); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else if (SmtpActionType.EHLO == action) { - if (SmtpState.GREET == state) { - response = new SmtpResponse(250, "OK", SmtpState.MAIL); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else if (SmtpActionType.MAIL == action) { - if (SmtpState.MAIL == state || SmtpState.QUIT == state) { - response = new SmtpResponse(250, "OK", SmtpState.RCPT); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else if (SmtpActionType.RCPT == action) { - if (SmtpState.RCPT == state) { - response = new SmtpResponse(250, "OK", this.state); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else if (SmtpActionType.DATA == action) { - if (SmtpState.RCPT == state) { - response = new SmtpResponse(354, "Start mail input; end with .", SmtpState.DATA_HDR); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else if (SmtpActionType.UNRECOG == action) { - if (SmtpState.DATA_HDR == state || SmtpState.DATA_BODY == state) { - response = new SmtpResponse(-1, Strings.EMPTY, this.state); - } else { - response = new SmtpResponse(500, "Command not recognized", this.state); - } - } else if (SmtpActionType.DATA_END == action) { - if (SmtpState.DATA_HDR == state || SmtpState.DATA_BODY == state) { - response = new SmtpResponse(250, "OK", SmtpState.QUIT); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else if (SmtpActionType.BLANK_LINE == action) { - if (SmtpState.DATA_HDR == state) { - response = new SmtpResponse(-1, Strings.EMPTY, SmtpState.DATA_BODY); - } else if (SmtpState.DATA_BODY == state) { - response = new SmtpResponse(-1, Strings.EMPTY, this.state); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else if (SmtpActionType.QUIT == action) { - if (SmtpState.QUIT == state) { - response = new SmtpResponse(221, "localhost Dumbster service closing transmission channel", - SmtpState.CONNECT); - } else { - response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); - } - } else { - response = new SmtpResponse(500, "Command not recognized", this.state); - } - } - return response; - } - - /** - * Create an SMTP request object given a line of the input stream from the client and the current internal state. - * - * @param s line of input - * @param state current state - * @return a populated SmtpRequest object - */ - public static SmtpRequest createRequest(final String s, final SmtpState state) { - SmtpActionType action = null; - String params = null; - - if (state == SmtpState.DATA_HDR) { - if (s.equals(".")) { - action = SmtpActionType.DATA_END; - } else if (s.length() < 1) { - action = SmtpActionType.BLANK_LINE; - } else { - action = SmtpActionType.UNRECOG; - params = s; - } - } else if (state == SmtpState.DATA_BODY) { - if (s.equals(".")) { - action = SmtpActionType.DATA_END; - } else { - action = SmtpActionType.UNRECOG; - if (s.length() < 1) { - params = "\n"; - } else { - params = s; - } - } - } else { - final String su = s.toUpperCase(); - if (su.startsWith("EHLO ") || su.startsWith("HELO")) { - action = SmtpActionType.EHLO; - params = s.substring(5); - } else if (su.startsWith("MAIL FROM:")) { - action = SmtpActionType.MAIL; - params = s.substring(10); - } else if (su.startsWith("RCPT TO:")) { - action = SmtpActionType.RCPT; - params = s.substring(8); - } else if (su.startsWith("DATA")) { - action = SmtpActionType.DATA; - } else if (su.startsWith("QUIT")) { - action = SmtpActionType.QUIT; - } else if (su.startsWith("RSET")) { - action = SmtpActionType.RSET; - } else if (su.startsWith("NOOP")) { - action = SmtpActionType.NOOP; - } else if (su.startsWith("EXPN")) { - action = SmtpActionType.EXPN; - } else if (su.startsWith("VRFY")) { - action = SmtpActionType.VRFY; - } else if (su.startsWith("HELP")) { - action = SmtpActionType.HELP; - } else { - action = SmtpActionType.UNRECOG; - } - } - - final SmtpRequest req = new SmtpRequest(action, params, state); - return req; - } - - /** - * Get the parameters of this request (remainder of command line once the command is removed. - * - * @return parameters - */ - public String getParams() { - return params; - } -} +/* + * 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.dumbster.smtp; + +import org.apache.logging.log4j.util.Strings; + +/** + * Contains an SMTP client request. Handles state transitions using the following state transition table. + *
+ * -----------+-------------------------------------------------------------------------------------------------
+ * |                                 State
+ * Action    +-------------+-----------+-----------+--------------+---------------+---------------+------------
+ * | CONNECT     | GREET     | MAIL      | RCPT         | DATA_HDR      | DATA_BODY     | QUIT
+ * -----------+-------------+-----------+-----------+--------------+---------------+---------------+------------
+ * connect    | 220/GREET   | 503/GREET | 503/MAIL  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
+ * ehlo       | 503/CONNECT | 250/MAIL  | 503/MAIL  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
+ * mail       | 503/CONNECT | 503/GREET | 250/RCPT  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 250/RCPT
+ * rcpt       | 503/CONNECT | 503/GREET | 503/MAIL  | 250/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
+ * data       | 503/CONNECT | 503/GREET | 503/MAIL  | 354/DATA_HDR | 503/DATA_HDR  | 503/DATA_BODY | 503/QUIT
+ * data_end   | 503/CONNECT | 503/GREET | 503/MAIL  | 503/RCPT     | 250/QUIT      | 250/QUIT      | 503/QUIT
+ * unrecog    | 500/CONNECT | 500/GREET | 500/MAIL  | 500/RCPT     | ---/DATA_HDR  | ---/DATA_BODY | 500/QUIT
+ * quit       | 503/CONNECT | 503/GREET | 503/MAIL  | 503/RCPT     | 503/DATA_HDR  | 503/DATA_BODY | 250/CONNECT
+ * blank_line | 503/CONNECT | 503/GREET | 503/MAIL  | 503/RCPT     | ---/DATA_BODY | ---/DATA_BODY | 503/QUIT
+ * rset       | 250/GREET   | 250/GREET | 250/GREET | 250/GREET    | 250/GREET     | 250/GREET     | 250/GREET
+ * vrfy       | 252/CONNECT | 252/GREET | 252/MAIL  | 252/RCPT     | 252/DATA_HDR  | 252/DATA_BODY | 252/QUIT
+ * expn       | 252/CONNECT | 252/GREET | 252/MAIL  | 252/RCPT     | 252/DATA_HDR  | 252/DATA_BODY | 252/QUIT
+ * help       | 211/CONNECT | 211/GREET | 211/MAIL  | 211/RCPT     | 211/DATA_HDR  | 211/DATA_BODY | 211/QUIT
+ * noop       | 250/CONNECT | 250/GREET | 250/MAIL  | 250/RCPT     | 250|DATA_HDR  | 250/DATA_BODY | 250/QUIT
+ * 
+ */ +public class SmtpRequest { + /** + * SMTP action received from client. + */ + private final SmtpActionType action; + /** + * Current state of the SMTP state table. + */ + private final SmtpState state; + /** + * Additional information passed from the client with the SMTP action. + */ + private final String params; + + /** + * Create a new SMTP client request. + * + * @param actionType type of action/command + * @param params remainder of command line once command is removed + * @param state current SMTP server state + */ + public SmtpRequest(final SmtpActionType actionType, final String params, final SmtpState state) { + this.action = actionType; + this.state = state; + this.params = params; + } + + /** + * Execute the SMTP request returning a response. This method models the state transition table for the SMTP server. + * + * @return reponse to the request + */ + public SmtpResponse execute() { + SmtpResponse response = null; + if (action.isStateless()) { + if (SmtpActionType.EXPN == action || SmtpActionType.VRFY == action) { + response = new SmtpResponse(252, "Not supported", this.state); + } else if (SmtpActionType.HELP == action) { + response = new SmtpResponse(211, "No help available", this.state); + } else if (SmtpActionType.NOOP == action) { + response = new SmtpResponse(250, "OK", this.state); + } else if (SmtpActionType.VRFY == action) { + response = new SmtpResponse(252, "Not supported", this.state); + } else if (SmtpActionType.RSET == action) { + response = new SmtpResponse(250, "OK", SmtpState.GREET); + } else { + response = new SmtpResponse(500, "Command not recognized", this.state); + } + } else { // Stateful commands + if (SmtpActionType.CONNECT == action) { + if (SmtpState.CONNECT == state) { + response = new SmtpResponse(220, "localhost Dumbster SMTP service ready", SmtpState.GREET); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else if (SmtpActionType.EHLO == action) { + if (SmtpState.GREET == state) { + response = new SmtpResponse(250, "OK", SmtpState.MAIL); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else if (SmtpActionType.MAIL == action) { + if (SmtpState.MAIL == state || SmtpState.QUIT == state) { + response = new SmtpResponse(250, "OK", SmtpState.RCPT); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else if (SmtpActionType.RCPT == action) { + if (SmtpState.RCPT == state) { + response = new SmtpResponse(250, "OK", this.state); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else if (SmtpActionType.DATA == action) { + if (SmtpState.RCPT == state) { + response = new SmtpResponse(354, "Start mail input; end with .", SmtpState.DATA_HDR); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else if (SmtpActionType.UNRECOG == action) { + if (SmtpState.DATA_HDR == state || SmtpState.DATA_BODY == state) { + response = new SmtpResponse(-1, Strings.EMPTY, this.state); + } else { + response = new SmtpResponse(500, "Command not recognized", this.state); + } + } else if (SmtpActionType.DATA_END == action) { + if (SmtpState.DATA_HDR == state || SmtpState.DATA_BODY == state) { + response = new SmtpResponse(250, "OK", SmtpState.QUIT); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else if (SmtpActionType.BLANK_LINE == action) { + if (SmtpState.DATA_HDR == state) { + response = new SmtpResponse(-1, Strings.EMPTY, SmtpState.DATA_BODY); + } else if (SmtpState.DATA_BODY == state) { + response = new SmtpResponse(-1, Strings.EMPTY, this.state); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else if (SmtpActionType.QUIT == action) { + if (SmtpState.QUIT == state) { + response = new SmtpResponse(221, "localhost Dumbster service closing transmission channel", + SmtpState.CONNECT); + } else { + response = new SmtpResponse(503, "Bad sequence of commands: " + action, this.state); + } + } else { + response = new SmtpResponse(500, "Command not recognized", this.state); + } + } + return response; + } + + /** + * Create an SMTP request object given a line of the input stream from the client and the current internal state. + * + * @param s line of input + * @param state current state + * @return a populated SmtpRequest object + */ + public static SmtpRequest createRequest(final String s, final SmtpState state) { + SmtpActionType action = null; + String params = null; + + if (state == SmtpState.DATA_HDR) { + if (s.equals(".")) { + action = SmtpActionType.DATA_END; + } else if (s.length() < 1) { + action = SmtpActionType.BLANK_LINE; + } else { + action = SmtpActionType.UNRECOG; + params = s; + } + } else if (state == SmtpState.DATA_BODY) { + if (s.equals(".")) { + action = SmtpActionType.DATA_END; + } else { + action = SmtpActionType.UNRECOG; + if (s.length() < 1) { + params = "\n"; + } else { + params = s; + } + } + } else { + final String su = s.toUpperCase(); + if (su.startsWith("EHLO ") || su.startsWith("HELO")) { + action = SmtpActionType.EHLO; + params = s.substring(5); + } else if (su.startsWith("MAIL FROM:")) { + action = SmtpActionType.MAIL; + params = s.substring(10); + } else if (su.startsWith("RCPT TO:")) { + action = SmtpActionType.RCPT; + params = s.substring(8); + } else if (su.startsWith("DATA")) { + action = SmtpActionType.DATA; + } else if (su.startsWith("QUIT")) { + action = SmtpActionType.QUIT; + } else if (su.startsWith("RSET")) { + action = SmtpActionType.RSET; + } else if (su.startsWith("NOOP")) { + action = SmtpActionType.NOOP; + } else if (su.startsWith("EXPN")) { + action = SmtpActionType.EXPN; + } else if (su.startsWith("VRFY")) { + action = SmtpActionType.VRFY; + } else if (su.startsWith("HELP")) { + action = SmtpActionType.HELP; + } else { + action = SmtpActionType.UNRECOG; + } + } + + final SmtpRequest req = new SmtpRequest(action, params, state); + return req; + } + + /** + * Get the parameters of this request (remainder of command line once the command is removed. + * + * @return parameters + */ + public String getParams() { + return params; + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpResponse.java b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpResponse.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpResponse.java rename to log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpResponse.java index 7023f1c39f2..8b72ba78ba5 100644 --- a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpResponse.java +++ b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpResponse.java @@ -1,75 +1,75 @@ -/* - * 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.dumbster.smtp; - -/** - * SMTP response container. - */ -public class SmtpResponse { - /** - * Response code - see RFC-2821. - */ - private final int code; - /** - * Response message. - */ - private final String message; - /** - * New state of the SMTP server once the request has been executed. - */ - private final SmtpState nextState; - - /** - * Constructor. - * - * @param code response code - * @param message response message - * @param next next state of the SMTP server - */ - public SmtpResponse(final int code, final String message, final SmtpState next) { - this.code = code; - this.message = message; - this.nextState = next; - } - - /** - * Get the response code. - * - * @return response code - */ - public int getCode() { - return code; - } - - /** - * Get the response message. - * - * @return response message - */ - public String getMessage() { - return message; - } - - /** - * Get the next SMTP server state. - * - * @return state - */ - public SmtpState getNextState() { - return nextState; - } -} +/* + * 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.dumbster.smtp; + +/** + * SMTP response container. + */ +public class SmtpResponse { + /** + * Response code - see RFC-2821. + */ + private final int code; + /** + * Response message. + */ + private final String message; + /** + * New state of the SMTP server once the request has been executed. + */ + private final SmtpState nextState; + + /** + * Constructor. + * + * @param code response code + * @param message response message + * @param next next state of the SMTP server + */ + public SmtpResponse(final int code, final String message, final SmtpState next) { + this.code = code; + this.message = message; + this.nextState = next; + } + + /** + * Get the response code. + * + * @return response code + */ + public int getCode() { + return code; + } + + /** + * Get the response message. + * + * @return response message + */ + public String getMessage() { + return message; + } + + /** + * Get the next SMTP server state. + * + * @return state + */ + public SmtpState getNextState() { + return nextState; + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpState.java b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpState.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpState.java rename to log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpState.java index bd94b4d1431..3c8354541ea 100644 --- a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/SmtpState.java +++ b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/SmtpState.java @@ -1,121 +1,121 @@ -/* - * 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.dumbster.smtp; - -/** - * SMTP server state. - */ -public class SmtpState { - /** - * Internal representation of the state. - */ - private final byte value; - - /** - * Internal representation of the CONNECT state. - */ - private static final byte CONNECT_BYTE = (byte) 1; - /** - * Internal representation of the GREET state. - */ - private static final byte GREET_BYTE = (byte) 2; - /** - * Internal representation of the MAIL state. - */ - private static final byte MAIL_BYTE = (byte) 3; - /** - * Internal representation of the RCPT state. - */ - private static final byte RCPT_BYTE = (byte) 4; - /** - * Internal representation of the DATA_HEADER state. - */ - private static final byte DATA_HEADER_BYTE = (byte) 5; - /** - * Internal representation of the DATA_BODY state. - */ - private static final byte DATA_BODY_BYTE = (byte) 6; - /** - * Internal representation of the QUIT state. - */ - private static final byte QUIT_BYTE = (byte) 7; - - /** - * CONNECT state: waiting for a client connection. - */ - public static final SmtpState CONNECT = new SmtpState(CONNECT_BYTE); - /** - * GREET state: wating for a ELHO message. - */ - public static final SmtpState GREET = new SmtpState(GREET_BYTE); - /** - * MAIL state: waiting for the MAIL FROM: command. - */ - public static final SmtpState MAIL = new SmtpState(MAIL_BYTE); - /** - * RCPT state: waiting for a RCPT <email address> command. - */ - public static final SmtpState RCPT = new SmtpState(RCPT_BYTE); - /** - * Waiting for headers. - */ - public static final SmtpState DATA_HDR = new SmtpState(DATA_HEADER_BYTE); - /** - * Processing body text. - */ - public static final SmtpState DATA_BODY = new SmtpState(DATA_BODY_BYTE); - /** - * End of client transmission. - */ - public static final SmtpState QUIT = new SmtpState(QUIT_BYTE); - - /** - * Create a new SmtpState object. Private to ensure that only valid states can be created. - * - * @param value one of the _BYTE values. - */ - private SmtpState(final byte value) { - this.value = value; - } - - /** - * String representation of this SmtpState. - * - * @return a String - */ - @Override - public String toString() { - switch (value) { - case CONNECT_BYTE: - return "CONNECT"; - case GREET_BYTE: - return "GREET"; - case MAIL_BYTE: - return "MAIL"; - case RCPT_BYTE: - return "RCPT"; - case DATA_HEADER_BYTE: - return "DATA_HDR"; - case DATA_BODY_BYTE: - return "DATA_BODY"; - case QUIT_BYTE: - return "QUIT"; - default: - return "Unknown"; - } - } -} +/* + * 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.dumbster.smtp; + +/** + * SMTP server state. + */ +public class SmtpState { + /** + * Internal representation of the state. + */ + private final byte value; + + /** + * Internal representation of the CONNECT state. + */ + private static final byte CONNECT_BYTE = (byte) 1; + /** + * Internal representation of the GREET state. + */ + private static final byte GREET_BYTE = (byte) 2; + /** + * Internal representation of the MAIL state. + */ + private static final byte MAIL_BYTE = (byte) 3; + /** + * Internal representation of the RCPT state. + */ + private static final byte RCPT_BYTE = (byte) 4; + /** + * Internal representation of the DATA_HEADER state. + */ + private static final byte DATA_HEADER_BYTE = (byte) 5; + /** + * Internal representation of the DATA_BODY state. + */ + private static final byte DATA_BODY_BYTE = (byte) 6; + /** + * Internal representation of the QUIT state. + */ + private static final byte QUIT_BYTE = (byte) 7; + + /** + * CONNECT state: waiting for a client connection. + */ + public static final SmtpState CONNECT = new SmtpState(CONNECT_BYTE); + /** + * GREET state: wating for a ELHO message. + */ + public static final SmtpState GREET = new SmtpState(GREET_BYTE); + /** + * MAIL state: waiting for the MAIL FROM: command. + */ + public static final SmtpState MAIL = new SmtpState(MAIL_BYTE); + /** + * RCPT state: waiting for a RCPT <email address> command. + */ + public static final SmtpState RCPT = new SmtpState(RCPT_BYTE); + /** + * Waiting for headers. + */ + public static final SmtpState DATA_HDR = new SmtpState(DATA_HEADER_BYTE); + /** + * Processing body text. + */ + public static final SmtpState DATA_BODY = new SmtpState(DATA_BODY_BYTE); + /** + * End of client transmission. + */ + public static final SmtpState QUIT = new SmtpState(QUIT_BYTE); + + /** + * Create a new SmtpState object. Private to ensure that only valid states can be created. + * + * @param value one of the _BYTE values. + */ + private SmtpState(final byte value) { + this.value = value; + } + + /** + * String representation of this SmtpState. + * + * @return a String + */ + @Override + public String toString() { + switch (value) { + case CONNECT_BYTE: + return "CONNECT"; + case GREET_BYTE: + return "GREET"; + case MAIL_BYTE: + return "MAIL"; + case RCPT_BYTE: + return "RCPT"; + case DATA_HEADER_BYTE: + return "DATA_HDR"; + case DATA_BODY_BYTE: + return "DATA_BODY"; + case QUIT_BYTE: + return "QUIT"; + default: + return "Unknown"; + } + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/dumbster/smtp/readme.txt b/log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/readme.txt similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/dumbster/smtp/readme.txt rename to log4j-smtp/src/test/java/org/apache/logging/dumbster/smtp/readme.txt diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java b/log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java rename to log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java b/log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java rename to log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java diff --git a/log4j-smtp/src/test/resources/SmtpAppenderAsyncTest.xml b/log4j-smtp/src/test/resources/SmtpAppenderAsyncTest.xml new file mode 100644 index 00000000000..1939ddd2e96 --- /dev/null +++ b/log4j-smtp/src/test/resources/SmtpAppenderAsyncTest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 86fa736dcc2..1d21f404c25 100644 --- a/pom.xml +++ b/pom.xml @@ -1348,6 +1348,7 @@ log4j-jul log4j-liquibase log4j-appserver + log4j-smtp log4j-osgi diff --git a/src/changes/changes.xml b/src/changes/changes.xml index fd8dbaf2cd8..cf7307a1d54 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -170,6 +170,9 @@ Split off Kafka support into a new module log4j-kafka. + + Split off SMTP support into a new module log4j-smtp. + diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index 9ca133d33cd..f4bba1a3fd9 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -4538,6 +4538,10 @@ public class JpaLogEntity extends AbstractLogEventWrapperEntity { +

+ As of Log4j 2.11.0, Simple Mail Transfer Protocol (SMTP) support has moved from the existing module + logj-core to the new module log4j-smtp. +

Sends an e-mail when a specific logging event occurs, typically on errors or fatal errors.

From 3f8ae50345731feca242b3a6c36d1a950c81dd69 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 28 Jan 2018 16:50:39 -0700 Subject: [PATCH 0012/2347] [LOG4J2-2231] Move CSV layout from log4j-core to a new module log4j-csv. Running 'mvn clean install' passes. --- log4j-bom/pom.xml | 6 + log4j-core/pom.xml | 6 - log4j-csv/pom.xml | 176 ++++++++++++++++++ .../log4j/core/layout/AbstractCsvLayout.java | 0 .../log4j/core/layout/CsvLogEventLayout.java | 0 .../log4j/core/layout/CsvParameterLayout.java | 0 log4j-csv/src/site/manual/index.md | 33 ++++ log4j-csv/src/site/site.xml | 52 ++++++ ...svJsonParameterLayoutFileAppenderTest.java | 7 +- .../core/layout/CsvLogEventLayoutTest.java | 0 .../CsvParameterLayoutAllAsyncTest.java | 0 .../core/layout/CsvParameterLayoutTest.java | 0 .../test/resources/csvParamsMixedAsync.xml | 0 .../src/test/resources/csvParamsSync.xml | 0 .../resources/log4j-cvs-json-parameter.xml | 0 pom.xml | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/layouts.xml.vm | 3 + 18 files changed, 277 insertions(+), 10 deletions(-) create mode 100644 log4j-csv/pom.xml rename {log4j-core => log4j-csv}/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java (100%) rename {log4j-core => log4j-csv}/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java (100%) rename {log4j-core => log4j-csv}/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java (100%) create mode 100644 log4j-csv/src/site/manual/index.md create mode 100644 log4j-csv/src/site/site.xml rename {log4j-core => log4j-csv}/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java (95%) rename {log4j-core => log4j-csv}/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java (100%) rename {log4j-core => log4j-csv}/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java (100%) rename {log4j-core => log4j-csv}/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java (100%) rename {log4j-core => log4j-csv}/src/test/resources/csvParamsMixedAsync.xml (100%) rename {log4j-core => log4j-csv}/src/test/resources/csvParamsSync.xml (100%) rename {log4j-core => log4j-csv}/src/test/resources/log4j-cvs-json-parameter.xml (100%) diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index b3554f1be8d..b8ea992c0a8 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -96,6 +96,12 @@ log4j-couchdb ${project.version} + + + org.apache.logging.log4j + log4j-csv + ${project.version} + org.apache.logging.log4j diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index d1f3f108f68..fab1712fe46 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -120,12 +120,6 @@ commons-compress true - - - org.apache.commons - commons-csv - true - com.beust diff --git a/log4j-csv/pom.xml b/log4j-csv/pom.xml new file mode 100644 index 00000000000..3876d51e7b6 --- /dev/null +++ b/log4j-csv/pom.xml @@ -0,0 +1,176 @@ + + + + + + org.apache.logging.log4j + log4j + 2.10.1-SNAPSHOT + + 4.0.0 + + log4j-csv + Apache Log4j CSV + + Apache Log4j CSV Layout. + + + ${basedir}/.. + Log4j CSV Documentation + /log4j-csv + org.apache.logging.log4j.csv + + + + + org.apache.logging.log4j + log4j-core + + + org.apache.commons + commons-csv + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + + com.lmax + disruptor + test + + + + commons-io + commons-io + test + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.core.appender.mom.jeromq + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]>
+ + false + true +
+ + + non-aggregate + + javadoc + + + +
+ + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + +
+
+
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java rename to log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java rename to log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java similarity index 100% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java rename to log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java diff --git a/log4j-csv/src/site/manual/index.md b/log4j-csv/src/site/manual/index.md new file mode 100644 index 00000000000..66fe24fe304 --- /dev/null +++ b/log4j-csv/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j ZeroMQ using JeroMQ module + +As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires the jeromq JAR. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-csv/src/site/site.xml b/log4j-csv/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-csv/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java similarity index 95% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java index 2443d5b0209..1dd7da76f3b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java +++ b/log4j-csv/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java @@ -22,6 +22,7 @@ import java.nio.charset.Charset; import java.util.List; +import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.categories.Layouts; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; @@ -32,8 +33,6 @@ import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; -import com.google.common.io.Files; - /** * Tests https://issues.apache.org/jira/browse/LOG4J2-1502 */ @@ -54,7 +53,7 @@ public void testNoNulCharacters(final String message, final String expected) thr logger.error("log:", message); loggerContext.stop(); final File file = new File(FILE_PATH); - final byte[] contents = Files.toByteArray(file); + final byte[] contents = FileUtils.readFileToByteArray(file); int count0s = 0; final StringBuilder sb = new StringBuilder(); for (int i = 0; i < contents.length; i++) { @@ -66,7 +65,7 @@ public void testNoNulCharacters(final String message, final String expected) thr } } Assert.assertEquals("File contains " + count0s + " 0x00 byte at indices " + sb, 0, count0s); - final List readLines = Files.readLines(file, Charset.defaultCharset()); + final List readLines = FileUtils.readLines(file, Charset.defaultCharset()); final String actual = readLines.get(0); // Assert.assertTrue(actual, actual.contains(message)); Assert.assertEquals(actual, expected, actual); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java diff --git a/log4j-core/src/test/resources/csvParamsMixedAsync.xml b/log4j-csv/src/test/resources/csvParamsMixedAsync.xml similarity index 100% rename from log4j-core/src/test/resources/csvParamsMixedAsync.xml rename to log4j-csv/src/test/resources/csvParamsMixedAsync.xml diff --git a/log4j-core/src/test/resources/csvParamsSync.xml b/log4j-csv/src/test/resources/csvParamsSync.xml similarity index 100% rename from log4j-core/src/test/resources/csvParamsSync.xml rename to log4j-csv/src/test/resources/csvParamsSync.xml diff --git a/log4j-core/src/test/resources/log4j-cvs-json-parameter.xml b/log4j-csv/src/test/resources/log4j-cvs-json-parameter.xml similarity index 100% rename from log4j-core/src/test/resources/log4j-cvs-json-parameter.xml rename to log4j-csv/src/test/resources/log4j-cvs-json-parameter.xml diff --git a/pom.xml b/pom.xml index 1d21f404c25..00b8bda59c6 100644 --- a/pom.xml +++ b/pom.xml @@ -1329,6 +1329,7 @@ log4j-slf4j-impl log4j-to-slf4j log4j-jcl + log4j-csv log4j-flume-ng log4j-taglib log4j-jmx-gui diff --git a/src/changes/changes.xml b/src/changes/changes.xml index cf7307a1d54..21e123ecf72 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -173,6 +173,9 @@ Split off SMTP support into a new module log4j-smtp. + + Move CSV layout from log4j-core to a new module log4j-csv. + diff --git a/src/site/xdoc/manual/layouts.xml.vm b/src/site/xdoc/manual/layouts.xml.vm index dffb00b100b..1f404273ece 100644 --- a/src/site/xdoc/manual/layouts.xml.vm +++ b/src/site/xdoc/manual/layouts.xml.vm @@ -56,6 +56,9 @@

+

+ As of Log4j 2.11.0, CSV support has moved from the existing module logj-core to the new module log4j-csv. +

This layout creates Comma Separated Value (CSV) records and requires Apache Commons CSV 1.4. From 2b5ec72851e2ab55bacd7e63cfe50f0488d343c1 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 06:53:43 -0700 Subject: [PATCH 0013/2347] Rename Java packages to fit the Java 9 naming module rules. List changes in release notes. --- RELEASE-NOTES.md | 70 +++++++++++++++++++ ...AbstractDriverManagerConnectionSource.java | 2 +- .../appender/db/jdbc/JdbcH2TestHelper.java | 6 +- .../builder/CustomConfigurationFactory.java | 2 +- .../layout/AbstractCsvLayout.java | 4 +- .../layout/CsvLogEventLayout.java | 2 +- .../layout/CsvParameterLayout.java | 2 +- ...svJsonParameterLayoutFileAppenderTest.java | 2 +- .../layout/CsvLogEventLayoutTest.java | 4 +- .../CsvParameterLayoutAllAsyncTest.java | 4 +- .../layout/CsvParameterLayoutTest.java | 4 +- log4j-jdbc-dbcp2/pom.xml | 2 +- .../PoolingDriverConnectionSource.java | 4 +- .../PoolingDriverConnectionSourceTest.java | 4 +- .../appender}/JeroMqAppender.java | 2 +- .../appender}/JeroMqManager.java | 2 +- .../appender}/JeroMqAppenderTest.java | 4 +- .../appender}/JeroMqTestClient.java | 2 +- .../appender/db/jpa/log4j2-h2-jpa-basic.xml | 38 ---------- .../db/jpa/log4j2-hsqldb-jpa-basic.xml | 38 ---------- .../AbstractLogEventWrapperEntity.java | 8 +-- .../appender}/BasicLogEventEntity.java | 12 ++-- .../db/jpa => jpa/appender}/JpaAppender.java | 2 +- .../appender}/JpaDatabaseManager.java | 2 +- .../db/jpa => jpa/appender}/package-info.java | 2 +- .../ContextDataAttributeConverter.java | 2 +- .../ContextDataJsonAttributeConverter.java | 2 +- .../ContextMapAttributeConverter.java | 2 +- .../ContextMapJsonAttributeConverter.java | 2 +- .../ContextStackAttributeConverter.java | 2 +- .../ContextStackJsonAttributeConverter.java | 2 +- .../converter/InstantAttributeConverter.java | 10 ++- .../converter/LevelAttributeConverter.java | 2 +- .../converter/MarkerAttributeConverter.java | 2 +- .../converter/MessageAttributeConverter.java | 2 +- .../StackTraceElementAttributeConverter.java | 2 +- .../ThrowableAttributeConverter.java | 2 +- .../db => }/jpa/converter/package-info.java | 10 +-- .../appender}/AbstractJpaAppenderTest.java | 7 +- .../appender}/JpaH2AppenderTest.java | 2 +- .../appender}/JpaHsqldbAppenderTest.java | 3 +- .../appender}/LogEventEntityTest.java | 5 +- .../jpa => jpa/appender}/TestBaseEntity.java | 13 ++-- .../jpa => jpa/appender}/TestBasicEntity.java | 7 +- .../ContextDataAttributeConverterTest.java | 3 +- ...ContextDataJsonAttributeConverterTest.java | 3 +- .../ContextMapAttributeConverterTest.java | 3 +- .../ContextMapJsonAttributeConverterTest.java | 3 +- .../ContextStackAttributeConverterTest.java | 3 +- ...ontextStackJsonAttributeConverterTest.java | 3 +- .../InstantAttributeConverterTest.java | 10 +-- .../MarkerAttributeConverterTest.java | 3 +- .../MessageAttributeConverterTest.java | 3 +- ...ackTraceElementAttributeConverterTest.java | 3 +- .../ThrowableAttributeConverterTest.java | 3 +- .../test/resources/META-INF/persistence.xml | 40 +++++------ .../appender/db/jpa/log4j2-h2-jpa-basic.xml | 38 ---------- .../db/jpa/log4j2-hsqldb-jpa-basic.xml | 38 ---------- .../jpa/appender}/log4j2-h2-jpa-base.xml | 4 +- .../appender/log4j2-h2-jpa-basic.xml} | 4 +- .../appender}/log4j2-hsqldb-jpa-base.xml | 4 +- .../jpa/appender/log4j2-hsqldb-jpa-basic.xml | 4 +- .../DefaultKafkaProducerFactory.java | 2 +- .../appender}/KafkaAppender.java | 2 +- .../appender}/KafkaManager.java | 2 +- .../appender}/KafkaProducerFactory.java | 2 +- .../KafkaAppenderCloseTimeoutTest.java | 4 +- .../appender}/KafkaAppenderTest.java | 4 +- .../builder/ConfigurationAssemblerTest.java | 13 ++-- .../builder/ConfigurationBuilderTest.java | 11 ++- .../builder/CustomConfigurationFactory.java | 2 +- .../log4j/perf/jmh/JpaAppenderBenchmark.java | 2 +- .../log4j/perf/jmh/jpa/TestBasicEntity.java | 4 +- .../net => smtp}/MimeMessageBuilder.java | 2 +- .../{core => smtp}/appender/SmtpAppender.java | 4 +- .../net => smtp/appender}/SmtpManager.java | 3 +- .../appender/SmtpAppenderAsyncTest.java | 2 +- .../appender/SmtpAppenderTest.java | 5 +- 78 files changed, 246 insertions(+), 293 deletions(-) rename log4j-csv/src/main/java/org/apache/logging/log4j/{core => csv}/layout/AbstractCsvLayout.java (94%) rename log4j-csv/src/main/java/org/apache/logging/log4j/{core => csv}/layout/CsvLogEventLayout.java (99%) rename log4j-csv/src/main/java/org/apache/logging/log4j/{core => csv}/layout/CsvParameterLayout.java (98%) rename log4j-csv/src/test/java/org/apache/logging/log4j/{core => csv}/appender/CsvJsonParameterLayoutFileAppenderTest.java (98%) rename log4j-csv/src/test/java/org/apache/logging/log4j/{core => csv}/layout/CsvLogEventLayoutTest.java (97%) rename log4j-csv/src/test/java/org/apache/logging/log4j/{core => csv}/layout/CsvParameterLayoutAllAsyncTest.java (94%) rename log4j-csv/src/test/java/org/apache/logging/log4j/{core => csv}/layout/CsvParameterLayoutTest.java (97%) rename log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/{core/appender/db/jdbc => dbcp2/appender}/PoolingDriverConnectionSource.java (96%) rename log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/{core/appender/db/jdbc => db/jdbc/appender}/PoolingDriverConnectionSourceTest.java (95%) rename log4j-jeromq/src/main/java/org/apache/logging/log4j/{core/appender/mom/jeromq => jeromq/appender}/JeroMqAppender.java (99%) rename log4j-jeromq/src/main/java/org/apache/logging/log4j/{core/appender/mom/jeromq => jeromq/appender}/JeroMqManager.java (99%) rename log4j-jeromq/src/test/java/org/apache/logging/log4j/{core/appender/mom/jeromq => jeromq/appender}/JeroMqAppenderTest.java (97%) rename log4j-jeromq/src/test/java/org/apache/logging/log4j/{core/appender/mom/jeromq => jeromq/appender}/JeroMqTestClient.java (97%) delete mode 100644 log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml delete mode 100644 log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/AbstractLogEventWrapperEntity.java (96%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/BasicLogEventEntity.java (94%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/JpaAppender.java (99%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/JpaDatabaseManager.java (99%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/package-info.java (95%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextDataAttributeConverter.java (96%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextDataJsonAttributeConverter.java (98%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextMapAttributeConverter.java (96%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextMapJsonAttributeConverter.java (97%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextStackAttributeConverter.java (97%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextStackJsonAttributeConverter.java (97%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/InstantAttributeConverter.java (91%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/LevelAttributeConverter.java (96%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/MarkerAttributeConverter.java (96%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/MessageAttributeConverter.java (96%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/StackTraceElementAttributeConverter.java (97%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ThrowableAttributeConverter.java (99%) rename log4j-jpa/src/main/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/package-info.java (68%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/AbstractJpaAppenderTest.java (97%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/JpaH2AppenderTest.java (97%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/JpaHsqldbAppenderTest.java (97%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/LogEventEntityTest.java (95%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/TestBaseEntity.java (91%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/TestBasicEntity.java (88%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextDataAttributeConverterTest.java (95%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextDataJsonAttributeConverterTest.java (96%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextMapAttributeConverterTest.java (94%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextMapJsonAttributeConverterTest.java (95%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextStackAttributeConverterTest.java (95%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ContextStackJsonAttributeConverterTest.java (96%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/InstantAttributeConverterTest.java (91%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/MarkerAttributeConverterTest.java (96%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/MessageAttributeConverterTest.java (95%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/StackTraceElementAttributeConverterTest.java (98%) rename log4j-jpa/src/test/java/org/apache/logging/log4j/{core/appender/db => }/jpa/converter/ThrowableAttributeConverterTest.java (96%) delete mode 100644 log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml delete mode 100644 log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml rename {log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa => log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender}/log4j2-h2-jpa-base.xml (85%) rename log4j-jpa/src/test/resources/org/apache/logging/log4j/{core/appender/db/jpa/log4j2-h2-jpa-base.xml => jpa/appender/log4j2-h2-jpa-basic.xml} (85%) rename log4j-jpa/src/test/resources/org/apache/logging/log4j/{core/appender/db/jpa => jpa/appender}/log4j2-hsqldb-jpa-base.xml (85%) rename log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml => log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-hsqldb-jpa-basic.xml (85%) rename log4j-kafka/src/main/java/org/apache/logging/log4j/{core/appender/mom/kafka => kafka/appender}/DefaultKafkaProducerFactory.java (96%) rename log4j-kafka/src/main/java/org/apache/logging/log4j/{core/appender/mom/kafka => kafka/appender}/KafkaAppender.java (99%) rename log4j-kafka/src/main/java/org/apache/logging/log4j/{core/appender/mom/kafka => kafka/appender}/KafkaManager.java (98%) rename log4j-kafka/src/main/java/org/apache/logging/log4j/{core/appender/mom/kafka => kafka/appender}/KafkaProducerFactory.java (96%) rename log4j-kafka/src/test/java/org/apache/logging/log4j/{core/appender/mom/kafka => kafka/appender}/KafkaAppenderCloseTimeoutTest.java (93%) rename log4j-kafka/src/test/java/org/apache/logging/log4j/{core/appender/mom/kafka => kafka/appender}/KafkaAppenderTest.java (97%) rename log4j-kafka/src/test/java/org/apache/logging/log4j/{core/config => kafka}/builder/ConfigurationAssemblerTest.java (92%) rename log4j-kafka/src/test/java/org/apache/logging/log4j/{core/config => kafka}/builder/ConfigurationBuilderTest.java (95%) rename log4j-kafka/src/test/java/org/apache/logging/log4j/{core/config => kafka}/builder/CustomConfigurationFactory.java (98%) rename log4j-smtp/src/main/java/org/apache/logging/log4j/{core/net => smtp}/MimeMessageBuilder.java (98%) rename log4j-smtp/src/main/java/org/apache/logging/log4j/{core => smtp}/appender/SmtpAppender.java (98%) rename log4j-smtp/src/main/java/org/apache/logging/log4j/{core/net => smtp/appender}/SmtpManager.java (99%) rename log4j-smtp/src/test/java/org/apache/logging/log4j/{core => smtp}/appender/SmtpAppenderAsyncTest.java (98%) rename log4j-smtp/src/test/java/org/apache/logging/log4j/{core => smtp}/appender/SmtpAppenderTest.java (97%) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index fe5f8001863..4908ebb6f46 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,73 @@ +# Apache Log4j 2.11.0 Release Notes + +## List of Binary Compatibility Breaking Changes in log4j-core + +Log4j 2.11.0 moves code from `log4j-core` to several new Maven modules. Dependencies to other jars that used to be +optional in `log4j-core` are now required in the new modules. The code in these modules have been repackaged. + +These changes do not affect your configuration files. + +The new modules are: + +### log4j-cvs + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-cvs` + +* Old package: `org.apache.logging.log4j.core.layout` +* New package: `org.apache.logging.log4j.csv.layout` + +### log4j-jeromq + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-jeromq` + +* Old package: `org.apache.logging.log4j.core.appender.mom.jeromq` +* New package: `org.apache.logging.log4j.jeromq.appender` + +### log4j-jpa + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-jpa` + +* Old package 1: `org.apache.logging.log4j.core.appender.db.jpa` +* New package 1: `org.apache.logging.log4j.jpa.appender` + +* Old package 2: `org.apache.logging.log4j.core.appender.db.jpa.converter` +* New package 2: `org.apache.logging.log4j.jpa.converter` + +### log4j-kafka + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-kafka` + +* Old package: `org.apache.logging.log4j.core.appender.mom.kafka` +* New package: `org.apache.logging.log4j.kafka.appender` + +### log4j-mongodb2 + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-mongodb2` + +* Old package: `org.apache.logging.log4j.mongodb` +* New package: `org.apache.logging.log4j.mongodb2` + +### log4j-mongodb3 + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-mongodb3` + +* Old package: `org.apache.logging.log4j.mongodb` +* New package: `org.apache.logging.log4j.mongodb3` + +### log4j-smtp + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-smtp` + +* Old package: `org.apache.logging.log4j.core.appender` +* New package: `org.apache.logging.log4j.smtp.appender` + # Apache Log4j 2.10.0 Release Notes The Apache Log4j 2 team is pleased to announce the Log4j 2.10.0 release! diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractDriverManagerConnectionSource.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractDriverManagerConnectionSource.java index 77c4391b4e4..4f25442c3c2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractDriverManagerConnectionSource.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractDriverManagerConnectionSource.java @@ -63,7 +63,7 @@ public static class Builder> { private char[] userName; @SuppressWarnings("unchecked") - protected B asBuilder() { + public B asBuilder() { return (B) this; } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcH2TestHelper.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcH2TestHelper.java index 1bb1f37217e..7152f1141fc 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcH2TestHelper.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcH2TestHelper.java @@ -22,9 +22,9 @@ public class JdbcH2TestHelper { - static final String CONNECTION_STRING = "jdbc:h2:mem:Log4j"; - static final String USER_NAME = "sa"; - static final String PASSWORD = ""; + public static final String CONNECTION_STRING = "jdbc:h2:mem:Log4j"; + public static final String USER_NAME = "sa"; + public static final String PASSWORD = ""; public static ConnectionSource TEST_CONFIGURATION_SOURCE = new AbstractConnectionSource() { @Override diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java index c8ba5aed73e..c9a3a331e2b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java @@ -37,7 +37,7 @@ //@Order(50) public class CustomConfigurationFactory extends ConfigurationFactory { - static Configuration addTestFixtures(final String name, final ConfigurationBuilder builder) { + public static Configuration addTestFixtures(final String name, final ConfigurationBuilder builder) { builder.setConfigurationName(name); builder.setStatusLevel(Level.ERROR); builder.add(builder.newScriptFile("target/test-classes/scripts/filter.groovy").addIsWatched(true)); diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/AbstractCsvLayout.java similarity index 94% rename from log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java rename to log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/AbstractCsvLayout.java index e47b5e6f00c..f10191ded39 100644 --- a/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/AbstractCsvLayout.java +++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/AbstractCsvLayout.java @@ -14,13 +14,15 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.csv.layout; import java.nio.charset.Charset; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.QuoteMode; import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.layout.AbstractStringLayout; +import org.apache.logging.log4j.core.layout.PatternLayout; /** * A superclass for Comma-Separated Value (CSV) layouts. diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java similarity index 99% rename from log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java rename to log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java index 499a3d96d1f..123e5a68f56 100644 --- a/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvLogEventLayout.java +++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.csv.layout; import java.io.IOException; import java.nio.charset.Charset; diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java similarity index 98% rename from log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java rename to log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java index fe079fb590f..075c65a436c 100644 --- a/log4j-csv/src/main/java/org/apache/logging/log4j/core/layout/CsvParameterLayout.java +++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.csv.layout; import java.io.IOException; import java.nio.charset.Charset; diff --git a/log4j-csv/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/appender/CsvJsonParameterLayoutFileAppenderTest.java similarity index 98% rename from log4j-csv/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/csv/appender/CsvJsonParameterLayoutFileAppenderTest.java index 1dd7da76f3b..8f87162987b 100644 --- a/log4j-csv/src/test/java/org/apache/logging/log4j/core/appender/CsvJsonParameterLayoutFileAppenderTest.java +++ b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/appender/CsvJsonParameterLayoutFileAppenderTest.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender; +package org.apache.logging.log4j.csv.appender; import java.io.File; import java.io.IOException; diff --git a/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayoutTest.java similarity index 97% rename from log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayoutTest.java index 0ee8861d4d5..2776b7b8acc 100644 --- a/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvLogEventLayoutTest.java +++ b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayoutTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.csv.layout; import static org.junit.Assert.assertEquals; @@ -30,6 +30,8 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.csv.layout.AbstractCsvLayout; +import org.apache.logging.log4j.csv.layout.CsvLogEventLayout; import org.apache.logging.log4j.junit.ThreadContextRule; import org.apache.logging.log4j.test.appender.ListAppender; import org.junit.AfterClass; diff --git a/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutAllAsyncTest.java similarity index 94% rename from log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutAllAsyncTest.java index 1e9d3ddda03..4b3d8aefcef 100644 --- a/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutAllAsyncTest.java +++ b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutAllAsyncTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.csv.layout; import org.apache.commons.csv.CSVFormat; import org.apache.logging.log4j.LogManager; @@ -23,6 +23,8 @@ import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.csv.layout.AbstractCsvLayout; +import org.apache.logging.log4j.csv.layout.CsvParameterLayout; import org.apache.logging.log4j.util.Strings; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutTest.java similarity index 97% rename from log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java rename to log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutTest.java index e7d1074efdb..568a8332ffd 100644 --- a/log4j-csv/src/test/java/org/apache/logging/log4j/core/layout/CsvParameterLayoutTest.java +++ b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.csv.layout; import static org.junit.Assert.assertEquals; @@ -32,6 +32,8 @@ import org.apache.logging.log4j.categories.Layouts; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.csv.layout.AbstractCsvLayout; +import org.apache.logging.log4j.csv.layout.CsvParameterLayout; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.junit.ThreadContextRule; import org.apache.logging.log4j.message.ObjectArrayMessage; diff --git a/log4j-jdbc-dbcp2/pom.xml b/log4j-jdbc-dbcp2/pom.xml index 18e0e863bc7..3155019a842 100644 --- a/log4j-jdbc-dbcp2/pom.xml +++ b/log4j-jdbc-dbcp2/pom.xml @@ -25,7 +25,7 @@ ${basedir}/.. Log4j JDBC DBCP 2 Documentation /log4j-jdbc-dbcp2 - org.apache.logging.log4j.jdbc.dbcp2 + org.apache.logging.log4j.dbcp2 diff --git a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/PoolingDriverConnectionSource.java b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java similarity index 96% rename from log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/PoolingDriverConnectionSource.java rename to log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java index f408d26a7ff..6734e178034 100644 --- a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/PoolingDriverConnectionSource.java +++ b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.dbcp2.appender; import java.sql.DriverManager; import java.sql.SQLException; @@ -28,6 +28,8 @@ import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.logging.log4j.core.Core; +import org.apache.logging.log4j.core.appender.db.jdbc.AbstractDriverManagerConnectionSource; +import org.apache.logging.log4j.core.appender.db.jdbc.ConnectionSource; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; diff --git a/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/PoolingDriverConnectionSourceTest.java b/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/db/jdbc/appender/PoolingDriverConnectionSourceTest.java similarity index 95% rename from log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/PoolingDriverConnectionSourceTest.java rename to log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/db/jdbc/appender/PoolingDriverConnectionSourceTest.java index 72dc3d49a43..56740f628bc 100644 --- a/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/PoolingDriverConnectionSourceTest.java +++ b/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/db/jdbc/appender/PoolingDriverConnectionSourceTest.java @@ -15,12 +15,14 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.db.jdbc.appender; import java.sql.Connection; import java.sql.SQLException; +import org.apache.logging.log4j.core.appender.db.jdbc.JdbcH2TestHelper; import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.dbcp2.appender.PoolingDriverConnectionSource; import org.junit.Assert; import org.junit.Test; diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java similarity index 99% rename from log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java rename to log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java index aa78fad87d8..3e20288e420 100644 --- a/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppender.java +++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.jeromq; +package org.apache.logging.log4j.jeromq.appender; import java.io.Serializable; import java.util.ArrayList; diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqManager.java similarity index 99% rename from log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java rename to log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqManager.java index 0326ebe8ca2..494f13d7cf5 100644 --- a/log4j-jeromq/src/main/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqManager.java +++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqManager.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.jeromq; +package org.apache.logging.log4j.jeromq.appender; import java.util.Arrays; import java.util.List; diff --git a/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java b/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppenderTest.java similarity index 97% rename from log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java rename to log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppenderTest.java index 24b8d25dab6..fa8be866246 100644 --- a/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqAppenderTest.java +++ b/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppenderTest.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.jeromq; +package org.apache.logging.log4j.jeromq.appender; import java.util.List; import java.util.concurrent.ExecutorService; @@ -27,6 +27,8 @@ import org.apache.logging.log4j.categories.Appenders; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.util.ExecutorServices; +import org.apache.logging.log4j.jeromq.appender.JeroMqAppender; +import org.apache.logging.log4j.jeromq.appender.JeroMqManager; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.Assert; import org.junit.ClassRule; diff --git a/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java b/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqTestClient.java similarity index 97% rename from log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java rename to log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqTestClient.java index b84cc729f72..494be9d91fe 100644 --- a/log4j-jeromq/src/test/java/org/apache/logging/log4j/core/appender/mom/jeromq/JeroMqTestClient.java +++ b/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqTestClient.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.jeromq; +package org.apache.logging.log4j.jeromq.appender; import java.util.ArrayList; import java.util.List; diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml deleted file mode 100644 index af3a0b74620..00000000000 --- a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml b/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml deleted file mode 100644 index 8215ea3a2b9..00000000000 --- a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/AbstractLogEventWrapperEntity.java similarity index 96% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/AbstractLogEventWrapperEntity.java index 8504f7a5007..91d1394056b 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractLogEventWrapperEntity.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/AbstractLogEventWrapperEntity.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.util.Map; import javax.persistence.Inheritance; @@ -27,9 +27,9 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.AbstractLogEvent; import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jpa.converter.ContextDataAttributeConverter; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextDataAttributeConverter; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.message.Message; @@ -56,7 +56,7 @@ * {@link org.apache.logging.log4j.ThreadContext.ContextStack ThreadContext.ContextStack}, and * {@link Map Map<String, String>}) will not be recognized by the JPA provider. In conjunction with * {@link javax.persistence.Convert @Convert}, you can use the converters in the - * {@link org.apache.logging.log4j.core.appender.db.jpa.converter} package to convert these types to database columns. + * {@link org.apache.logging.log4j.jpa.converter} package to convert these types to database columns. * If you want to retrieve log events from the database, you can create a true POJO entity and also use these * converters for extracting persisted values.
*

@@ -323,7 +323,7 @@ public final void setEndOfBatch(final boolean endOfBatch) { * * @return the context data. * @see ContextDataAttributeConverter - * @see org.apache.logging.log4j.core.appender.db.jpa.converter.ContextDataAttributeConverter + * @see org.apache.logging.log4j.jpa.converter.ContextDataAttributeConverter */ @Override @Transient diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/BasicLogEventEntity.java similarity index 94% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/BasicLogEventEntity.java index fa52501c2b0..f48fd46b57c 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/BasicLogEventEntity.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/BasicLogEventEntity.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.util.Map; import javax.persistence.Basic; @@ -26,9 +26,9 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.appender.db.jpa.converter.*; import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jpa.converter.*; import org.apache.logging.log4j.message.Message; /** @@ -49,8 +49,8 @@ * {@link ContextMapAttributeConverter} and {@link ContextStackAttributeConverter}, respectively. These convert the * properties to simple strings that cannot be converted back to the properties. If you wish to instead convert these to * a reversible JSON string, override these attributes with the same annotations but use the - * {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter} and - * {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter} instead.
+ * {@link org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter} and + * {@link org.apache.logging.log4j.jpa.converter.ContextStackJsonAttributeConverter} instead.
*
* All other attributes in this entity use reversible converters that can be used for both persistence and retrieval. If * there are any attributes you do not want persistent, you should override their accessor methods and annotate with @@ -231,7 +231,7 @@ public ThrowableProxy getThrownProxy() { * * @return the context map. * @see ContextMapAttributeConverter - * @see org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter + * @see org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter */ @SuppressWarnings("deprecation") @Override @@ -245,7 +245,7 @@ public Map getContextMap() { * * @return the context stack. * @see ContextStackAttributeConverter - * @see org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter + * @see org.apache.logging.log4j.jpa.converter.ContextStackJsonAttributeConverter */ @Override @Convert(converter = ContextStackAttributeConverter.class) diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaAppender.java similarity index 99% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaAppender.java index aee94e8ea1e..46fc66c3bb2 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaAppender.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaAppender.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.lang.reflect.Constructor; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaDatabaseManager.java similarity index 99% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaDatabaseManager.java index b2d36a8b253..fda26af7c9c 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JpaDatabaseManager.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/JpaDatabaseManager.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.io.Serializable; import java.lang.reflect.Constructor; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/package-info.java similarity index 95% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/package-info.java index 3434faa1639..13f40c953d4 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/package-info.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/appender/package-info.java @@ -20,4 +20,4 @@ * and your JPA provider of choice on the class path; these Maven dependencies are optional and will not automatically * be added to your classpath. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataAttributeConverter.java similarity index 96% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataAttributeConverter.java index ede6706b601..d3b1db2f431 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverter.java similarity index 98% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverter.java index b6c57edd9ad..b2981729c4a 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.io.IOException; import java.util.Iterator; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextMapAttributeConverter.java similarity index 96% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextMapAttributeConverter.java index 0561c952ed8..374a6cebab1 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextMapAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.util.Map; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextMapJsonAttributeConverter.java similarity index 97% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextMapJsonAttributeConverter.java index 385cc647638..94d039fecfb 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextMapJsonAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.io.IOException; import java.util.Map; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextStackAttributeConverter.java similarity index 97% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextStackAttributeConverter.java index 18e1dbf4711..d9090ca9caf 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextStackAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextStackJsonAttributeConverter.java similarity index 97% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextStackJsonAttributeConverter.java index 49dec9e2ea0..ab66679d1c8 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ContextStackJsonAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.io.IOException; import java.util.List; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/InstantAttributeConverter.java similarity index 91% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/InstantAttributeConverter.java index 9e0120eb2be..1f41e6cd112 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/InstantAttributeConverter.java @@ -14,23 +14,21 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; -import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Strings; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; - /** * A JPA 2.1 attribute converter for {@link Instant}s in {@link org.apache.logging.log4j.core.LogEvent}s. This * converter is capable of converting both to and from {@link String}s. */ @Converter(autoApply = false) public class InstantAttributeConverter implements AttributeConverter { - private static final StatusLogger LOGGER = StatusLogger.getLogger(); @Override public String convertToDatabaseColumn(final Instant instant) { diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/LevelAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/LevelAttributeConverter.java similarity index 96% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/LevelAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/LevelAttributeConverter.java index c418a648cdf..4a543b9287a 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/LevelAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/LevelAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/MarkerAttributeConverter.java similarity index 96% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/MarkerAttributeConverter.java index a8bb072215e..c133473ba50 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/MarkerAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/MessageAttributeConverter.java similarity index 96% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/MessageAttributeConverter.java index e369c29ba00..5046fb8d5cf 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/MessageAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/StackTraceElementAttributeConverter.java similarity index 97% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/StackTraceElementAttributeConverter.java index b34822d79e3..a6ffe31d71c 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/StackTraceElementAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import javax.persistence.AttributeConverter; import javax.persistence.Converter; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ThrowableAttributeConverter.java similarity index 99% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ThrowableAttributeConverter.java index bbec3197527..0a3b876836f 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverter.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/ThrowableAttributeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.lang.reflect.Constructor; import java.lang.reflect.Field; diff --git a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/package-info.java similarity index 68% rename from log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java rename to log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/package-info.java index 2245fa7713c..51d9afb368a 100644 --- a/log4j-jpa/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/converter/package-info.java +++ b/log4j-jpa/src/main/java/org/apache/logging/log4j/jpa/converter/package-info.java @@ -20,13 +20,13 @@ * The converters in this package implement the JPA 2.1 mechanism for converting non-standard types to and from * database fields. Most of these types are capable of two-way conversion and can be used to both persist and retrieve * entities. The - * {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter ContextMapAttributeConverter} - * and {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter ContextStackAttributeConverter} + * {@link org.apache.logging.log4j.jpa.converter.ContextMapAttributeConverter ContextMapAttributeConverter} + * and {@link org.apache.logging.log4j.jpa.converter.ContextStackAttributeConverter ContextStackAttributeConverter} * only support persistence and not retrieval, persisting the type as a simple string. You can use the - * {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter ContextMapJsonAttributeConverter} - * and {@link org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter ContextStackJsonAttributeConverter} + * {@link org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter ContextMapJsonAttributeConverter} + * and {@link org.apache.logging.log4j.jpa.converter.ContextStackJsonAttributeConverter ContextStackJsonAttributeConverter} * instead, which require the Jackson Data Processor dependency to also be on your class path. */ //CHECKSTYLE:ON -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractJpaAppenderTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/AbstractJpaAppenderTest.java similarity index 97% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractJpaAppenderTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/AbstractJpaAppenderTest.java index 6ff3c14a866..1d451e09512 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/AbstractJpaAppenderTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/AbstractJpaAppenderTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; @@ -30,6 +30,7 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.DefaultConfiguration; +import org.apache.logging.log4j.jpa.appender.JpaAppender; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.PropertiesUtil; import org.junit.Test; @@ -51,8 +52,10 @@ public AbstractJpaAppenderTest(final String databaseType) { public void setUp(final String configFileName) throws SQLException { this.connection = this.setUpConnection(); + final String resource = "org/apache/logging/log4j/jpa/appender/" + configFileName; + assertNotNull(getClass().getClassLoader().getResource(resource)); System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, - "org/apache/logging/log4j/core/appender/db/jpa/" + configFileName); + resource); PropertiesUtil.getProperties().reload(); final LoggerContext context = LoggerContext.getContext(false); if (context.getConfiguration() instanceof DefaultConfiguration) { diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaH2AppenderTest.java similarity index 97% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaH2AppenderTest.java index 9b299b92cf8..f6bf26baefc 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaH2AppenderTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaH2AppenderTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.sql.Connection; import java.sql.DriverManager; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaHsqldbAppenderTest.java similarity index 97% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaHsqldbAppenderTest.java index b91734d0b22..24b5862743a 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/JpaHsqldbAppenderTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/JpaHsqldbAppenderTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.sql.Connection; import java.sql.DriverManager; @@ -23,6 +23,7 @@ import org.apache.logging.log4j.categories.Appenders; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.jpa.appender.JpaAppender; import org.apache.logging.log4j.util.Strings; import org.junit.Test; import org.junit.experimental.categories.Category; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/LogEventEntityTest.java similarity index 95% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/LogEventEntityTest.java index b70c754f76c..502b4fa860d 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/LogEventEntityTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/LogEventEntityTest.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.util.Map; @@ -26,6 +26,7 @@ import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; +import org.apache.logging.log4j.jpa.appender.AbstractLogEventWrapperEntity; import org.apache.logging.log4j.message.Message; import org.junit.Assert; import org.junit.Test; @@ -36,7 +37,7 @@ public class LogEventEntityTest { public void testToImmutable_AbstractLogEventWrapperEntity() { final LogEvent logEvent = new AbstractLogEventWrapperEntity() { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; @Override public Map getContextMap() { diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBaseEntity.java similarity index 91% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBaseEntity.java index 2171de47c27..522372a499c 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBaseEntity.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBaseEntity.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.util.Date; import java.util.Map; @@ -34,20 +34,21 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter; import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jpa.appender.AbstractLogEventWrapperEntity; +import org.apache.logging.log4j.jpa.converter.InstantAttributeConverter; +import org.apache.logging.log4j.jpa.converter.LevelAttributeConverter; +import org.apache.logging.log4j.jpa.converter.MessageAttributeConverter; +import org.apache.logging.log4j.jpa.converter.ThrowableAttributeConverter; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter; -import org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter; -import org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter; import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.message.Message; @Entity @Table(name = "jpaBaseLogEntry") public class TestBaseEntity extends AbstractLogEventWrapperEntity { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; private long id = 0L; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBasicEntity.java similarity index 88% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBasicEntity.java index b804078aa37..b98d525e7c8 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/TestBasicEntity.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/appender/TestBasicEntity.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa; +package org.apache.logging.log4j.jpa.appender; import java.util.Map; @@ -27,13 +27,14 @@ import javax.persistence.Table; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter; +import org.apache.logging.log4j.jpa.appender.BasicLogEventEntity; +import org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter; @Entity @Table(name = "jpaBasicLogEntry") @SuppressWarnings("unused") public class TestBasicEntity extends BasicLogEventEntity { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; private long id = 0L; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextDataAttributeConverterTest.java similarity index 95% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextDataAttributeConverterTest.java index 41306a1b516..5c8a12b30e3 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextDataAttributeConverterTest.java @@ -14,9 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.ContextDataAttributeConverter; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; import org.junit.Before; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverterTest.java similarity index 96% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverterTest.java index 161a23e4c29..fc0a588b874 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextDataJsonAttributeConverterTest.java @@ -14,9 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.ContextDataJsonAttributeConverter; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.SortedArrayStringMap; import org.apache.logging.log4j.util.StringMap; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextMapAttributeConverterTest.java similarity index 94% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextMapAttributeConverterTest.java index e755d7f0889..2f2d6ea3d8a 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextMapAttributeConverterTest.java @@ -14,12 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.util.HashMap; import java.util.Map; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.ContextMapAttributeConverter; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextMapJsonAttributeConverterTest.java similarity index 95% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextMapJsonAttributeConverterTest.java index 07af863ea65..8b9571e1ffd 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapJsonAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextMapJsonAttributeConverterTest.java @@ -14,12 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.util.HashMap; import java.util.Map; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextStackAttributeConverterTest.java similarity index 95% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextStackAttributeConverterTest.java index 57ae0a7e999..452eaf28b80 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextStackAttributeConverterTest.java @@ -14,12 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.util.Arrays; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.ContextStackAttributeConverter; import org.apache.logging.log4j.spi.MutableThreadContextStack; import org.junit.Before; import org.junit.Test; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextStackJsonAttributeConverterTest.java similarity index 96% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextStackJsonAttributeConverterTest.java index 0fae006fbfa..de8700eed62 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextStackJsonAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ContextStackJsonAttributeConverterTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -24,6 +24,7 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.ContextStackJsonAttributeConverter; import org.apache.logging.log4j.junit.ThreadContextStackRule; import org.apache.logging.log4j.spi.MutableThreadContextStack; import org.junit.Before; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/InstantAttributeConverterTest.java similarity index 91% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/InstantAttributeConverterTest.java index f4970a99b5a..e7a495ed256 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/InstantAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/InstantAttributeConverterTest.java @@ -14,21 +14,21 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import org.apache.logging.log4j.categories.Appenders; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; -import org.apache.logging.log4j.status.StatusLogger; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.junit.Assert.*; - @Category(Appenders.Jpa.class) public class InstantAttributeConverterTest { - private static final StatusLogger LOGGER = StatusLogger.getLogger(); private InstantAttributeConverter converter; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/MarkerAttributeConverterTest.java similarity index 96% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/MarkerAttributeConverterTest.java index 334bf1eac39..cacf59cdbc4 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MarkerAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/MarkerAttributeConverterTest.java @@ -14,11 +14,12 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.MarkerAttributeConverter; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/MessageAttributeConverterTest.java similarity index 95% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/MessageAttributeConverterTest.java index e665dd66fa9..9b16dbd78cf 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/MessageAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/MessageAttributeConverterTest.java @@ -14,9 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.MessageAttributeConverter; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.status.StatusLogger; import org.junit.Before; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/StackTraceElementAttributeConverterTest.java similarity index 98% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/StackTraceElementAttributeConverterTest.java index 6da0d93e9d6..d0e6d094049 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/StackTraceElementAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/StackTraceElementAttributeConverterTest.java @@ -14,9 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.StackTraceElementAttributeConverter; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; diff --git a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverterTest.java b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ThrowableAttributeConverterTest.java similarity index 96% rename from log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverterTest.java rename to log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ThrowableAttributeConverterTest.java index 95deb6fb8eb..f06eee97139 100644 --- a/log4j-jpa/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ThrowableAttributeConverterTest.java +++ b/log4j-jpa/src/test/java/org/apache/logging/log4j/jpa/converter/ThrowableAttributeConverterTest.java @@ -14,11 +14,12 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jpa.converter; +package org.apache.logging.log4j.jpa.converter; import java.sql.SQLException; import org.apache.logging.log4j.categories.Appenders; +import org.apache.logging.log4j.jpa.converter.ThrowableAttributeConverter; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; diff --git a/log4j-jpa/src/test/resources/META-INF/persistence.xml b/log4j-jpa/src/test/resources/META-INF/persistence.xml index d80073902c5..209ae2176ec 100644 --- a/log4j-jpa/src/test/resources/META-INF/persistence.xml +++ b/log4j-jpa/src/test/resources/META-INF/persistence.xml @@ -24,16 +24,16 @@ org.eclipse.persistence.jpa.PersistenceProvider - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextMapAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextStackAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextStackJsonAttributeConverter + org.apache.logging.log4j.jpa.converter.InstantAttributeConverter + org.apache.logging.log4j.jpa.converter.LevelAttributeConverter + org.apache.logging.log4j.jpa.converter.MarkerAttributeConverter + org.apache.logging.log4j.jpa.converter.MessageAttributeConverter + org.apache.logging.log4j.jpa.converter.StackTraceElementAttributeConverter + org.apache.logging.log4j.jpa.converter.ThrowableAttributeConverter false NONE @@ -49,16 +49,16 @@ org.eclipse.persistence.jpa.PersistenceProvider - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.InstantAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.LevelAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter - org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextMapAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextStackAttributeConverter + org.apache.logging.log4j.jpa.converter.ContextStackJsonAttributeConverter + org.apache.logging.log4j.jpa.converter.InstantAttributeConverter + org.apache.logging.log4j.jpa.converter.LevelAttributeConverter + org.apache.logging.log4j.jpa.converter.MarkerAttributeConverter + org.apache.logging.log4j.jpa.converter.MessageAttributeConverter + org.apache.logging.log4j.jpa.converter.StackTraceElementAttributeConverter + org.apache.logging.log4j.jpa.converter.ThrowableAttributeConverter false NONE diff --git a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml b/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml deleted file mode 100644 index af3a0b74620..00000000000 --- a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-basic.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml b/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml deleted file mode 100644 index 8215ea3a2b9..00000000000 --- a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-basic.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-h2-jpa-base.xml similarity index 85% rename from log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml rename to log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-h2-jpa-base.xml index ad22f659779..75471eee5a8 100644 --- a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml +++ b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-h2-jpa-base.xml @@ -22,11 +22,11 @@ + entityClassName="org.apache.logging.log4j.jpa.appender.TestBaseEntity" ignoreExceptions="false" /> - + diff --git a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-h2-jpa-basic.xml similarity index 85% rename from log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml rename to log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-h2-jpa-basic.xml index ad22f659779..3b04abf9dad 100644 --- a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-h2-jpa-base.xml +++ b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-h2-jpa-basic.xml @@ -22,11 +22,11 @@ + entityClassName="org.apache.logging.log4j.jpa.appender.TestBasicEntity" ignoreExceptions="false" /> - + diff --git a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-hsqldb-jpa-base.xml similarity index 85% rename from log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml rename to log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-hsqldb-jpa-base.xml index 3f6e50a0367..a03f3907511 100644 --- a/log4j-jpa/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml +++ b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-hsqldb-jpa-base.xml @@ -22,11 +22,11 @@ + entityClassName="org.apache.logging.log4j.jpa.appender.TestBaseEntity" ignoreExceptions="false" /> - + diff --git a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-hsqldb-jpa-basic.xml similarity index 85% rename from log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml rename to log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-hsqldb-jpa-basic.xml index 3f6e50a0367..7d369394d91 100644 --- a/log4j-jeromq/src/test/resources/org/apache/logging/log4j/core/appender/db/jpa/log4j2-hsqldb-jpa-base.xml +++ b/log4j-jpa/src/test/resources/org/apache/logging/log4j/jpa/appender/log4j2-hsqldb-jpa-basic.xml @@ -22,11 +22,11 @@ + entityClassName="org.apache.logging.log4j.jpa.appender.TestBasicEntity" ignoreExceptions="false" /> - + diff --git a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/DefaultKafkaProducerFactory.java similarity index 96% rename from log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/DefaultKafkaProducerFactory.java index e0b39219dbc..da9ab921bf5 100644 --- a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/DefaultKafkaProducerFactory.java +++ b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/DefaultKafkaProducerFactory.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.kafka; +package org.apache.logging.log4j.kafka.appender; import java.util.Properties; diff --git a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java similarity index 99% rename from log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java index f7d50af4b8a..687a9e7a83e 100644 --- a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppender.java +++ b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaAppender.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.kafka; +package org.apache.logging.log4j.kafka.appender; import java.io.Serializable; import java.util.Objects; diff --git a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaManager.java similarity index 98% rename from log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaManager.java index 9af11cd6931..dfb1d135a15 100644 --- a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaManager.java +++ b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaManager.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.kafka; +package org.apache.logging.log4j.kafka.appender; import java.nio.charset.StandardCharsets; import java.util.Objects; diff --git a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaProducerFactory.java similarity index 96% rename from log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java rename to log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaProducerFactory.java index 7532bb84afb..21944923bfd 100644 --- a/log4j-kafka/src/main/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaProducerFactory.java +++ b/log4j-kafka/src/main/java/org/apache/logging/log4j/kafka/appender/KafkaProducerFactory.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.kafka; +package org.apache.logging.log4j.kafka.appender; import java.util.Properties; diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderCloseTimeoutTest.java similarity index 93% rename from log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java rename to log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderCloseTimeoutTest.java index a8d3566b97f..25cdd608f5a 100644 --- a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderCloseTimeoutTest.java +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderCloseTimeoutTest.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.kafka; +package org.apache.logging.log4j.kafka.appender; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -25,6 +25,8 @@ import org.apache.logging.log4j.categories.Appenders; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.junit.LoggerContextRule; +import org.apache.logging.log4j.kafka.appender.KafkaManager; +import org.apache.logging.log4j.kafka.appender.KafkaProducerFactory; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderTest.java similarity index 97% rename from log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java rename to log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderTest.java index 613bd7455ce..c1a38cbeab6 100644 --- a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/appender/mom/kafka/KafkaAppenderTest.java +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/appender/KafkaAppenderTest.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom.kafka; +package org.apache.logging.log4j.kafka.appender; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -36,6 +36,8 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.junit.LoggerContextRule; +import org.apache.logging.log4j.kafka.appender.KafkaManager; +import org.apache.logging.log4j.kafka.appender.KafkaProducerFactory; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.junit.Before; diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/ConfigurationAssemblerTest.java similarity index 92% rename from log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java rename to log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/ConfigurationAssemblerTest.java index ec4f541bd34..4e60fb6d2c4 100644 --- a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationAssemblerTest.java +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/ConfigurationAssemblerTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.config.builder; +package org.apache.logging.log4j.kafka.builder; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -31,7 +31,6 @@ import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.mom.kafka.KafkaAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.Configurator; @@ -43,6 +42,7 @@ import org.apache.logging.log4j.core.filter.ThresholdFilter; import org.apache.logging.log4j.core.layout.GelfLayout; import org.apache.logging.log4j.core.util.Constants; +import org.apache.logging.log4j.kafka.appender.KafkaAppender; import org.junit.Test; /** @@ -55,7 +55,8 @@ public void testBuildConfiguration() throws Exception { try { System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"); - final ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder(); + final ConfigurationBuilder builder = ConfigurationBuilderFactory + .newConfigurationBuilder(); CustomConfigurationFactory.addTestFixtures("config name", builder); final Configuration configuration = builder.build(); try (LoggerContext ctx = Configurator.initialize(configuration)) { @@ -70,7 +71,7 @@ public void testBuildConfiguration() throws Exception { public void testCustomConfigurationFactory() throws Exception { try { System.setProperty(ConfigurationFactory.CONFIGURATION_FACTORY_PROPERTY, - "org.apache.logging.log4j.core.config.builder.CustomConfigurationFactory"); + "org.apache.logging.log4j.kafka.builder.CustomConfigurationFactory"); System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, "org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"); final Configuration config = ((LoggerContext) LogManager.getContext(false)).getConfiguration(); @@ -90,8 +91,8 @@ private void validate(final Configuration config) { final Map appenders = config.getAppenders(); assertNotNull(appenders); assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 2); - final KafkaAppender kafkaAppender = (KafkaAppender)appenders.get("Kafka"); - final GelfLayout gelfLayout = (GelfLayout)kafkaAppender.getLayout(); + final KafkaAppender kafkaAppender = (KafkaAppender) appenders.get("Kafka"); + final GelfLayout gelfLayout = (GelfLayout) kafkaAppender.getLayout(); final Map loggers = config.getLoggers(); assertNotNull(loggers); assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2); diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/ConfigurationBuilderTest.java similarity index 95% rename from log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java rename to log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/ConfigurationBuilderTest.java index bbb7f104141..0d263fe8795 100644 --- a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/ConfigurationBuilderTest.java @@ -14,7 +14,9 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.config.builder; +package org.apache.logging.log4j.kafka.builder; + +import static org.junit.Assert.assertEquals; import java.util.concurrent.TimeUnit; @@ -27,9 +29,6 @@ import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration; import org.junit.Test; -import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; - public class ConfigurationBuilderTest { private static final String INDENT = " "; @@ -70,7 +69,7 @@ private void addTestFixtures(final String name, final ConfigurationBuilder" + EOL + + "" + EOL + "" + EOL + INDENT + "" + EOL + INDENT + INDENT + "MyValue" + EOL + @@ -110,7 +109,7 @@ private void addTestFixtures(final String name, final ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder(); addTestFixtures("config name", builder); final String xmlConfiguration = builder.toXmlConfiguration(); diff --git a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/CustomConfigurationFactory.java similarity index 98% rename from log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java rename to log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/CustomConfigurationFactory.java index 847f79e75e0..4c8a3421c6d 100644 --- a/log4j-kafka/src/test/java/org/apache/logging/log4j/core/config/builder/CustomConfigurationFactory.java +++ b/log4j-kafka/src/test/java/org/apache/logging/log4j/kafka/builder/CustomConfigurationFactory.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.config.builder; +package org.apache.logging.log4j.kafka.builder; import java.net.URI; diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JpaAppenderBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JpaAppenderBenchmark.java index 462b74aed56..2d9f9aad536 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JpaAppenderBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JpaAppenderBenchmark.java @@ -26,10 +26,10 @@ 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.appender.db.jpa.JpaAppender; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.jpa.appender.JpaAppender; import org.apache.logging.log4j.status.StatusLogger; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/jpa/TestBasicEntity.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/jpa/TestBasicEntity.java index b1e43d4d773..eb559250899 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/jpa/TestBasicEntity.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/jpa/TestBasicEntity.java @@ -27,8 +27,8 @@ import javax.persistence.Table; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.appender.db.jpa.BasicLogEventEntity; -import org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter; +import org.apache.logging.log4j.jpa.appender.BasicLogEventEntity; +import org.apache.logging.log4j.jpa.converter.ContextMapJsonAttributeConverter; @Entity @Table(name = "jpaBasicLogEntry") diff --git a/log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/MimeMessageBuilder.java similarity index 98% rename from log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java rename to log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/MimeMessageBuilder.java index b4d2549b995..9c57d919eec 100644 --- a/log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/MimeMessageBuilder.java +++ b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/MimeMessageBuilder.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.net; +package org.apache.logging.log4j.smtp; import java.nio.charset.StandardCharsets; diff --git a/log4j-smtp/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java similarity index 98% rename from log4j-smtp/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java rename to log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java index e3aac4dbdd4..4d5b73b6fbe 100644 --- a/log4j-smtp/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java +++ b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpAppender.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender; +package org.apache.logging.log4j.smtp.appender; import java.io.Serializable; @@ -24,6 +24,7 @@ import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.config.plugins.Plugin; @@ -35,7 +36,6 @@ import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort; import org.apache.logging.log4j.core.filter.ThresholdFilter; import org.apache.logging.log4j.core.layout.HtmlLayout; -import org.apache.logging.log4j.core.net.SmtpManager; import org.apache.logging.log4j.core.util.Booleans; /** diff --git a/log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpManager.java similarity index 99% rename from log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java rename to log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpManager.java index 84b07fe44cf..4f1c4a14331 100644 --- a/log4j-smtp/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java +++ b/log4j-smtp/src/main/java/org/apache/logging/log4j/smtp/appender/SmtpManager.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.net; +package org.apache.logging.log4j.smtp.appender; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -50,6 +50,7 @@ import org.apache.logging.log4j.core.util.NameUtil; import org.apache.logging.log4j.core.util.NetUtils; import org.apache.logging.log4j.message.ReusableMessage; +import org.apache.logging.log4j.smtp.MimeMessageBuilder; import org.apache.logging.log4j.util.PropertiesUtil; import org.apache.logging.log4j.util.Strings; diff --git a/log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderAsyncTest.java similarity index 98% rename from log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java rename to log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderAsyncTest.java index 91503d3b0a4..e0225cbd2df 100644 --- a/log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderAsyncTest.java +++ b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderAsyncTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender; +package org.apache.logging.log4j.smtp.appender; import org.apache.logging.dumbster.smtp.SimpleSmtpServer; import org.apache.logging.dumbster.smtp.SmtpMessage; diff --git a/log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java similarity index 97% rename from log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java rename to log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java index 61b9b92797d..599093c1c58 100644 --- a/log4j-smtp/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java +++ b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender; +package org.apache.logging.log4j.smtp.appender; import java.util.Iterator; import javax.mail.Address; @@ -29,7 +29,8 @@ import org.apache.logging.log4j.categories.Appenders; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.net.MimeMessageBuilder; +import org.apache.logging.log4j.smtp.MimeMessageBuilder; +import org.apache.logging.log4j.smtp.appender.SmtpAppender; import org.apache.logging.log4j.test.AvailablePortFinder; import org.junit.Test; import org.junit.experimental.categories.Category; From 10ba5a1396cd3221f4063454d1e40c22c86e3317 Mon Sep 17 00:00:00 2001 From: rpopma Date: Tue, 30 Jan 2018 00:26:08 +0900 Subject: [PATCH 0014/2347] LOG4J2-2225 partial revert to preserve binary compatibility for common use cases (ClockFactory and SystemNanoClock) --- .../cassandra/ClockTimestampGenerator.java | 2 +- .../rolling/action/IfLastModified.java | 2 +- .../logging/log4j/core/async/AsyncLogger.java | 2 +- .../logging/log4j/core/filter/TimeFilter.java | 2 +- .../log4j/core/impl/Log4jLogEvent.java | 2 +- .../core/impl/ReusableLogEventFactory.java | 2 +- .../log4j/core/pattern/PatternParser.java | 2 +- .../time/{internal => }/ClockFactory.java | 8 +++- .../time/{internal => }/SystemNanoClock.java | 3 +- .../logging/log4j/core/util/ClockFactory.java | 37 +++++++++++++++++++ .../log4j/core/util/SystemNanoClock.java | 35 ++++++++++++++++++ .../log4j/core/TimestampMessageTest.java | 4 +- .../JsonCompleteFileAppenderTest.java | 2 +- .../core/async/AsyncLoggerTestNanoTime.java | 2 +- .../AsyncLoggerTimestampMessageTest.java | 4 +- .../log4j/core/filter/TimeFilterTest.java | 4 +- .../core/impl/Log4jLogEventNanoTimeTest.java | 2 +- .../log4j/core/impl/Log4jLogEventTest.java | 4 +- .../log4j/core/pattern/PatternParserTest.java | 2 +- .../time/{internal => }/ClockFactoryTest.java | 9 ++--- .../{internal => }/SystemNanoClockTest.java | 9 ++--- 21 files changed, 107 insertions(+), 32 deletions(-) rename log4j-core/src/main/java/org/apache/logging/log4j/core/time/{internal => }/ClockFactory.java (93%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/time/{internal => }/SystemNanoClock.java (95%) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java rename log4j-core/src/test/java/org/apache/logging/log4j/core/time/{internal => }/ClockFactoryTest.java (96%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/time/{internal => }/SystemNanoClockTest.java (89%) diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java index 50d7bc4ae85..be9611ddbc9 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java @@ -18,7 +18,7 @@ import com.datastax.driver.core.TimestampGenerator; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactory; /** * A {@link TimestampGenerator} implementation using the configured {@link Clock}. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java index 66902d7d501..5aba668c941 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.status.StatusLogger; /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java index fd7c6f6acb8..e32f2101dd0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.core.util.NanoClock; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java index 8cab11fc9ec..ba7ec99f5b0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.PerformanceSensitive; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java index d7da56ca4b9..248202c0c4e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java @@ -29,7 +29,7 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.ContextDataInjector; -import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.util.*; import org.apache.logging.log4j.core.time.Instant; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java index 44a2572952e..2a96007eeca 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java @@ -26,7 +26,7 @@ import org.apache.logging.log4j.core.async.ThreadNameCachingStrategy; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.StringMap; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java index ac6940a3128..21747e0b9d0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/PatternParser.java @@ -29,7 +29,7 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.util.PluginManager; import org.apache.logging.log4j.core.config.plugins.util.PluginType; -import org.apache.logging.log4j.core.time.internal.SystemNanoClock; +import org.apache.logging.log4j.core.time.SystemNanoClock; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.Strings; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/ClockFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/ClockFactory.java similarity index 93% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/ClockFactory.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/ClockFactory.java index 415e903cbfd..ef6febf859e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/ClockFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/ClockFactory.java @@ -14,9 +14,12 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.time.internal; +package org.apache.logging.log4j.core.time; -import org.apache.logging.log4j.core.time.PreciseClock; +import org.apache.logging.log4j.core.time.internal.CachedClock; +import org.apache.logging.log4j.core.time.internal.CoarseCachedClock; +import org.apache.logging.log4j.core.time.internal.SystemClock; +import org.apache.logging.log4j.core.time.internal.SystemMillisClock; import org.apache.logging.log4j.core.util.Clock; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.status.StatusLogger; @@ -28,6 +31,7 @@ /** * Factory for {@code Clock} objects. + * @since 2.11 */ public final class ClockFactory { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/SystemNanoClock.java similarity index 95% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemNanoClock.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/SystemNanoClock.java index 1cd1a6ffb2e..13019e5f48d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemNanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/SystemNanoClock.java @@ -14,12 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.time.internal; +package org.apache.logging.log4j.core.time; import org.apache.logging.log4j.core.util.NanoClock; /** * Implementation of the {@code NanoClock} interface that returns the system nano time. + * @since 2.11 */ public final class SystemNanoClock implements NanoClock { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java new file mode 100644 index 00000000000..abe26fb0d13 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java @@ -0,0 +1,37 @@ +/* + * 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.util; + +/** + * @deprecated Use {@link org.apache.logging.log4j.core.time.ClockFactory} instead. + */ +@Deprecated +public final class ClockFactory { + + /** @see org.apache.logging.log4j.core.time.ClockFactory#PROPERTY_NAME */ + @Deprecated + public static final String PROPERTY_NAME = org.apache.logging.log4j.core.time.ClockFactory.PROPERTY_NAME; + + private ClockFactory() {} + + /** @see org.apache.logging.log4j.core.time.ClockFactory#getClock() */ + @Deprecated + public static Clock getClock() { + return org.apache.logging.log4j.core.time.ClockFactory.getClock(); + } + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java new file mode 100644 index 00000000000..367b2aac448 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java @@ -0,0 +1,35 @@ +/* + * 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.util; + +/** + * @deprecated Use {@link org.apache.logging.log4j.core.time.SystemNanoClock} instead. + */ +@Deprecated +public final class SystemNanoClock implements NanoClock { + + /** + * @see org.apache.logging.log4j.core.time.SystemNanoClock#nanoTime() + * @deprecated use {@link org.apache.logging.log4j.core.time.SystemNanoClock} instead. + */ + @Deprecated + @Override + public long nanoTime() { + return System.nanoTime(); + } + +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java index a2c02fbc8f2..abea8b02dad 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java @@ -20,8 +20,8 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; -import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; +import org.apache.logging.log4j.core.time.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.message.Message; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java index fcbd40c7c4f..853f7e3f7c2 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java @@ -26,7 +26,7 @@ import org.apache.logging.log4j.core.impl.Log4jLogEventTest; import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.selector.CoreContextSelectors; -import org.apache.logging.log4j.core.time.internal.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.junit.CleanFiles; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.AfterClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java index 628e68598af..7995f11fcd6 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTestNanoTime.java @@ -27,7 +27,7 @@ import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; -import org.apache.logging.log4j.core.time.internal.SystemNanoClock; +import org.apache.logging.log4j.core.time.SystemNanoClock; import org.apache.logging.log4j.util.Strings; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java index 4c9a00f48cc..35515536b76 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java @@ -26,8 +26,8 @@ import org.apache.logging.log4j.core.CoreLoggerContexts; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; -import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; +import org.apache.logging.log4j.core.time.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java index 9b026acbb2b..117de29a704 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java @@ -24,8 +24,8 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; -import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; +import org.apache.logging.log4j.core.time.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java index 5355774739b..86383b59519 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventNanoTimeTest.java @@ -27,7 +27,7 @@ import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; -import org.apache.logging.log4j.core.time.internal.SystemNanoClock; +import org.apache.logging.log4j.core.time.SystemNanoClock; import org.apache.logging.log4j.util.Strings; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java index eab49491e4f..1a9a66d1415 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java @@ -39,8 +39,8 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.convert.Base64Converter; import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; -import org.apache.logging.log4j.core.time.internal.ClockFactoryTest; +import org.apache.logging.log4j.core.time.ClockFactory; +import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ObjectMessage; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java index 5b61b69fc95..7fd7254b90a 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/PatternParserTest.java @@ -34,7 +34,7 @@ import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.impl.ThrowableFormatOptions; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; -import org.apache.logging.log4j.core.time.internal.SystemNanoClock; +import org.apache.logging.log4j.core.time.SystemNanoClock; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.util.Strings; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/ClockFactoryTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/ClockFactoryTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/ClockFactoryTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/ClockFactoryTest.java index 2db66f21629..203c70b4d48 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/ClockFactoryTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/ClockFactoryTest.java @@ -14,22 +14,21 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.time.internal; - -import java.lang.reflect.Field; +package org.apache.logging.log4j.core.time; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.logging.log4j.core.async.AsyncLogger; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.time.internal.CachedClock; -import org.apache.logging.log4j.core.time.internal.ClockFactory; import org.apache.logging.log4j.core.time.internal.CoarseCachedClock; import org.apache.logging.log4j.core.time.internal.SystemClock; import org.apache.logging.log4j.core.util.Clock; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; +import java.lang.reflect.Field; + +import static org.junit.Assert.assertSame; public class ClockFactoryTest { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemNanoClockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/SystemNanoClockTest.java similarity index 89% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemNanoClockTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/SystemNanoClockTest.java index 7b729522015..00b01eec563 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/SystemNanoClockTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/SystemNanoClockTest.java @@ -15,15 +15,14 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.time.internal; +package org.apache.logging.log4j.core.time; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.core.time.internal.SystemNanoClock; import org.apache.logging.log4j.core.util.NanoClock; import org.junit.Test; -import static org.junit.Assert.*; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertTrue; /** * Tests the SystemNanoClock. From 47604fafbf3c456e2d39727cb9679b1c6415c1c2 Mon Sep 17 00:00:00 2001 From: rpopma Date: Tue, 30 Jan 2018 00:41:57 +0900 Subject: [PATCH 0015/2347] LOG4J2-2225 move Clock and NanoClock interfaces from util to time; provide deprecated sub-interfaces to preserve binary compatibility --- .../log4j/cassandra/CassandraAppender.java | 2 +- .../cassandra/ClockTimestampGenerator.java | 2 +- .../rolling/action/IfLastModified.java | 2 +- .../logging/log4j/core/async/AsyncLogger.java | 4 +-- .../log4j/core/async/RingBufferLogEvent.java | 2 ++ .../async/RingBufferLogEventTranslator.java | 4 +-- .../core/config/AbstractConfiguration.java | 2 +- .../log4j/core/config/Configuration.java | 2 +- .../logging/log4j/core/filter/TimeFilter.java | 2 +- .../log4j/core/impl/Log4jLogEvent.java | 4 +-- .../log4j/core/impl/MutableLogEvent.java | 2 ++ .../core/impl/ReusableLogEventFactory.java | 2 +- .../apache/logging/log4j/core/time/Clock.java | 33 +++++++++++++++++ .../logging/log4j/core/time/ClockFactory.java | 4 ++- .../logging/log4j/core/time/Instant.java | 1 - .../log4j/core/time/MutableInstant.java | 1 - .../logging/log4j/core/time/NanoClock.java | 36 +++++++++++++++++++ .../logging/log4j/core/time/PreciseClock.java | 2 -- .../log4j/core/time/SystemNanoClock.java | 5 +-- .../log4j/core/time/internal/CachedClock.java | 2 +- .../core/time/internal/CoarseCachedClock.java | 2 +- .../core/time/internal/DummyNanoClock.java | 2 +- .../log4j/core/time/internal/SystemClock.java | 2 +- .../core/time/internal/SystemMillisClock.java | 2 +- .../apache/logging/log4j/core/util/Clock.java | 12 +++---- .../logging/log4j/core/util/ClockFactory.java | 2 ++ .../logging/log4j/core/util/NanoClock.java | 12 +++---- .../log4j/core/util/SystemNanoClock.java | 2 ++ .../log4j/core/TimestampMessageTest.java | 2 +- .../AsyncLoggerTimestampMessageTest.java | 2 +- .../log4j/core/filter/TimeFilterTest.java | 2 +- .../log4j/core/impl/Log4jLogEventTest.java | 2 +- .../log4j/core/time/ClockFactoryTest.java | 1 - .../log4j/core/time/SystemNanoClockTest.java | 1 - .../log4j/perf/jmh/ClocksBenchmark.java | 2 +- src/site/xdoc/manual/appenders.xml | 2 +- src/site/xdoc/manual/async.xml | 2 +- src/site/xdoc/manual/configuration.xml.vm | 2 +- 38 files changed, 116 insertions(+), 52 deletions(-) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/time/Clock.java create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/time/NanoClock.java diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java index 7a9ade9744b..5f87d7eeaa7 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java @@ -28,7 +28,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; import org.apache.logging.log4j.core.net.SocketAddress; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; /** * Appender plugin that uses a Cassandra database. diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java index be9611ddbc9..cbc5c1fe888 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java @@ -17,7 +17,7 @@ package org.apache.logging.log4j.cassandra; import com.datastax.driver.core.TimestampGenerator; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java index 5aba668c941..ffd740e2d46 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfLastModified.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.PluginFactory; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.status.StatusLogger; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java index e32f2101dd0..8f86588a109 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java @@ -30,9 +30,9 @@ import org.apache.logging.log4j.core.config.ReliabilityStrategy; import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; -import org.apache.logging.log4j.core.util.NanoClock; +import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; import org.apache.logging.log4j.message.ReusableMessage; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java index 9e5181538af..0a2964df412 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java @@ -27,6 +27,8 @@ import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Clock; +import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.core.util.*; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java index ec2ff1c897e..cac5d39b8aa 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java @@ -21,8 +21,8 @@ import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.core.ContextDataInjector; import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; -import org.apache.logging.log4j.core.util.Clock; -import org.apache.logging.log4j.core.util.NanoClock; +import org.apache.logging.log4j.core.time.Clock; +import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.message.Message; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java index 98f072ab645..a22468dc7bf 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java @@ -65,7 +65,7 @@ import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.core.util.NameUtil; -import org.apache.logging.log4j.core.util.NanoClock; +import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.core.util.WatchManager; import org.apache.logging.log4j.util.PropertiesUtil; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java index 95e6edcc17b..b2e5cb7f06a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.net.Advertiser; import org.apache.logging.log4j.core.script.ScriptManager; -import org.apache.logging.log4j.core.util.NanoClock; +import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.core.util.WatchManager; /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java index ba7ec99f5b0..491960b9072 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/TimeFilter.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginAttribute; import org.apache.logging.log4j.core.config.plugins.PluginFactory; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.PerformanceSensitive; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java index 248202c0c4e..455de65d9f2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java @@ -29,11 +29,9 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.ContextDataInjector; +import org.apache.logging.log4j.core.time.*; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; -import org.apache.logging.log4j.core.util.*; -import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.core.time.MutableInstant; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.async.RingBufferLogEvent; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java index d03223f5f9e..b427c4a272d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java @@ -26,6 +26,8 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.async.InternalAsyncUtil; +import org.apache.logging.log4j.core.time.Clock; +import org.apache.logging.log4j.core.time.NanoClock; import org.apache.logging.log4j.core.util.*; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java index 2a96007eeca..54041447b10 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java @@ -25,7 +25,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.async.ThreadNameCachingStrategy; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.util.StringMap; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Clock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Clock.java new file mode 100644 index 00000000000..a7a52a5a62e --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Clock.java @@ -0,0 +1,33 @@ +/* + * 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.time; + +/** + * Provides the time stamp used in log events. + *

+ * This interface replaces {@link org.apache.logging.log4j.core.util.Clock}. + *

+ * @since 2.11 + */ +public interface Clock { + /** + * Returns the time in milliseconds since the epoch. + * + * @return the time in milliseconds since the epoch + */ + long currentTimeMillis(); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/ClockFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/ClockFactory.java index ef6febf859e..d5721c4d84d 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/ClockFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/ClockFactory.java @@ -20,7 +20,6 @@ import org.apache.logging.log4j.core.time.internal.CoarseCachedClock; import org.apache.logging.log4j.core.time.internal.SystemClock; import org.apache.logging.log4j.core.time.internal.SystemMillisClock; -import org.apache.logging.log4j.core.util.Clock; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.PropertiesUtil; @@ -31,6 +30,9 @@ /** * Factory for {@code Clock} objects. + *

+ * This class replaces {@link org.apache.logging.log4j.core.util.ClockFactory}. + *

* @since 2.11 */ public final class ClockFactory { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java index c9609cd02a5..f41b6c1fe2b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/Instant.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.time; -import org.apache.logging.log4j.core.util.Clock; import org.apache.logging.log4j.util.StringBuilderFormattable; /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java index 6e27dd80cc4..303f75d8aef 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/MutableInstant.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.time; -import org.apache.logging.log4j.core.util.Clock; import org.apache.logging.log4j.util.PerformanceSensitive; import java.io.Serializable; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/NanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/NanoClock.java new file mode 100644 index 00000000000..3c1ed960cfb --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/NanoClock.java @@ -0,0 +1,36 @@ +/* + * 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.time; + +import org.apache.logging.log4j.core.LogEvent; + +/** + * Provides the {@link LogEvent#getNanoTime() high-resolution time stamp} used in log events. + *

+ * This interface replaces {@link org.apache.logging.log4j.core.util.NanoClock}. + *

+ * @since 2.11 + */ +public interface NanoClock { + /** + * Returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds. + * + * @return the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds + */ + long nanoTime(); +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java index a0ae3f6f51d..c81ffc7a069 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/PreciseClock.java @@ -16,8 +16,6 @@ */ package org.apache.logging.log4j.core.time; -import org.apache.logging.log4j.core.util.Clock; - /** * Extension of the {@link Clock} interface that is able to provide more accurate time information than milliseconds * since the epoch. {@code PreciseClock} implementations are free to return millisecond-precision time diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/SystemNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/SystemNanoClock.java index 13019e5f48d..75775348c6b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/SystemNanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/SystemNanoClock.java @@ -16,10 +16,11 @@ */ package org.apache.logging.log4j.core.time; -import org.apache.logging.log4j.core.util.NanoClock; - /** * Implementation of the {@code NanoClock} interface that returns the system nano time. + *

+ * This class replaces {@link org.apache.logging.log4j.core.util.SystemNanoClock}. + *

* @since 2.11 */ public final class SystemNanoClock implements NanoClock { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CachedClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CachedClock.java index 9ff7ebdba64..bfca6547645 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CachedClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CachedClock.java @@ -16,7 +16,7 @@ */ package org.apache.logging.log4j.core.time.internal; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.util.Log4jThread; import java.util.concurrent.locks.LockSupport; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CoarseCachedClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CoarseCachedClock.java index bbbc1bd1f2f..44793b1f2ab 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CoarseCachedClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/CoarseCachedClock.java @@ -16,7 +16,7 @@ */ package org.apache.logging.log4j.core.time.internal; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.util.Log4jThread; import java.util.concurrent.locks.LockSupport; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/DummyNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/DummyNanoClock.java index f89f6d8d228..445286ebd0f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/DummyNanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/DummyNanoClock.java @@ -16,7 +16,7 @@ */ package org.apache.logging.log4j.core.time.internal; -import org.apache.logging.log4j.core.util.NanoClock; +import org.apache.logging.log4j.core.time.NanoClock; /** * Implementation of the {@code NanoClock} interface that always returns a fixed value. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java index 0626149d0cf..473b0e877db 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemClock.java @@ -16,7 +16,7 @@ */ package org.apache.logging.log4j.core.time.internal; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; /** * Implementation of the {@code Clock} interface that returns the system time. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java index af266330670..82daab37215 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/SystemMillisClock.java @@ -16,7 +16,7 @@ */ package org.apache.logging.log4j.core.time.internal; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; /** * Implementation of the {@code Clock} interface that returns the system time in millisecond granularity. diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Clock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Clock.java index 87457dc357d..15d6f65e84f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Clock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Clock.java @@ -17,13 +17,9 @@ package org.apache.logging.log4j.core.util; /** - * Provides the time stamp used in log events. + * @deprecated Use {@link org.apache.logging.log4j.core.time.Clock} instead + * @see org.apache.logging.log4j.core.time.Clock */ -public interface Clock { - /** - * Returns the time in milliseconds since the epoch. - * - * @return the time in milliseconds since the epoch - */ - long currentTimeMillis(); +@Deprecated +public interface Clock extends org.apache.logging.log4j.core.time.Clock { } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java index abe26fb0d13..9ef4dbdcb2f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ClockFactory.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.util; +import org.apache.logging.log4j.core.time.Clock; + /** * @deprecated Use {@link org.apache.logging.log4j.core.time.ClockFactory} instead. */ diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java index 8fe8bf871e6..b1f3c35fc0c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java @@ -18,13 +18,9 @@ package org.apache.logging.log4j.core.util; /** - * Provides the high-resolution time stamp used in log events. + * @deprecated Use {@link org.apache.logging.log4j.core.time.NanoClock} instead + * @see org.apache.logging.log4j.core.time.NanoClock */ -public interface NanoClock { - /** - * Returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds. - * - * @return the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds - */ - long nanoTime(); +@Deprecated +public interface NanoClock extends org.apache.logging.log4j.core.time.NanoClock { } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java index 367b2aac448..d4ce19b98b7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/SystemNanoClock.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.util; +import org.apache.logging.log4j.core.time.NanoClock; + /** * @deprecated Use {@link org.apache.logging.log4j.core.time.SystemNanoClock} instead. */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java index abea8b02dad..188c6f890f3 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/TimestampMessageTest.java @@ -19,7 +19,7 @@ import java.util.List; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.apache.logging.log4j.core.util.Constants; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java index 35515536b76..fccb4f4f15d 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerTimestampMessageTest.java @@ -25,7 +25,7 @@ import org.apache.logging.log4j.categories.AsyncLoggers; import org.apache.logging.log4j.core.CoreLoggerContexts; import org.apache.logging.log4j.core.config.ConfigurationFactory; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.apache.logging.log4j.core.util.Constants; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java index 117de29a704..c6da0e8bda2 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/filter/TimeFilterTest.java @@ -23,7 +23,7 @@ import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.junit.AfterClass; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java index 1a9a66d1415..4489564c6bd 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java @@ -38,7 +38,7 @@ import org.apache.logging.log4j.ThreadContext.ContextStack; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.convert.Base64Converter; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.ClockFactory; import org.apache.logging.log4j.core.time.ClockFactoryTest; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/ClockFactoryTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/ClockFactoryTest.java index 203c70b4d48..17e184d7476 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/ClockFactoryTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/ClockFactoryTest.java @@ -22,7 +22,6 @@ import org.apache.logging.log4j.core.time.internal.CachedClock; import org.apache.logging.log4j.core.time.internal.CoarseCachedClock; import org.apache.logging.log4j.core.time.internal.SystemClock; -import org.apache.logging.log4j.core.util.Clock; import org.junit.Before; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/SystemNanoClockTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/SystemNanoClockTest.java index 00b01eec563..5ab94049a91 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/time/SystemNanoClockTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/SystemNanoClockTest.java @@ -17,7 +17,6 @@ package org.apache.logging.log4j.core.time; -import org.apache.logging.log4j.core.util.NanoClock; import org.junit.Test; import java.util.concurrent.TimeUnit; diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java index 5872c5afaa7..ff778d250f1 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ClocksBenchmark.java @@ -21,7 +21,7 @@ import java.util.concurrent.locks.LockSupport; import org.apache.logging.log4j.core.time.internal.CachedClock; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.internal.CoarseCachedClock; import org.apache.logging.log4j.core.time.internal.SystemClock; import org.openjdk.jmh.annotations.Benchmark; diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index f4bba1a3fd9..038fc2ca614 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -345,7 +345,7 @@ useClockForTimestampGenerator boolean - Whether or not to use the configured org.apache.logging.log4j.core.util.Clock as a + Whether or not to use the configured org.apache.logging.log4j.core.time.Clock as a TimestampGenerator. By default, this is false. diff --git a/src/site/xdoc/manual/async.xml b/src/site/xdoc/manual/async.xml index 48340b6d90a..59b14c72887 100644 --- a/src/site/xdoc/manual/async.xml +++ b/src/site/xdoc/manual/async.xml @@ -275,7 +275,7 @@

- Implementation of the org.apache.logging.log4j.core.util.Clock + Implementation of the org.apache.logging.log4j.core.time.Clock interface that is used for timestamping the log events when all loggers are asynchronous.
By default, System.currentTimeMillis is called on every log event. diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm index 77c5f827275..525baa108fd 100644 --- a/src/site/xdoc/manual/configuration.xml.vm +++ b/src/site/xdoc/manual/configuration.xml.vm @@ -1742,7 +1742,7 @@ public class AwesomeTest { log4j.Clock SystemClock - Implementation of the org.apache.logging.log4j.core.util.Clock + Implementation of the org.apache.logging.log4j.core.time.Clock interface that is used for timestamping the log events.
By default, System.currentTimeMillis is called on every log event. From 636b0934618051f7edeadba5a95798b1820f3142 Mon Sep 17 00:00:00 2001 From: rpopma Date: Tue, 30 Jan 2018 00:47:15 +0900 Subject: [PATCH 0016/2347] LOG4J2-2191 better module description --- log4j-core-java9/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-core-java9/pom.xml b/log4j-core-java9/pom.xml index b46f8c91044..2da8629595c 100644 --- a/log4j-core-java9/pom.xml +++ b/log4j-core-java9/pom.xml @@ -25,7 +25,7 @@ log4j-core-java9 pom - Apache Log4j Implementation Java 9 support + Apache Log4j Core Java 9 support The Apache Log4j Implementation (Java 9) ${basedir}/.. From d58aa1e037a7af31183caf399bc786a441f10c44 Mon Sep 17 00:00:00 2001 From: rpopma Date: Tue, 30 Jan 2018 00:50:12 +0900 Subject: [PATCH 0017/2347] LOG4J2-2225 update change log --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 21e123ecf72..ce95f6a97ab 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -31,6 +31,9 @@ - "remove" - Removed --> + + Moved time-related classes from core.util to core.time. Classes considered private moved to core.time.internal. + Added support for precise (micro and nanosecond) timestamps when running on Java 9. A limited number of precise %d date formats are supported with PatternLayout. POTENTIAL BREAKING CHANGE: The XML, JSON and YAML formats have changed: they no longer have the "timeMillis" attribute and instead have an "Instant" element with "epochSecond" and "nanoOfSecond" attributes. From 9b2345ea2437649bd35374bff6d764e0ea96d9d6 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 08:50:24 -0700 Subject: [PATCH 0018/2347] [LOG4J2-2232] Move JMS code to a new module log4j-jms. --- RELEASE-NOTES.md | 10 + log4j-core/pom.xml | 7 - .../appender/nosql/NoSqlDatabaseManager.java | 2 - log4j-jms/pom.xml | 179 ++++++++++++++++++ .../log4j/jms/appender}/JmsAppender.java | 4 +- .../log4j/jms/appender}/JmsManager.java | 2 +- .../log4j/jms/appender}/package-info.java | 2 +- log4j-jms/src/site/manual/index.md | 33 ++++ log4j-jms/src/site/site.xml | 52 +++++ .../log4j/jms/appender}/JmsAppenderTest.java | 21 +- pom.xml | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/appenders.xml | 3 + 13 files changed, 296 insertions(+), 23 deletions(-) create mode 100644 log4j-jms/pom.xml rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom => log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender}/JmsAppender.java (98%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom => log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender}/JmsManager.java (99%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom => log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender}/package-info.java (94%) create mode 100644 log4j-jms/src/site/manual/index.md create mode 100644 log4j-jms/src/site/site.xml rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom => log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender}/JmsAppenderTest.java (99%) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 4908ebb6f46..ed4a5912224 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -25,6 +25,16 @@ The new modules are: * Old package: `org.apache.logging.log4j.core.appender.mom.jeromq` * New package: `org.apache.logging.log4j.jeromq.appender` +### log4j-jms + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-jms` + +* Old package 1: `org.apache.logging.log4j.core.appender.mom` +* New package 1: `org.apache.logging.log4j.jms.appender` + + + ### log4j-jpa * Group ID: `org.apache.logging.log4j` diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index fab1712fe46..dab3328dfc2 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -107,13 +107,6 @@ jansi true - - - org.jboss.spec.javax.jms - jboss-jms-api_1.1_spec - provided - true - org.apache.commons diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java index 80acae7c5f1..7e2cad81cab 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManager.java @@ -18,8 +18,6 @@ import java.io.Serializable; -import javax.jms.JMSException; - import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; diff --git a/log4j-jms/pom.xml b/log4j-jms/pom.xml new file mode 100644 index 00000000000..0584cd0bc9c --- /dev/null +++ b/log4j-jms/pom.xml @@ -0,0 +1,179 @@ + + + + + + org.apache.logging.log4j + log4j + 2.10.1-SNAPSHOT + + 4.0.0 + + log4j-jms + Apache Log4j JMS + + Apache Log4j Java Message Service (JMS). + + + ${basedir}/.. + Log4j JMS Documentation + /log4j-jms + org.apache.logging.log4j.jms + + + + + org.apache.logging.log4j + log4j-core + + + + org.jboss.spec.javax.jms + jboss-jms-api_1.1_spec + provided + true + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + + org.mockito + mockito-core + test + + + + org.springframework + spring-test + test + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.core.appender.mom.jeromq + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]> + + false + true +
+ + + non-aggregate + + javadoc + + + + + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + + + + diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java rename to log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java index 17040186d82..a26b6b09db6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsAppender.java +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsAppender.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom; +package org.apache.logging.log4j.jms.appender; import java.io.Serializable; import java.util.Properties; @@ -29,7 +29,6 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.appender.AbstractManager; -import org.apache.logging.log4j.core.appender.mom.JmsManager.JmsManagerConfiguration; import org.apache.logging.log4j.core.config.Node; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginAliases; @@ -38,6 +37,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; import org.apache.logging.log4j.core.net.JndiManager; +import org.apache.logging.log4j.jms.appender.JmsManager.JmsManagerConfiguration; /** * Generic JMS Appender plugin for both queues and topics. This Appender replaces the previous split ones. However, diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsManager.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java rename to log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsManager.java index f7794e664b7..49a7e7f817a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/JmsManager.java +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/JmsManager.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom; +package org.apache.logging.log4j.jms.appender; import java.io.Serializable; import java.util.Properties; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/package-info.java b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/package-info.java similarity index 94% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/package-info.java rename to log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/package-info.java index 866b689c777..afca4f267f8 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/mom/package-info.java +++ b/log4j-jms/src/main/java/org/apache/logging/log4j/jms/appender/package-info.java @@ -20,4 +20,4 @@ * * @since 2.1 */ -package org.apache.logging.log4j.core.appender.mom; +package org.apache.logging.log4j.jms.appender; diff --git a/log4j-jms/src/site/manual/index.md b/log4j-jms/src/site/manual/index.md new file mode 100644 index 00000000000..8ef1b4754c0 --- /dev/null +++ b/log4j-jms/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j Java Message Service (JMS) module + +As of Log4j 2.11.0, JMS support has moved from the existing module logj-core to the new module log4j-jms. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires a JMS API JAR. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-jms/src/site/site.xml b/log4j-jms/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-jms/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java b/log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender/JmsAppenderTest.java similarity index 99% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java rename to log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender/JmsAppenderTest.java index d48167e5698..492171927ff 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/mom/JmsAppenderTest.java +++ b/log4j-jms/src/test/java/org/apache/logging/log4j/jms/appender/JmsAppenderTest.java @@ -15,11 +15,21 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.mom; +package org.apache.logging.log4j.jms.appender; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import java.io.Serializable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; @@ -41,15 +51,6 @@ import org.junit.experimental.categories.Category; import org.junit.rules.RuleChain; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; - @Category(Appenders.Jms.class) public class JmsAppenderTest { diff --git a/pom.xml b/pom.xml index 00b8bda59c6..1ae7f777104 100644 --- a/pom.xml +++ b/pom.xml @@ -1338,6 +1338,7 @@ log4j-jdbc-dbcp2 log4j-jpa log4j-jeromq + log4j-jms log4j-kafka log4j-couchdb log4j-mongodb2 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 21e123ecf72..60aeb6f8051 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -176,6 +176,9 @@ Move CSV layout from log4j-core to a new module log4j-csv. + + Move JMS code to a new module log4j-jms. + diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index f4bba1a3fd9..b6cb7c68684 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -1416,6 +1416,9 @@ public class ConnectionFactory { +

+ As of Log4j 2.11.0, JPA support has moved from the existing module logj-core to the new module log4j-jms. +

The JMS Appender sends the formatted log event to a JMS Destination.

Note that in Log4j 2.0, this appender was split into a JMSQueueAppender and a JMSTopicAppender. Starting From a267906a4ee4c6ea0f249f0fcaf27e70d9535b7f Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 08:54:21 -0700 Subject: [PATCH 0019/2347] [LOG4J2-2232] Move JMS code to a new module log4j-jms. --- log4j-bom/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index b8ea992c0a8..7539d544e97 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -72,6 +72,12 @@ log4j-jeromq ${project.version} + + + org.apache.logging.log4j + log4j-jms + ${project.version} + org.apache.logging.log4j From 2b90040e4f116debb9304992fbeb3d787cc43bb5 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 08:57:42 -0700 Subject: [PATCH 0020/2347] [LOG4J2-2232] Move JMS code to a new module log4j-jms. Forgot about this Fragment-Host business. --- log4j-jms/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-jms/pom.xml b/log4j-jms/pom.xml index 0584cd0bc9c..db1b029f6bd 100644 --- a/log4j-jms/pom.xml +++ b/log4j-jms/pom.xml @@ -76,7 +76,7 @@ maven-bundle-plugin - org.apache.logging.log4j.core.appender.mom.jeromq + org.apache.logging.log4j.jms.appender * From 925f5d0f3ff51abcaae907594f5f1c345030978a Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 08:59:14 -0700 Subject: [PATCH 0021/2347] Add log4j-jdbc-dbcp2. --- log4j-bom/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index 7539d544e97..e98e6811274 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -54,6 +54,12 @@ log4j-jcl ${project.version} + + + org.apache.logging.log4j + log4j-jdbc-dbcp2 + ${project.version} + org.apache.logging.log4j From 14d0150f48fbbc7579e3783e5c6277f8d8b44be8 Mon Sep 17 00:00:00 2001 From: rpopma Date: Tue, 30 Jan 2018 01:57:46 +0900 Subject: [PATCH 0022/2347] LOG4J2-2224 Renamed package core.util.datetime to core.time.internal.format to clarify these classes are to be considered private. --- .../core/pattern/DatePatternConverter.java | 6 +-- .../internal/format}/DateParser.java | 2 +- .../internal/format}/DatePrinter.java | 2 +- .../internal/format}/FastDateFormat.java | 2 +- .../internal/format}/FastDateParser.java | 2 +- .../internal/format}/FastDatePrinter.java | 2 +- .../internal/format}/FixedDateFormat.java | 2 +- .../internal/format}/Format.java | 2 +- .../internal/format}/FormatCache.java | 2 +- .../internal/format}/package-info.java | 2 +- .../logging/log4j/core/util/NanoClock.java | 52 +++++++++---------- .../OnStartupTriggeringPolicyTest.java | 2 +- ...ngAppenderDeleteAccumulatedCount1Test.java | 4 +- ...ngAppenderDeleteAccumulatedCount2Test.java | 4 +- ...lingAppenderDeleteAccumulatedSizeTest.java | 4 +- .../RollingAppenderDeleteNestedTest.java | 4 +- .../pattern/DatePatternConverterTest.java | 2 +- .../format}/FastDateParserSDFTest.java | 4 +- .../internal/format}/FastDateParserTest.java | 6 ++- .../FastDateParser_MoreOrLessTest.java | 3 +- .../FastDateParser_TimeZoneStrategyTest.java | 3 +- .../internal/format}/FixedDateFormatTest.java | 7 +-- .../jmh/ThreadsafeDateFormatBenchmark.java | 4 +- .../log4j/perf/jmh/TimeFormatBenchmark.java | 4 +- src/changes/changes.xml | 3 ++ 25 files changed, 71 insertions(+), 59 deletions(-) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/DateParser.java (98%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/DatePrinter.java (98%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FastDateFormat.java (99%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FastDateParser.java (99%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FastDatePrinter.java (99%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FixedDateFormat.java (99%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/Format.java (96%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FormatCache.java (99%) rename log4j-core/src/main/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/package-info.java (93%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FastDateParserSDFTest.java (98%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FastDateParserTest.java (98%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FastDateParser_MoreOrLessTest.java (97%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FastDateParser_TimeZoneStrategyTest.java (95%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/{util/datetime => time/internal/format}/FixedDateFormatTest.java (98%) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java index ca65d4d7dc2..049c9aea72b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java @@ -27,9 +27,9 @@ import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; -import org.apache.logging.log4j.core.util.datetime.FastDateFormat; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat; +import org.apache.logging.log4j.core.time.internal.format.FastDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedFormat; import org.apache.logging.log4j.util.PerformanceSensitive; /** diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DateParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/DateParser.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DateParser.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/DateParser.java index 16940c6fa7d..56251998c82 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DateParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/DateParser.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.ParseException; import java.text.ParsePosition; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DatePrinter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/DatePrinter.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DatePrinter.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/DatePrinter.java index 91f5e1a0ad9..8f93347609f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DatePrinter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/DatePrinter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.FieldPosition; import java.util.Calendar; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateFormat.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDateFormat.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateFormat.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDateFormat.java index db38bd12e9c..fe0c4c2365c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateFormat.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDateFormat.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.DateFormat; import java.text.FieldPosition; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateParser.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser.java index 4ba56685728..ce0bc4edbc6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.io.IOException; import java.io.ObjectInputStream; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDatePrinter.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDatePrinter.java index 4f33b6bd118..0798fcd738c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDatePrinter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FastDatePrinter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.io.IOException; import java.io.ObjectInputStream; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FixedDateFormat.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FixedDateFormat.java index f814b62201f..415c835c6c9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormat.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FixedDateFormat.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import org.apache.logging.log4j.core.time.Instant; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/Format.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/Format.java similarity index 96% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/Format.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/Format.java index a4a2f6951ea..f87e2fdc4e2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/Format.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/Format.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.FieldPosition; import java.text.ParseException; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FormatCache.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FormatCache.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FormatCache.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FormatCache.java index e146a1dda2a..f1eff096ae9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FormatCache.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/FormatCache.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.DateFormat; import java.text.SimpleDateFormat; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/package-info.java similarity index 93% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/package-info.java rename to log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/package-info.java index 31b2b4cc07d..aec2664fa43 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/package-info.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/time/internal/format/package-info.java @@ -17,4 +17,4 @@ /** * Log4j 2 date formatting classes. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java index b1f3c35fc0c..a0afda66057 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NanoClock.java @@ -1,26 +1,26 @@ -/* - * 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.util; - -/** - * @deprecated Use {@link org.apache.logging.log4j.core.time.NanoClock} instead - * @see org.apache.logging.log4j.core.time.NanoClock - */ -@Deprecated -public interface NanoClock extends org.apache.logging.log4j.core.time.NanoClock { -} +/* + * 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.util; + +/** + * @deprecated Use {@link org.apache.logging.log4j.core.time.NanoClock} instead + * @see org.apache.logging.log4j.core.time.NanoClock + */ +@Deprecated +public interface NanoClock extends org.apache.logging.log4j.core.time.NanoClock { +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicyTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicyTest.java index f05e4e2ef2f..7ef9d920f24 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicyTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicyTest.java @@ -31,7 +31,7 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.layout.PatternLayout; -import org.apache.logging.log4j.core.util.datetime.FastDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FastDateFormat; import org.apache.logging.log4j.junit.CleanFolders; import org.junit.Assert; import org.junit.Rule; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java index 23dcffa85ac..b9d627b5e78 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount1Test.java @@ -32,8 +32,8 @@ import java.util.List; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedFormat; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.Rule; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java index f6362752f85..f27f7c4844a 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedCount2Test.java @@ -32,8 +32,8 @@ import java.util.List; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedFormat; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.Rule; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java index f580b79d95c..d7ef4bbc449 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteAccumulatedSizeTest.java @@ -23,8 +23,8 @@ import java.util.Arrays; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedFormat; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.Rule; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java index 7d335f03e13..134d621acb2 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderDeleteNestedTest.java @@ -32,8 +32,8 @@ import java.util.List; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedFormat; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.Rule; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java index 728254a827a..ae53cc26b7b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTest.java @@ -30,7 +30,7 @@ import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserSDFTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParserSDFTest.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserSDFTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParserSDFTest.java index 247dad81cd8..b8e02d62f33 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserSDFTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParserSDFTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -30,6 +30,8 @@ import java.util.Locale; import java.util.TimeZone; +import org.apache.logging.log4j.core.time.internal.format.DateParser; +import org.apache.logging.log4j.core.time.internal.format.FastDateParser; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParserTest.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParserTest.java index 546780b1de9..4aee15dafa0 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParserTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -34,6 +34,10 @@ import org.apache.commons.lang3.LocaleUtils; import org.apache.commons.lang3.SerializationUtils; +import org.apache.logging.log4j.core.time.internal.format.DateParser; +import org.apache.logging.log4j.core.time.internal.format.FastDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FastDateParser; +import org.apache.logging.log4j.core.time.internal.format.FormatCache; import org.junit.Assert; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParser_MoreOrLessTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser_MoreOrLessTest.java similarity index 97% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParser_MoreOrLessTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser_MoreOrLessTest.java index 0caa8becc80..fa180eb2886 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParser_MoreOrLessTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser_MoreOrLessTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.ParsePosition; import java.util.Calendar; @@ -22,6 +22,7 @@ import java.util.Locale; import java.util.TimeZone; +import org.apache.logging.log4j.core.time.internal.format.FastDateParser; import org.junit.Assert; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParser_TimeZoneStrategyTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser_TimeZoneStrategyTest.java similarity index 95% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParser_TimeZoneStrategyTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser_TimeZoneStrategyTest.java index 64d5ed35bbf..e5bb3f98dbd 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParser_TimeZoneStrategyTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FastDateParser_TimeZoneStrategyTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.DateFormatSymbols; import java.text.ParseException; @@ -22,6 +22,7 @@ import java.util.Locale; import java.util.TimeZone; +import org.apache.logging.log4j.core.time.internal.format.FastDateParser; import org.junit.Assert; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FixedDateFormatTest.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FixedDateFormatTest.java index e41c4e12643..c254ca15438 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/datetime/FixedDateFormatTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/time/internal/format/FixedDateFormatTest.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.util.datetime; +package org.apache.logging.log4j.core.time.internal.format; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -24,10 +24,11 @@ import java.util.TimeZone; import java.util.concurrent.TimeUnit; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedFormat; import org.junit.Test; -import static org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat.*; +import static org.apache.logging.log4j.core.time.internal.format.FixedDateFormat.FixedFormat.*; import static org.junit.Assert.*; /** diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java index 885c3578b14..59ac56f646d 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java @@ -22,8 +22,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; -import org.apache.logging.log4j.core.util.datetime.FastDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FastDateFormat; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TimeFormatBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TimeFormatBenchmark.java index 74e76f7e281..fd462c299ff 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TimeFormatBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TimeFormatBenchmark.java @@ -23,8 +23,8 @@ import java.util.Date; import java.util.concurrent.TimeUnit; -import org.apache.logging.log4j.core.util.datetime.FixedDateFormat; -import org.apache.logging.log4j.core.util.datetime.FastDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FixedDateFormat; +import org.apache.logging.log4j.core.time.internal.format.FastDateFormat; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 75e7044e051..95801c021ce 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -31,6 +31,9 @@ - "remove" - Removed --> + + Renamed package core.util.datetime to core.time.internal.format to clarify these classes are to be considered private. + Moved time-related classes from core.util to core.time. Classes considered private moved to core.time.internal. From 6fc3f6d3f70d7ea49954db9f39c115ab546e4eda Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 11:15:53 -0700 Subject: [PATCH 0023/2347] Add new modules. --- log4j-distribution/pom.xml | 169 ++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 4 deletions(-) diff --git a/log4j-distribution/pom.xml b/log4j-distribution/pom.xml index 8a5b6f228bb..98217a1237d 100644 --- a/log4j-distribution/pom.xml +++ b/log4j-distribution/pom.xml @@ -28,6 +28,7 @@ Log4j Distribution The Apache Log4j distribution archives. + org.apache.logging.log4j log4j-api @@ -45,6 +46,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-core @@ -68,6 +70,25 @@ ${project.version} tests + + + org.apache.logging.log4j + log4j-csv + ${project.version} + + + org.apache.logging.log4j + log4j-csv + ${project.version} + sources + + + org.apache.logging.log4j + log4j-csv + ${project.version} + javadoc + + org.apache.logging.log4j log4j-iostreams @@ -85,6 +106,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-jcl @@ -102,6 +124,79 @@ ${project.version} javadoc + + + org.apache.logging.log4j + log4j-jdbc-dbcp2 + ${project.version} + + + org.apache.logging.log4j + log4j-jdbc-dbcp2 + ${project.version} + sources + + + org.apache.logging.log4j + log4j-jdbc-dbcp2 + ${project.version} + javadoc + + + + org.apache.logging.log4j + log4j-jeromq + ${project.version} + + + org.apache.logging.log4j + log4j-jeromq + ${project.version} + sources + + + org.apache.logging.log4j + log4j-jeromq + ${project.version} + javadoc + + + + org.apache.logging.log4j + log4j-jms + ${project.version} + + + org.apache.logging.log4j + log4j-jms + ${project.version} + sources + + + org.apache.logging.log4j + log4j-jms + ${project.version} + javadoc + + + + org.apache.logging.log4j + log4j-jpa + ${project.version} + + + org.apache.logging.log4j + log4j-jpa + ${project.version} + sources + + + org.apache.logging.log4j + log4j-jpa + ${project.version} + javadoc + + org.apache.logging.log4j log4j-jul @@ -119,6 +214,25 @@ ${project.version} javadoc + + + org.apache.logging.log4j + log4j-kafka + ${project.version} + + + org.apache.logging.log4j + log4j-kafka + ${project.version} + sources + + + org.apache.logging.log4j + log4j-kafka + ${project.version} + javadoc + + org.apache.logging.log4j log4j-flume-ng @@ -136,6 +250,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-1.2-api @@ -153,6 +268,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-slf4j-impl @@ -170,6 +286,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-to-slf4j @@ -187,6 +304,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-jmx-gui @@ -204,6 +322,25 @@ ${project.version} javadoc + + + org.apache.logging.log4j + log4j-smtp + ${project.version} + + + org.apache.logging.log4j + log4j-smtp + ${project.version} + sources + + + org.apache.logging.log4j + log4j-smtp + ${project.version} + javadoc + + org.apache.logging.log4j log4j-taglib @@ -221,6 +358,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-web @@ -238,6 +376,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-couchdb @@ -255,6 +394,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-mongodb2 @@ -272,6 +412,25 @@ ${project.version} javadoc + + + org.apache.logging.log4j + log4j-mongodb3 + ${project.version} + + + org.apache.logging.log4j + log4j-mongodb3 + ${project.version} + sources + + + org.apache.logging.log4j + log4j-mongodb3 + ${project.version} + javadoc + + org.apache.logging.log4j log4j-cassandra @@ -289,11 +448,12 @@ ${project.version} javadoc + - org.apache.logging.log4j - log4j-liquibase - ${project.version} - + org.apache.logging.log4j + log4j-liquibase + ${project.version} + org.apache.logging.log4j log4j-liquibase @@ -306,6 +466,7 @@ ${project.version} javadoc + org.apache.logging.log4j log4j-appserver From 4a2ac2dcb0220fd54ae168d9e0e0a0904c150a49 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 12:12:33 -0700 Subject: [PATCH 0024/2347] This test does not need to depend on java.sql.SQLException. --- .../log4j/core/appender/OutputStreamAppenderTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java index d3ffa387ef8..8dcc97f7cd6 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/OutputStreamAppenderTest.java @@ -19,7 +19,6 @@ import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; -import java.sql.SQLException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -60,7 +59,7 @@ private void addAppender(final OutputStream outputStream, final String outputStr } @Test - public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException { + public void testOutputStreamAppenderToBufferedOutputStream() { final ByteArrayOutputStream out = new ByteArrayOutputStream(); final OutputStream os = new BufferedOutputStream(out); final String name = getName(out); @@ -72,7 +71,7 @@ public void testOutputStreamAppenderToBufferedOutputStream() throws SQLException } @Test - public void testOutputStreamAppenderToByteArrayOutputStream() throws SQLException { + public void testOutputStreamAppenderToByteArrayOutputStream() { final OutputStream out = new ByteArrayOutputStream(); final String name = getName(out); final Logger logger = LogManager.getLogger(name); From 887ab6636d241881630c35e7ecc638d0ad0c5a6c Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 12:14:28 -0700 Subject: [PATCH 0025/2347] This test does not need to depend on java.sql.SQLException. --- .../core/appender/WriterAppenderTest.java | 207 +++++++++--------- 1 file changed, 103 insertions(+), 104 deletions(-) diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java index fff28e229a8..abde0d6be6c 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/WriterAppenderTest.java @@ -1,104 +1,103 @@ -/* - * 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 java.io.ByteArrayOutputStream; -import java.io.CharArrayWriter; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.sql.SQLException; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.layout.PatternLayout; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -/** - * Tests {@link WriterAppender}. - */ -public class WriterAppenderTest { - - private static final String TEST_MSG = "FOO ERROR"; - - @Rule - public TestName testName = new TestName(); - - private String getName(final Writer writer) { - return writer.getClass().getSimpleName() + "." + testName.getMethodName(); - } - - private void test(final ByteArrayOutputStream out, final Writer writer) throws SQLException { - final String name = getName(writer); - addAppender(writer, name); - final Logger logger = LogManager.getLogger(name); - logger.error(TEST_MSG); - final String actual = out.toString(); - Assert.assertTrue(actual, actual.contains(TEST_MSG)); - } - - private void test(final Writer writer) throws SQLException { - final String name = getName(writer); - addAppender(writer, name); - final Logger logger = LogManager.getLogger(name); - logger.error(TEST_MSG); - final String actual = writer.toString(); - Assert.assertTrue(actual, actual.contains(TEST_MSG)); - } - - private void addAppender(final Writer writer, final String writerName) { - final LoggerContext context = LoggerContext.getContext(false); - final Configuration config = context.getConfiguration(); - final PatternLayout layout = PatternLayout.createDefaultLayout(config); - final Appender appender = WriterAppender.createAppender(layout, null, writer, writerName, false, true); - appender.start(); - config.addAppender(appender); - ConfigurationTestUtils.updateLoggers(appender, config); - } - - @Test - public void testWriterAppenderToCharArrayWriter() throws SQLException { - test(new CharArrayWriter()); - } - - @Test - public void testWriterAppenderToOutputStreamWriter() throws SQLException { - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final Writer writer = new OutputStreamWriter(out); - test(out, writer); - } - - @Test - public void testWriterAppenderToPrintWriter() throws SQLException { - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final Writer writer = new PrintWriter(out); - test(out, writer); - } - - @Test - public void testWriterAppenderToStringWriter() throws SQLException { - test(new StringWriter()); - } - -} +/* + * 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 java.io.ByteArrayOutputStream; +import java.io.CharArrayWriter; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +/** + * Tests {@link WriterAppender}. + */ +public class WriterAppenderTest { + + private static final String TEST_MSG = "FOO ERROR"; + + @Rule + public TestName testName = new TestName(); + + private String getName(final Writer writer) { + return writer.getClass().getSimpleName() + "." + testName.getMethodName(); + } + + private void test(final ByteArrayOutputStream out, final Writer writer) { + final String name = getName(writer); + addAppender(writer, name); + final Logger logger = LogManager.getLogger(name); + logger.error(TEST_MSG); + final String actual = out.toString(); + Assert.assertTrue(actual, actual.contains(TEST_MSG)); + } + + private void test(final Writer writer) { + final String name = getName(writer); + addAppender(writer, name); + final Logger logger = LogManager.getLogger(name); + logger.error(TEST_MSG); + final String actual = writer.toString(); + Assert.assertTrue(actual, actual.contains(TEST_MSG)); + } + + private void addAppender(final Writer writer, final String writerName) { + final LoggerContext context = LoggerContext.getContext(false); + final Configuration config = context.getConfiguration(); + final PatternLayout layout = PatternLayout.createDefaultLayout(config); + final Appender appender = WriterAppender.createAppender(layout, null, writer, writerName, false, true); + appender.start(); + config.addAppender(appender); + ConfigurationTestUtils.updateLoggers(appender, config); + } + + @Test + public void testWriterAppenderToCharArrayWriter() { + test(new CharArrayWriter()); + } + + @Test + public void testWriterAppenderToOutputStreamWriter() { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final Writer writer = new OutputStreamWriter(out); + test(out, writer); + } + + @Test + public void testWriterAppenderToPrintWriter() { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final Writer writer = new PrintWriter(out); + test(out, writer); + } + + @Test + public void testWriterAppenderToStringWriter() { + test(new StringWriter()); + } + +} From 1408a5d568f7f01c1dd2c4d457b7ca481eac11cf Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 12:17:42 -0700 Subject: [PATCH 0026/2347] This test does not need to depend on java.sql.SQLException. --- .../nosql/NoSqlDatabaseManagerTest.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java index 772a947d800..1881490737c 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java @@ -16,8 +16,16 @@ */ package org.apache.logging.log4j.core.appender.nosql; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; + import java.io.IOException; -import java.sql.SQLException; import java.util.Collection; import java.util.Date; import java.util.HashMap; @@ -45,12 +53,6 @@ import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; - @RunWith(MockitoJUnitRunner.class) public class NoSqlDatabaseManagerTest { @Mock @@ -291,7 +293,7 @@ public void testWriteInternal03() { then(provider).should().getConnection(); final IOException exception1 = new IOException("This is the cause."); - final SQLException exception2 = new SQLException("This is the result.", exception1); + final IllegalStateException exception2 = new IllegalStateException("This is the result.", exception1); final Map context = new HashMap<>(); context.put("hello", "world"); context.put("user", "pass"); @@ -377,7 +379,7 @@ public void testWriteInternal03() { assertTrue("The thrown should be a map.", object.get("thrown") instanceof Map); @SuppressWarnings("unchecked") final Map thrown = (Map) object.get("thrown"); - assertEquals("The thrown type is not correct.", "java.sql.SQLException", thrown.get("type")); + assertEquals("The thrown type is not correct.", "java.lang.IllegalStateException", thrown.get("type")); assertEquals("The thrown message is not correct.", "This is the result.", thrown.get("message")); assertTrue("The thrown stack trace should be a list.", thrown.get("stackTrace") instanceof List); @SuppressWarnings("unchecked") From 83f6a18a11e0f5769289feacdad81bfb29d3b208 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 12:26:27 -0700 Subject: [PATCH 0027/2347] Fix generics compiler warnings. --- .../log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java index 1881490737c..63ae624e27e 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/nosql/NoSqlDatabaseManagerTest.java @@ -175,9 +175,9 @@ public void testWriteInternal01() { assertNull("The thrown should be null.", object.get("thrown")); - assertTrue("The context map should be empty.", ((Map) object.get("contextMap")).isEmpty()); + assertTrue("The context map should be empty.", ((Map) object.get("contextMap")).isEmpty()); - assertTrue("The context stack should be null.", ((Collection) object.get("contextStack")).isEmpty()); + assertTrue("The context stack should be null.", ((Collection) object.get("contextStack")).isEmpty()); } } From b5d4655d32b394e4c278ff1999a3c8473fda34dd Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 29 Jan 2018 13:03:17 -0700 Subject: [PATCH 0028/2347] [LOG4J2-2233] Move JDBC code to a new module log4j-jdbc. --- RELEASE-NOTES.md | 8 + log4j-bom/pom.xml | 8 +- log4j-cassandra/pom.xml | 6 + .../log4j/cassandra/CassandraManager.java | 2 +- log4j-distribution/pom.xml | 18 ++ log4j-jdbc-dbcp2/pom.xml | 11 + .../PoolingDriverConnectionSource.java | 4 +- .../PoolingDriverConnectionSourceTest.java | 7 +- log4j-jdbc/pom.xml | 210 ++++++++++++++++++ .../appender}/AbstractConnectionSource.java | 2 +- ...AbstractDriverManagerConnectionSource.java | 2 +- .../log4j/jdbc/appender}/ColumnConfig.java | 2 +- .../jdbc/appender}/ConnectionSource.java | 2 +- .../appender}/DataSourceConnectionSource.java | 2 +- .../DriverManagerConnectionSource.java | 2 +- .../FactoryMethodConnectionSource.java | 2 +- .../log4j/jdbc/appender}/JdbcAppender.java | 2 +- .../jdbc/appender}/JdbcDatabaseManager.java | 4 +- .../log4j/jdbc/appender}/package-info.java | 2 +- .../jdbc}/convert/DateTypeConverter.java | 2 +- log4j-jdbc/src/site/manual/index.md | 33 +++ log4j-jdbc/src/site/site.xml | 52 +++++ .../AbstractJdbcAppenderDataSourceTest.java | 5 +- ...AbstractJdbcAppenderFactoryMethodTest.java | 6 +- .../jdbc/appender}/ColumnConfigTest.java | 3 +- .../DataSourceConnectionSourceTest.java | 3 +- .../DriverManagerConnectionSourceTest.java | 3 +- .../FactoryMethodConnectionSourceTest.java | 3 +- .../JdbcAppenderH2DataSourceTest.java | 4 +- .../JdbcAppenderH2FactoryMethodTest.java | 4 +- .../JdbcAppenderHsqldbDataSourceTest.java | 4 +- .../JdbcAppenderHsqldbFactoryMethodTest.java | 4 +- .../JdbcAppenderMapMessageDataSourceTest.java | 5 +- .../jdbc/appender}/JdbcH2TestHelper.java | 5 +- .../log4j/jdbc/appender}/JdbcRule.java | 5 +- .../jdbc}/convert/DateTypeConverterTest.java | 3 +- .../src/test/resources/log4j-fatalOnly.xml | 0 .../log4j2-data-source-map-message.xml | 2 +- .../jdbc/appender}/log4j2-data-source.xml | 2 +- .../appender}/log4j2-h2-factory-method.xml | 4 +- .../log4j2-hsqldb-factory-method.xml | 4 +- log4j-perf/pom.xml | 7 +- .../log4j/perf/jmh/JdbcAppenderBenchmark.java | 2 +- pom.xml | 1 + src/changes/changes.xml | 3 + src/site/xdoc/manual/appenders.xml | 3 + 46 files changed, 413 insertions(+), 55 deletions(-) rename log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/{db/jdbc => dbcp2}/appender/PoolingDriverConnectionSourceTest.java (91%) create mode 100644 log4j-jdbc/pom.xml rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/AbstractConnectionSource.java (94%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/AbstractDriverManagerConnectionSource.java (99%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/ColumnConfig.java (99%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/ConnectionSource.java (96%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/DataSourceConnectionSource.java (98%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/DriverManagerConnectionSource.java (98%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/FactoryMethodConnectionSource.java (99%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/JdbcAppender.java (99%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/JdbcDatabaseManager.java (99%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender}/package-info.java (94%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins => log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc}/convert/DateTypeConverter.java (97%) create mode 100644 log4j-jdbc/src/site/manual/index.md create mode 100644 log4j-jdbc/src/site/site.xml rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/AbstractJdbcAppenderDataSourceTest.java (96%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/AbstractJdbcAppenderFactoryMethodTest.java (96%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/ColumnConfigTest.java (98%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/DataSourceConnectionSourceTest.java (96%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/DriverManagerConnectionSourceTest.java (94%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/FactoryMethodConnectionSourceTest.java (97%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/JdbcAppenderH2DataSourceTest.java (92%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/JdbcAppenderH2FactoryMethodTest.java (93%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/JdbcAppenderHsqldbDataSourceTest.java (93%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/JdbcAppenderHsqldbFactoryMethodTest.java (94%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/JdbcAppenderMapMessageDataSourceTest.java (96%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/JdbcH2TestHelper.java (89%) rename {log4j-core/src/test/java/org/apache/logging/log4j/junit => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender}/JdbcRule.java (95%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins => log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc}/convert/DateTypeConverterTest.java (94%) rename {log4j-core => log4j-jdbc}/src/test/resources/log4j-fatalOnly.xml (100%) rename {log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender}/log4j2-data-source-map-message.xml (93%) rename {log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender}/log4j2-data-source.xml (94%) rename {log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender}/log4j2-h2-factory-method.xml (89%) rename {log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc => log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender}/log4j2-hsqldb-factory-method.xml (89%) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index ed4a5912224..9914baf7441 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -17,6 +17,14 @@ The new modules are: * Old package: `org.apache.logging.log4j.core.layout` * New package: `org.apache.logging.log4j.csv.layout` +### log4j-jdbc + +* Group ID: `org.apache.logging.log4j` +* Artifact ID: `log4j-jdbc` + +* Old package: `org.apache.logging.log4j.core.appender.db.jdbc` +* New package: `org.apache.logging.log4j.jdbc.appender` + ### log4j-jeromq * Group ID: `org.apache.logging.log4j` diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index e98e6811274..0f4bb816f10 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -54,7 +54,13 @@ log4j-jcl ${project.version} - + + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + + org.apache.logging.log4j log4j-jdbc-dbcp2 diff --git a/log4j-cassandra/pom.xml b/log4j-cassandra/pom.xml index e3c8cb3d8ea..869b5081c83 100644 --- a/log4j-cassandra/pom.xml +++ b/log4j-cassandra/pom.xml @@ -41,6 +41,12 @@ org.apache.logging.log4j log4j-core + + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + com.datastax.cassandra cassandra-driver-core diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java index 65ee60eecd7..8b54a0b5c88 100644 --- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java +++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java @@ -31,9 +31,9 @@ import org.apache.logging.log4j.core.appender.ManagerFactory; import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager; import org.apache.logging.log4j.core.appender.db.ColumnMapping; -import org.apache.logging.log4j.core.config.plugins.convert.DateTypeConverter; import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters; import org.apache.logging.log4j.core.net.SocketAddress; +import org.apache.logging.log4j.jdbc.convert.DateTypeConverter; import org.apache.logging.log4j.spi.ThreadContextMap; import org.apache.logging.log4j.spi.ThreadContextStack; import org.apache.logging.log4j.util.ReadOnlyStringMap; diff --git a/log4j-distribution/pom.xml b/log4j-distribution/pom.xml index 98217a1237d..275d3795315 100644 --- a/log4j-distribution/pom.xml +++ b/log4j-distribution/pom.xml @@ -124,6 +124,24 @@ ${project.version} javadoc + + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + sources + + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + javadoc + org.apache.logging.log4j diff --git a/log4j-jdbc-dbcp2/pom.xml b/log4j-jdbc-dbcp2/pom.xml index 3155019a842..900ac8ec40a 100644 --- a/log4j-jdbc-dbcp2/pom.xml +++ b/log4j-jdbc-dbcp2/pom.xml @@ -33,6 +33,11 @@ org.apache.logging.log4j log4j-core + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + org.apache.commons commons-dbcp2 @@ -53,6 +58,12 @@ log4j-core test-jar + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + test-jar + com.h2database h2 diff --git a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java index 6734e178034..93574345197 100644 --- a/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java +++ b/log4j-jdbc-dbcp2/src/main/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSource.java @@ -28,11 +28,11 @@ import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.logging.log4j.core.Core; -import org.apache.logging.log4j.core.appender.db.jdbc.AbstractDriverManagerConnectionSource; -import org.apache.logging.log4j.core.appender.db.jdbc.ConnectionSource; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.jdbc.appender.AbstractDriverManagerConnectionSource; +import org.apache.logging.log4j.jdbc.appender.ConnectionSource; /** * A {@link ConnectionSource} that uses a JDBC connection string, a user name, and a password to call diff --git a/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/db/jdbc/appender/PoolingDriverConnectionSourceTest.java b/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSourceTest.java similarity index 91% rename from log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/db/jdbc/appender/PoolingDriverConnectionSourceTest.java rename to log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSourceTest.java index 56740f628bc..d415d436622 100644 --- a/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/db/jdbc/appender/PoolingDriverConnectionSourceTest.java +++ b/log4j-jdbc-dbcp2/src/test/java/org/apache/logging/log4j/dbcp2/appender/PoolingDriverConnectionSourceTest.java @@ -15,14 +15,13 @@ * limitations under the license. */ -package org.apache.logging.log4j.db.jdbc.appender; +package org.apache.logging.log4j.dbcp2.appender; import java.sql.Connection; import java.sql.SQLException; -import org.apache.logging.log4j.core.appender.db.jdbc.JdbcH2TestHelper; import org.apache.logging.log4j.core.config.Property; -import org.apache.logging.log4j.dbcp2.appender.PoolingDriverConnectionSource; +import org.apache.logging.log4j.jdbc.appender.JdbcH2TestHelper; import org.junit.Assert; import org.junit.Test; @@ -37,7 +36,7 @@ public void testH2Properties() throws SQLException { // @formatter:on }; // @formatter:off - final PoolingDriverConnectionSource source = (PoolingDriverConnectionSource) PoolingDriverConnectionSource.newPoolingDriverConnectionSourceBuilder() + final PoolingDriverConnectionSource source = PoolingDriverConnectionSource.newPoolingDriverConnectionSourceBuilder() .setConnectionString(JdbcH2TestHelper.CONNECTION_STRING) .setProperties(properties) .build(); diff --git a/log4j-jdbc/pom.xml b/log4j-jdbc/pom.xml new file mode 100644 index 00000000000..9cc622ebcd8 --- /dev/null +++ b/log4j-jdbc/pom.xml @@ -0,0 +1,210 @@ + + + + + + org.apache.logging.log4j + log4j + 2.10.1-SNAPSHOT + + 4.0.0 + + log4j-jdbc + Apache Log4j JDBC + + Apache Log4j Java Database Connectivity (JDBC). + + + ${basedir}/.. + Log4j JDBC Documentation + /log4j-jdbc + org.apache.logging.log4j.jdbc + + + + + org.apache.logging.log4j + log4j-core + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + + org.mockito + mockito-core + test + + + + org.springframework + spring-test + test + + + org.hsqldb + hsqldb + test + + + com.h2database + h2 + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + default + + test-jar + + + + ${manifestfile} + + ${project.name} + ${project.version} + ${project.organization.name} + ${project.name} + ${project.version} + ${project.organization.name} + org.apache + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.jdbc + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]> + + false + true + + + + non-aggregate + + javadoc + + + + + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + + + + diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/AbstractConnectionSource.java similarity index 94% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractConnectionSource.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/AbstractConnectionSource.java index bd04eac95cc..0ddeba0fec6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractConnectionSource.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/AbstractConnectionSource.java @@ -15,7 +15,7 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import org.apache.logging.log4j.core.AbstractLifeCycle; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractDriverManagerConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/AbstractDriverManagerConnectionSource.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractDriverManagerConnectionSource.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/AbstractDriverManagerConnectionSource.java index 4f25442c3c2..0248fce4ff2 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractDriverManagerConnectionSource.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/AbstractDriverManagerConnectionSource.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.DriverManager; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ColumnConfig.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ColumnConfig.java index 1377b2a49f3..6d1e2ca9dc9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfig.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ColumnConfig.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.Core; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ConnectionSource.java similarity index 96% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ConnectionSource.java index 2a25b251826..6c058967e5b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ConnectionSource.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/ConnectionSource.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.SQLException; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSource.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSource.java index a791df98978..eaf5750b0f9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSource.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSource.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.SQLException; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSource.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSource.java index e390c5e85e7..93760d131f3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSource.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSource.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.DriverManager; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/FactoryMethodConnectionSource.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/FactoryMethodConnectionSource.java index 20bf2f39540..a082e6192d7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSource.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/FactoryMethodConnectionSource.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.io.PrintWriter; import java.lang.reflect.Method; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java index 974d87ed16c..d68556c6008 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppender.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcAppender.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.io.Serializable; import java.sql.PreparedStatement; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java similarity index 99% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java index 2952288d347..2afcaf7ee16 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcDatabaseManager.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/JdbcDatabaseManager.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.io.Serializable; import java.io.StringReader; @@ -38,9 +38,9 @@ import org.apache.logging.log4j.core.appender.ManagerFactory; import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager; import org.apache.logging.log4j.core.appender.db.ColumnMapping; -import org.apache.logging.log4j.core.config.plugins.convert.DateTypeConverter; import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters; import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.jdbc.convert.DateTypeConverter; import org.apache.logging.log4j.message.MapMessage; import org.apache.logging.log4j.spi.ThreadContextMap; import org.apache.logging.log4j.spi.ThreadContextStack; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/package-info.java similarity index 94% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/package-info.java index 1dbd663c4e3..ab1e6a67a7f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/package-info.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/appender/package-info.java @@ -18,4 +18,4 @@ * The JDBC Appender supports writing log events to a relational database using standard JDBC connections. You will need * a JDBC driver on your classpath for the database you wish to log to. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/DateTypeConverter.java b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/convert/DateTypeConverter.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/DateTypeConverter.java rename to log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/convert/DateTypeConverter.java index 6fbc7aac8cf..ffb6cf22942 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/DateTypeConverter.java +++ b/log4j-jdbc/src/main/java/org/apache/logging/log4j/jdbc/convert/DateTypeConverter.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.config.plugins.convert; +package org.apache.logging.log4j.jdbc.convert; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; diff --git a/log4j-jdbc/src/site/manual/index.md b/log4j-jdbc/src/site/manual/index.md new file mode 100644 index 00000000000..66fe24fe304 --- /dev/null +++ b/log4j-jdbc/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j ZeroMQ using JeroMQ module + +As of Log4j 2.11.0, ZeroMQ using JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires the jeromq JAR. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-jdbc/src/site/site.xml b/log4j-jdbc/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-jdbc/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderDataSourceTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/AbstractJdbcAppenderDataSourceTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderDataSourceTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/AbstractJdbcAppenderDataSourceTest.java index 732c2f7c717..4773a3d2370 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderDataSourceTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/AbstractJdbcAppenderDataSourceTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; @@ -27,7 +27,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.util.Throwables; -import org.apache.logging.log4j.junit.JdbcRule; import org.apache.logging.log4j.junit.JndiRule; import org.apache.logging.log4j.junit.LoggerContextRule; import org.h2.util.IOUtils; @@ -55,7 +54,7 @@ protected AbstractJdbcAppenderDataSourceTest(final JdbcRule jdbcRule) { .around(new JndiRule("java:/comp/env/jdbc/TestDataSourceAppender", createMockDataSource())) .around(jdbcRule) .around(new LoggerContextRule( - "org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source.xml")); + "org/apache/logging/log4j/jdbc/appender/log4j2-data-source.xml")); this.jdbcRule = jdbcRule; } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderFactoryMethodTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/AbstractJdbcAppenderFactoryMethodTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderFactoryMethodTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/AbstractJdbcAppenderFactoryMethodTest.java index 72f7f3935a6..39be14fba94 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/AbstractJdbcAppenderFactoryMethodTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/AbstractJdbcAppenderFactoryMethodTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; @@ -26,7 +26,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.ThreadContext; -import org.apache.logging.log4j.junit.JdbcRule; +import org.apache.logging.log4j.jdbc.appender.FactoryMethodConnectionSource; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.util.Strings; import org.h2.util.IOUtils; @@ -49,7 +49,7 @@ public abstract class AbstractJdbcAppenderFactoryMethodTest { protected AbstractJdbcAppenderFactoryMethodTest(final JdbcRule jdbcRule, final String databaseType) { this.rules = RuleChain.emptyRuleChain().around(jdbcRule).around(new LoggerContextRule( - "org/apache/logging/log4j/core/appender/db/jdbc/log4j2-" + databaseType + "-factory-method.xml")); + "org/apache/logging/log4j/jdbc/appender/log4j2-" + databaseType + "-factory-method.xml")); this.jdbcRule = jdbcRule; } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfigTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/ColumnConfigTest.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfigTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/ColumnConfigTest.java index 9d36cb762c9..62c01fb8e56 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/ColumnConfigTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/ColumnConfigTest.java @@ -14,8 +14,9 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; +import org.apache.logging.log4j.jdbc.appender.ColumnConfig; import org.apache.logging.log4j.util.Strings; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSourceTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSourceTest.java index a49404a83fc..94fc8086c22 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DataSourceConnectionSourceTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/DataSourceConnectionSourceTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -28,6 +28,7 @@ import javax.sql.DataSource; +import org.apache.logging.log4j.jdbc.appender.DataSourceConnectionSource; import org.apache.logging.log4j.junit.JndiRule; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.Rule; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSourceTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSourceTest.java similarity index 94% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSourceTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSourceTest.java index 5a4835a3ea5..e1e94ed96a1 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/DriverManagerConnectionSourceTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/DriverManagerConnectionSourceTest.java @@ -15,12 +15,13 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.SQLException; import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.jdbc.appender.DriverManagerConnectionSource; import org.junit.Assert; import org.junit.Test; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSourceTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/FactoryMethodConnectionSourceTest.java similarity index 97% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSourceTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/FactoryMethodConnectionSourceTest.java index 28b6d876058..8371d35caab 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/FactoryMethodConnectionSourceTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/FactoryMethodConnectionSourceTest.java @@ -14,12 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; +import org.apache.logging.log4j.jdbc.appender.FactoryMethodConnectionSource; import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.After; import org.junit.ClassRule; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2DataSourceTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderH2DataSourceTest.java similarity index 92% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2DataSourceTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderH2DataSourceTest.java index acd14cabeb9..bb1c2433885 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2DataSourceTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderH2DataSourceTest.java @@ -14,9 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; - -import org.apache.logging.log4j.junit.JdbcRule; +package org.apache.logging.log4j.jdbc.appender; /** * diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2FactoryMethodTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderH2FactoryMethodTest.java similarity index 93% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2FactoryMethodTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderH2FactoryMethodTest.java index c79b6ba3785..ff88fe1bd14 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderH2FactoryMethodTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderH2FactoryMethodTest.java @@ -14,13 +14,11 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.SQLException; -import org.apache.logging.log4j.junit.JdbcRule; - /** * */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbDataSourceTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderHsqldbDataSourceTest.java similarity index 93% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbDataSourceTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderHsqldbDataSourceTest.java index 79560ffcae5..32135eb8361 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbDataSourceTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderHsqldbDataSourceTest.java @@ -14,13 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import org.apache.logging.log4j.junit.JdbcRule; +import org.apache.logging.log4j.jdbc.appender.AbstractConnectionSource; /** * diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbFactoryMethodTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderHsqldbFactoryMethodTest.java similarity index 94% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbFactoryMethodTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderHsqldbFactoryMethodTest.java index 0d76ac1e36f..355fbeadb9b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderHsqldbFactoryMethodTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderHsqldbFactoryMethodTest.java @@ -14,13 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import org.apache.logging.log4j.junit.JdbcRule; +import org.apache.logging.log4j.jdbc.appender.AbstractConnectionSource; /** * diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderMapMessageDataSourceTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderMapMessageDataSourceTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderMapMessageDataSourceTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderMapMessageDataSourceTest.java index c186537512c..a60c3c0ca67 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcAppenderMapMessageDataSourceTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcAppenderMapMessageDataSourceTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -33,7 +33,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.util.Throwables; -import org.apache.logging.log4j.junit.JdbcRule; import org.apache.logging.log4j.junit.JndiRule; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.message.MapMessage; @@ -66,7 +65,7 @@ protected JdbcAppenderMapMessageDataSourceTest(final JdbcRule jdbcRule) { this.rules = RuleChain.emptyRuleChain() .around(new JndiRule("java:/comp/env/jdbc/TestDataSourceAppender", createMockDataSource())) .around(jdbcRule) - .around(new LoggerContextRule("org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source-map-message.xml")); + .around(new LoggerContextRule("org/apache/logging/log4j/jdbc/appender/log4j2-data-source-map-message.xml")); // @formatter:on this.jdbcRule = jdbcRule; } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcH2TestHelper.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcH2TestHelper.java similarity index 89% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcH2TestHelper.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcH2TestHelper.java index 7152f1141fc..9eb271390c0 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jdbc/JdbcH2TestHelper.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcH2TestHelper.java @@ -14,12 +14,15 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.appender.db.jdbc; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import org.apache.logging.log4j.jdbc.appender.AbstractConnectionSource; +import org.apache.logging.log4j.jdbc.appender.ConnectionSource; + public class JdbcH2TestHelper { public static final String CONNECTION_STRING = "jdbc:h2:mem:Log4j"; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/junit/JdbcRule.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcRule.java similarity index 95% rename from log4j-core/src/test/java/org/apache/logging/log4j/junit/JdbcRule.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcRule.java index 9354a5e696a..bd062818503 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/junit/JdbcRule.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/appender/JdbcRule.java @@ -14,12 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.junit; +package org.apache.logging.log4j.jdbc.appender; import java.sql.Connection; import java.sql.Statement; -import org.apache.logging.log4j.core.appender.db.jdbc.ConnectionSource; +import org.apache.logging.log4j.jdbc.appender.ConnectionSource; +import org.apache.logging.log4j.junit.LoggerContextRule; import org.junit.rules.TestRule; import org.junit.runner.Description; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/DateTypeConverterTest.java b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/convert/DateTypeConverterTest.java similarity index 94% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/DateTypeConverterTest.java rename to log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/convert/DateTypeConverterTest.java index 1c83d8d5dc3..494b3dcb943 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/DateTypeConverterTest.java +++ b/log4j-jdbc/src/test/java/org/apache/logging/log4j/jdbc/convert/DateTypeConverterTest.java @@ -14,12 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.config.plugins.convert; +package org.apache.logging.log4j.jdbc.convert; import java.sql.Time; import java.sql.Timestamp; import java.util.Date; +import org.apache.logging.log4j.jdbc.convert.DateTypeConverter; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; diff --git a/log4j-core/src/test/resources/log4j-fatalOnly.xml b/log4j-jdbc/src/test/resources/log4j-fatalOnly.xml similarity index 100% rename from log4j-core/src/test/resources/log4j-fatalOnly.xml rename to log4j-jdbc/src/test/resources/log4j-fatalOnly.xml diff --git a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source-map-message.xml b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-data-source-map-message.xml similarity index 93% rename from log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source-map-message.xml rename to log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-data-source-map-message.xml index a50bbf6c58a..7fc2114fe22 100644 --- a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source-map-message.xml +++ b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-data-source-map-message.xml @@ -31,7 +31,7 @@ - + diff --git a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source.xml b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-data-source.xml similarity index 94% rename from log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source.xml rename to log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-data-source.xml index 4e6ca91a69b..3f9766db30c 100644 --- a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-data-source.xml +++ b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-data-source.xml @@ -33,7 +33,7 @@ - + diff --git a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-h2-factory-method.xml b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-h2-factory-method.xml similarity index 89% rename from log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-h2-factory-method.xml rename to log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-h2-factory-method.xml index b7ef94006b8..b89c1395f2d 100644 --- a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-h2-factory-method.xml +++ b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-h2-factory-method.xml @@ -22,7 +22,7 @@ - @@ -35,7 +35,7 @@ - + diff --git a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-hsqldb-factory-method.xml b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-hsqldb-factory-method.xml similarity index 89% rename from log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-hsqldb-factory-method.xml rename to log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-hsqldb-factory-method.xml index be92697e4ef..293ed80c98b 100644 --- a/log4j-core/src/test/resources/org/apache/logging/log4j/core/appender/db/jdbc/log4j2-hsqldb-factory-method.xml +++ b/log4j-jdbc/src/test/resources/org/apache/logging/log4j/jdbc/appender/log4j2-hsqldb-factory-method.xml @@ -22,7 +22,7 @@ - @@ -35,7 +35,7 @@ - + diff --git a/log4j-perf/pom.xml b/log4j-perf/pom.xml index b352bd3f2eb..0f48624edef 100644 --- a/log4j-perf/pom.xml +++ b/log4j-perf/pom.xml @@ -63,10 +63,15 @@ org.apache.logging.log4j log4j-core + + org.apache.logging.log4j + log4j-jdbc + ${project.version} + org.apache.logging.log4j log4j-jpa - 2.10.1-SNAPSHOT + ${project.version} org.slf4j diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JdbcAppenderBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JdbcAppenderBenchmark.java index 62e6218a74d..14ae458db12 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JdbcAppenderBenchmark.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/JdbcAppenderBenchmark.java @@ -26,10 +26,10 @@ 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.appender.db.jdbc.JdbcAppender; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.util.Closer; +import org.apache.logging.log4j.jdbc.appender.JdbcAppender; import org.apache.logging.log4j.status.StatusLogger; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; diff --git a/pom.xml b/pom.xml index 1ae7f777104..691d456860c 100644 --- a/pom.xml +++ b/pom.xml @@ -1335,6 +1335,7 @@ log4j-jmx-gui log4j-samples log4j-bom + log4j-jdbc log4j-jdbc-dbcp2 log4j-jpa log4j-jeromq diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 95801c021ce..5f577613612 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -185,6 +185,9 @@ Move JMS code to a new module log4j-jms. + + Move JDBC code to a new module log4j-jdbc. + diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml index de83a704017..caabe2dc6e7 100644 --- a/src/site/xdoc/manual/appenders.xml +++ b/src/site/xdoc/manual/appenders.xml @@ -982,6 +982,9 @@ CREATE TABLE logs ( +

+ As of Log4j 2.11.0, JDBC support has moved from the existing module logj-core to the new module log4j-jdbc. +

The JDBCAppender writes log events to a relational database table using standard JDBC. It can be configured to obtain JDBC connections using a JNDI DataSource or a custom factory method. Whichever approach you take, it must be backed by a connection pool. Otherwise, logging From ded845696bcd0b96f3eb4b647feeecc149f0f72c Mon Sep 17 00:00:00 2001 From: rpopma Date: Tue, 30 Jan 2018 23:08:29 +0900 Subject: [PATCH 0029/2347] LOG4J2-2236 Removed unnecessary dependency on jcommander since Log4j uses embedded picocli since 2.9. (cherry picked from commit 4da4243f50ba2af3ad69f69f56c37ff7d6eac250) # Conflicts: # log4j-core/pom.xml # src/changes/changes.xml --- log4j-core/pom.xml | 6 ------ pom.xml | 5 ----- src/changes/changes.xml | 18 +++--------------- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index dab3328dfc2..dc1694edf84 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -113,12 +113,6 @@ commons-compress true - - - com.beust - jcommander - true - diff --git a/pom.xml b/pom.xml index 1ae7f777104..ea37eed9bb4 100644 --- a/pom.xml +++ b/pom.xml @@ -296,11 +296,6 @@ commons-lang3 3.7 - - com.beust - jcommander - 1.48 - ch.qos.logback logback-classic diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 95801c021ce..c683d69334a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -37,6 +37,9 @@ Moved time-related classes from core.util to core.time. Classes considered private moved to core.time.internal. + + Removed unnecessary dependency on jcommander since Log4j uses embedded picocli since 2.9. + Added support for precise (micro and nanosecond) timestamps when running on Java 9. A limited number of precise %d date formats are supported with PatternLayout. POTENTIAL BREAKING CHANGE: The XML, JSON and YAML formats have changed: they no longer have the "timeMillis" attribute and instead have an "Instant" element with "epochSecond" and "nanoOfSecond" attributes. @@ -170,21 +173,6 @@ Update Jackson from 2.9.3 to 2.9.4. - - Split off ZeroMq/JeroMq support into a new module log4j-jeromq. - - - Split off Kafka support into a new module log4j-kafka. - - - Split off SMTP support into a new module log4j-smtp. - - - Move CSV layout from log4j-core to a new module log4j-csv. - - - Move JMS code to a new module log4j-jms. - From 041fe8ffeb910f56194323a3b9808e3d27bab335 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 30 Jan 2018 09:05:17 -0700 Subject: [PATCH 0030/2347] Update POM version to 3.0.0-SNAPSHOT since we now have a 2.x-release branch. --- log4j-1.2-api/pom.xml | 2 +- log4j-api-java9/pom.xml | 2 +- log4j-api/pom.xml | 2 +- log4j-appserver/pom.xml | 2 +- log4j-bom/pom.xml | 2 +- log4j-cassandra/pom.xml | 2 +- log4j-core-its/pom.xml | 2 +- log4j-core-java9/pom.xml | 2 +- log4j-core/pom.xml | 2 +- log4j-couchdb/pom.xml | 2 +- log4j-csv/pom.xml | 2 +- log4j-distribution/pom.xml | 2 +- log4j-flume-ng/pom.xml | 2 +- log4j-iostreams/pom.xml | 2 +- log4j-jcl/pom.xml | 2 +- log4j-jdbc-dbcp2/pom.xml | 2 +- log4j-jdbc/pom.xml | 2 +- log4j-jeromq/pom.xml | 2 +- log4j-jms/pom.xml | 2 +- log4j-jmx-gui/pom.xml | 2 +- log4j-jpa/pom.xml | 2 +- log4j-jul/pom.xml | 2 +- log4j-kafka/pom.xml | 2 +- log4j-liquibase/pom.xml | 2 +- log4j-mongodb2/pom.xml | 2 +- log4j-mongodb3/pom.xml | 2 +- log4j-osgi/pom.xml | 2 +- log4j-perf/pom.xml | 2 +- log4j-samples/log4j-samples-configuration/pom.xml | 2 +- log4j-samples/log4j-samples-flume-common/pom.xml | 2 +- log4j-samples/log4j-samples-flume-embedded/pom.xml | 2 +- log4j-samples/log4j-samples-flume-remote/pom.xml | 2 +- log4j-samples/log4j-samples-loggerProperties/pom.xml | 2 +- log4j-samples/pom.xml | 2 +- log4j-slf4j-impl/pom.xml | 2 +- log4j-smtp/pom.xml | 2 +- log4j-taglib/pom.xml | 2 +- log4j-to-slf4j/pom.xml | 2 +- log4j-web/pom.xml | 2 +- pom.xml | 2 +- 40 files changed, 40 insertions(+), 40 deletions(-) diff --git a/log4j-1.2-api/pom.xml b/log4j-1.2-api/pom.xml index 3ddf8055ac7..95c6c9b3c59 100644 --- a/log4j-1.2-api/pom.xml +++ b/log4j-1.2-api/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-1.2-api diff --git a/log4j-api-java9/pom.xml b/log4j-api-java9/pom.xml index 183ad14dd3c..793c4b92df1 100644 --- a/log4j-api-java9/pom.xml +++ b/log4j-api-java9/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-api-java9 diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml index 2ddbde86382..5ee38a4c2bd 100644 --- a/log4j-api/pom.xml +++ b/log4j-api/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-api diff --git a/log4j-appserver/pom.xml b/log4j-appserver/pom.xml index bd1351fd941..79fbad84a2d 100644 --- a/log4j-appserver/pom.xml +++ b/log4j-appserver/pom.xml @@ -20,7 +20,7 @@ log4j org.apache.logging.log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index 0f4bb816f10..97021b2cf80 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -26,7 +26,7 @@ Apache Log4j Bill of Materials org.apache.logging.log4j log4j-bom - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT pom diff --git a/log4j-cassandra/pom.xml b/log4j-cassandra/pom.xml index 869b5081c83..be370788737 100644 --- a/log4j-cassandra/pom.xml +++ b/log4j-cassandra/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-core-its/pom.xml b/log4j-core-its/pom.xml index 9df2f43fca6..2a0cec1a2a8 100644 --- a/log4j-core-its/pom.xml +++ b/log4j-core-its/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-core-its diff --git a/log4j-core-java9/pom.xml b/log4j-core-java9/pom.xml index 2da8629595c..b818c7fc7c1 100644 --- a/log4j-core-java9/pom.xml +++ b/log4j-core-java9/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-core-java9 diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index dc1694edf84..76ac37ef38a 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-core diff --git a/log4j-couchdb/pom.xml b/log4j-couchdb/pom.xml index 6acded48280..4e7e75a55fa 100644 --- a/log4j-couchdb/pom.xml +++ b/log4j-couchdb/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-csv/pom.xml b/log4j-csv/pom.xml index 3876d51e7b6..3cec7bfa68c 100644 --- a/log4j-csv/pom.xml +++ b/log4j-csv/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-distribution/pom.xml b/log4j-distribution/pom.xml index 275d3795315..30ee9b32d4b 100644 --- a/log4j-distribution/pom.xml +++ b/log4j-distribution/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-distribution diff --git a/log4j-flume-ng/pom.xml b/log4j-flume-ng/pom.xml index 7a654e4a26a..cdd2ca1ce30 100644 --- a/log4j-flume-ng/pom.xml +++ b/log4j-flume-ng/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-flume-ng diff --git a/log4j-iostreams/pom.xml b/log4j-iostreams/pom.xml index e3a21e2d2f1..68efa5848a1 100644 --- a/log4j-iostreams/pom.xml +++ b/log4j-iostreams/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-iostreams diff --git a/log4j-jcl/pom.xml b/log4j-jcl/pom.xml index 0eb099e7e20..5113378123d 100644 --- a/log4j-jcl/pom.xml +++ b/log4j-jcl/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-jcl diff --git a/log4j-jdbc-dbcp2/pom.xml b/log4j-jdbc-dbcp2/pom.xml index 900ac8ec40a..a9a77ff3b2e 100644 --- a/log4j-jdbc-dbcp2/pom.xml +++ b/log4j-jdbc-dbcp2/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-jdbc/pom.xml b/log4j-jdbc/pom.xml index 9cc622ebcd8..195b7c28690 100644 --- a/log4j-jdbc/pom.xml +++ b/log4j-jdbc/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-jeromq/pom.xml b/log4j-jeromq/pom.xml index 77f47758bfd..2f03dc6a09b 100644 --- a/log4j-jeromq/pom.xml +++ b/log4j-jeromq/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-jms/pom.xml b/log4j-jms/pom.xml index db1b029f6bd..4d9d9929b31 100644 --- a/log4j-jms/pom.xml +++ b/log4j-jms/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-jmx-gui/pom.xml b/log4j-jmx-gui/pom.xml index 7f283e80b73..ad6c84be334 100644 --- a/log4j-jmx-gui/pom.xml +++ b/log4j-jmx-gui/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-jmx-gui diff --git a/log4j-jpa/pom.xml b/log4j-jpa/pom.xml index 3d8ee71863a..9baa151647f 100644 --- a/log4j-jpa/pom.xml +++ b/log4j-jpa/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-jul/pom.xml b/log4j-jul/pom.xml index 3d81b4611eb..a1d9ccbd693 100644 --- a/log4j-jul/pom.xml +++ b/log4j-jul/pom.xml @@ -20,7 +20,7 @@ log4j org.apache.logging.log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ 4.0.0 diff --git a/log4j-kafka/pom.xml b/log4j-kafka/pom.xml index 73df1a5f22f..9f6d44960e0 100644 --- a/log4j-kafka/pom.xml +++ b/log4j-kafka/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-liquibase/pom.xml b/log4j-liquibase/pom.xml index b65d1a94208..34fb47d21c4 100644 --- a/log4j-liquibase/pom.xml +++ b/log4j-liquibase/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-liquibase diff --git a/log4j-mongodb2/pom.xml b/log4j-mongodb2/pom.xml index 9c7979e2d47..9f22ba97eed 100644 --- a/log4j-mongodb2/pom.xml +++ b/log4j-mongodb2/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-mongodb3/pom.xml b/log4j-mongodb3/pom.xml index 4d4a6520d2b..2d6667db5a6 100644 --- a/log4j-mongodb3/pom.xml +++ b/log4j-mongodb3/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-osgi/pom.xml b/log4j-osgi/pom.xml index ea454fdc6ce..6200b86a9a1 100644 --- a/log4j-osgi/pom.xml +++ b/log4j-osgi/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-osgi diff --git a/log4j-perf/pom.xml b/log4j-perf/pom.xml index 0f48624edef..02e3162780d 100644 --- a/log4j-perf/pom.xml +++ b/log4j-perf/pom.xml @@ -20,7 +20,7 @@ log4j org.apache.logging.log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ diff --git a/log4j-samples/log4j-samples-configuration/pom.xml b/log4j-samples/log4j-samples-configuration/pom.xml index 0003f3713c9..dc65cb2708c 100644 --- a/log4j-samples/log4j-samples-configuration/pom.xml +++ b/log4j-samples/log4j-samples-configuration/pom.xml @@ -20,7 +20,7 @@ log4j-samples org.apache.logging.log4j.samples - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT log4j-samples-configuration jar diff --git a/log4j-samples/log4j-samples-flume-common/pom.xml b/log4j-samples/log4j-samples-flume-common/pom.xml index a5df8cac9f3..876b9ecb3c7 100644 --- a/log4j-samples/log4j-samples-flume-common/pom.xml +++ b/log4j-samples/log4j-samples-flume-common/pom.xml @@ -20,7 +20,7 @@ log4j-samples org.apache.logging.log4j.samples - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT log4j-samples-flume-common jar diff --git a/log4j-samples/log4j-samples-flume-embedded/pom.xml b/log4j-samples/log4j-samples-flume-embedded/pom.xml index e8892792cd7..00b95d0449b 100644 --- a/log4j-samples/log4j-samples-flume-embedded/pom.xml +++ b/log4j-samples/log4j-samples-flume-embedded/pom.xml @@ -20,7 +20,7 @@ log4j-samples org.apache.logging.log4j.samples - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT log4j-samples-flume-embedded war diff --git a/log4j-samples/log4j-samples-flume-remote/pom.xml b/log4j-samples/log4j-samples-flume-remote/pom.xml index 76e50a8afb2..c5e16f3bead 100644 --- a/log4j-samples/log4j-samples-flume-remote/pom.xml +++ b/log4j-samples/log4j-samples-flume-remote/pom.xml @@ -20,7 +20,7 @@ log4j-samples org.apache.logging.log4j.samples - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT log4j-samples-flume-remote war diff --git a/log4j-samples/log4j-samples-loggerProperties/pom.xml b/log4j-samples/log4j-samples-loggerProperties/pom.xml index 36c14440511..25ca5c8c59a 100644 --- a/log4j-samples/log4j-samples-loggerProperties/pom.xml +++ b/log4j-samples/log4j-samples-loggerProperties/pom.xml @@ -20,7 +20,7 @@ log4j-samples org.apache.logging.log4j.samples - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT log4j-samples-loggerProperties jar diff --git a/log4j-samples/pom.xml b/log4j-samples/pom.xml index 92e1284139a..d479b3cbd7e 100644 --- a/log4j-samples/pom.xml +++ b/log4j-samples/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ org.apache.logging.log4j.samples diff --git a/log4j-slf4j-impl/pom.xml b/log4j-slf4j-impl/pom.xml index db270ee1f36..2b5fcdd2d91 100644 --- a/log4j-slf4j-impl/pom.xml +++ b/log4j-slf4j-impl/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-slf4j-impl diff --git a/log4j-smtp/pom.xml b/log4j-smtp/pom.xml index 203db56de7a..99cb383bdea 100644 --- a/log4j-smtp/pom.xml +++ b/log4j-smtp/pom.xml @@ -12,7 +12,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/log4j-taglib/pom.xml b/log4j-taglib/pom.xml index 49361e2aaf6..8c321a1b271 100644 --- a/log4j-taglib/pom.xml +++ b/log4j-taglib/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-taglib diff --git a/log4j-to-slf4j/pom.xml b/log4j-to-slf4j/pom.xml index c7231003ee8..e544bbde6cc 100644 --- a/log4j-to-slf4j/pom.xml +++ b/log4j-to-slf4j/pom.xml @@ -20,7 +20,7 @@ org.apache.logging.log4j log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT ../ log4j-to-slf4j diff --git a/log4j-web/pom.xml b/log4j-web/pom.xml index fb4fe1a771c..1d4300c8594 100644 --- a/log4j-web/pom.xml +++ b/log4j-web/pom.xml @@ -20,7 +20,7 @@ log4j org.apache.logging.log4j - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 86d2786f041..ed00dd87018 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ log4j pom Apache Log4j 2 - 2.10.1-SNAPSHOT + 3.0.0-SNAPSHOT org.apache.logging logging-parent From a9e8f525a20d92d85caf6c4e4de22d45b0a98c2c Mon Sep 17 00:00:00 2001 From: rpopma Date: Thu, 1 Feb 2018 21:08:50 +0900 Subject: [PATCH 0031/2347] Update changes.xml: moved JIRA tickets that are not included in the 2.11 release to the 3.0 section --- src/changes/changes.xml | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 2f21b0f8dbe..469493ae421 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -30,13 +30,33 @@ - "update" - Change - "remove" - Removed --> - + Renamed package core.util.datetime to core.time.internal.format to clarify these classes are to be considered private. Moved time-related classes from core.util to core.time. Classes considered private moved to core.time.internal. + + Split off ZeroMq/JeroMq support into a new module log4j-jeromq. + + + Split off Kafka support into a new module log4j-kafka. + + + Split off SMTP support into a new module log4j-smtp. + + + Move CSV layout from log4j-core to a new module log4j-csv. + + + Move JMS code to a new module log4j-jms. + + + Move JDBC code to a new module log4j-jdbc. + + + Removed unnecessary dependency on jcommander since Log4j uses embedded picocli since 2.9. @@ -173,24 +193,6 @@ Update Jackson from 2.9.3 to 2.9.4. - - Split off ZeroMq/JeroMq support into a new module log4j-jeromq. - - - Split off Kafka support into a new module log4j-kafka. - - - Split off SMTP support into a new module log4j-smtp. - - - Move CSV layout from log4j-core to a new module log4j-csv. - - - Move JMS code to a new module log4j-jms. - - - Move JDBC code to a new module log4j-jdbc. - From f8479bc534f68a3a7cd1e1a9babc5d33a66aa805 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 10:12:08 -0700 Subject: [PATCH 0032/2347] Better test class name. --- .../log4j/osgi/tests/junit/{OsgiRule.java => OsgiTestRule.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/{OsgiRule.java => OsgiTestRule.java} (100%) diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiRule.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java similarity index 100% rename from log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiRule.java rename to log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java From 3d07263d8a1a70c6a64bcb08a5396edb92eafa7b Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 10:14:59 -0700 Subject: [PATCH 0033/2347] Better test class name. --- .../apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java index 68321579ee9..4e683682162 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/OsgiTestRule.java @@ -28,12 +28,12 @@ /** * JUnit rule to initialize and shutdown an OSGi framework. */ -public class OsgiRule extends ExternalResource { +public class OsgiTestRule extends ExternalResource { private final FrameworkFactory factory; private Framework framework; - public OsgiRule(final FrameworkFactory factory) { + public OsgiTestRule(final FrameworkFactory factory) { this.factory = factory; } From 5f248ef7a498aa5c8cfe3ae9e0bf7ab644890435 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 10:16:26 -0700 Subject: [PATCH 0034/2347] Better test class name. --- .../logging/log4j/osgi/tests/AbstractLoadBundleTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index dde3f7de9e5..988263194ea 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -24,7 +24,7 @@ import java.nio.file.Paths; import org.apache.logging.log4j.osgi.tests.junit.BundleTestInfo; -import org.apache.logging.log4j.osgi.tests.junit.OsgiRule; +import org.apache.logging.log4j.osgi.tests.junit.OsgiTestRule; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -46,7 +46,7 @@ public abstract class AbstractLoadBundleTest { private Path here; @Rule - public OsgiRule osgi = new OsgiRule(getFactory()); + public OsgiTestRule osgi = new OsgiTestRule(getFactory()); /** * Constructs a test for a given bundle. */ From ad2ee803e0348036349ea776514cf243a7b76fee Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 10:30:35 -0700 Subject: [PATCH 0035/2347] Remove exceptions that are not thrown from method signatures. --- .../logging/log4j/osgi/tests/AbstractLoadBundleTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index 988263194ea..6edf48a31e6 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -59,7 +59,7 @@ public AbstractLoadBundleTest() { * Called before each @Test. */ @Before - public void before() throws BundleException { + public void before() { bundleContext = osgi.getFramework().getBundleContext(); here = Paths.get(".").toAbsolutePath().normalize(); @@ -150,7 +150,7 @@ private void uninstall(final Bundle api, final Bundle core, final Bundle dummy) * Tests starting, then stopping, then restarting, then stopping, and finally uninstalling the API and Core bundles */ @Test - public void testApiCoreStartStopStartStop() throws BundleException, ReflectiveOperationException { + public void testApiCoreStartStopStartStop() throws BundleException { final Bundle api = getApiBundle(); final Bundle core = getCoreBundle(); From ae6d9c15b0e8e9a754e5396a4ee968f7465efc3e Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 10:41:05 -0700 Subject: [PATCH 0036/2347] Minor refactoring in test framework. --- .../logging/log4j/osgi/tests/AbstractLoadBundleTest.java | 8 ++++---- .../logging/log4j/osgi/tests/junit/BundleTestInfo.java | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index 6edf48a31e6..80f4dc7be66 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -66,23 +66,23 @@ public void before() { } private Bundle getApiBundle() throws BundleException { - final Path apiPath = here.resolveSibling("log4j-api").resolve("target").resolve("log4j-api-" + bundleTestInfo.getVersion() + ".jar"); + final Path apiPath = here.resolveSibling("log4j-api").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-api")); return bundleContext.installBundle(apiPath.toUri().toString()); } private Bundle getCoreBundle() throws BundleException { - final Path corePath = here.resolveSibling("log4j-core").resolve("target").resolve("log4j-core-" + bundleTestInfo.getVersion() + ".jar"); + final Path corePath = here.resolveSibling("log4j-core").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-core")); return bundleContext.installBundle(corePath.toUri().toString()); } private Bundle getDummyBundle() throws BundleException { - final Path dumyPath = here.resolveSibling("log4j-samples").resolve("log4j-samples-configuration").resolve("target").resolve("log4j-samples-configuration-" + bundleTestInfo.getVersion() + ".jar"); + final Path dumyPath = here.resolveSibling("log4j-samples").resolve("log4j-samples-configuration").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-samples-configuration")); return bundleContext.installBundle(dumyPath.toUri().toString()); } private Bundle get12ApiBundle() throws BundleException { - final Path apiPath = here.resolveSibling("log4j-1.2-api").resolve("target").resolve("log4j-1.2-api-" + bundleTestInfo.getVersion() + ".jar"); + final Path apiPath = here.resolveSibling("log4j-1.2-api").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-1.2-api")); return bundleContext.installBundle(apiPath.toUri().toString()); } diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/BundleTestInfo.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/BundleTestInfo.java index 9a4f8a81737..02596168d81 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/BundleTestInfo.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/junit/BundleTestInfo.java @@ -45,6 +45,10 @@ public BundleTestInfo() { } } + public String buildJarFileName(final String artifactId) { + return artifactId + "-" + getVersion() + ".jar"; + } + /** * Gets the Maven artifact ID. * @@ -67,5 +71,4 @@ public String getVersion() { public String toString() { return "BundleTestInfo [project=" + project + "]"; } - } From 9774e05ec9d3cd2394e5736fb8902b90c54e4165 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 11:51:20 -0700 Subject: [PATCH 0037/2347] Refactoring in test framework before porting to Apache Commons Testing. --- .../osgi/tests/AbstractLoadBundleTest.java | 52 +++---------- .../log4j/osgi/tests/AbstractOsgiTest.java | 74 +++++++++++++++++++ 2 files changed, 84 insertions(+), 42 deletions(-) create mode 100644 log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index 80f4dc7be66..8b0a6656c29 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -21,69 +21,37 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.file.Path; -import java.nio.file.Paths; -import org.apache.logging.log4j.osgi.tests.junit.BundleTestInfo; -import org.apache.logging.log4j.osgi.tests.junit.OsgiTestRule; import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.launch.FrameworkFactory; /** * Tests a basic Log4J 'setup' in an OSGi container. */ -public abstract class AbstractLoadBundleTest { - - private BundleContext bundleContext; - - private final BundleTestInfo bundleTestInfo; - - private Path here; - - @Rule - public OsgiTestRule osgi = new OsgiTestRule(getFactory()); - /** - * Constructs a test for a given bundle. - */ - public AbstractLoadBundleTest() { - super(); - this.bundleTestInfo = new BundleTestInfo(); - } - - /** - * Called before each @Test. - */ - @Before - public void before() { - bundleContext = osgi.getFramework().getBundleContext(); - - here = Paths.get(".").toAbsolutePath().normalize(); - } +public abstract class AbstractLoadBundleTest extends AbstractOsgiTest { private Bundle getApiBundle() throws BundleException { - final Path apiPath = here.resolveSibling("log4j-api").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-api")); - return bundleContext.installBundle(apiPath.toUri().toString()); + final Path apiPath = getHere().resolveSibling("log4j-api").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-api")); + return getBundleContext().installBundle(apiPath.toUri().toString()); } private Bundle getCoreBundle() throws BundleException { - final Path corePath = here.resolveSibling("log4j-core").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-core")); - return bundleContext.installBundle(corePath.toUri().toString()); + final Path corePath = getHere().resolveSibling("log4j-core").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-core")); + return getBundleContext().installBundle(corePath.toUri().toString()); } private Bundle getDummyBundle() throws BundleException { - final Path dumyPath = here.resolveSibling("log4j-samples").resolve("log4j-samples-configuration").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-samples-configuration")); - return bundleContext.installBundle(dumyPath.toUri().toString()); + final Path dumyPath = getHere().resolveSibling("log4j-samples").resolve("log4j-samples-configuration").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-samples-configuration")); + return getBundleContext().installBundle(dumyPath.toUri().toString()); } private Bundle get12ApiBundle() throws BundleException { - final Path apiPath = here.resolveSibling("log4j-1.2-api").resolve("target").resolve(bundleTestInfo.buildJarFileName("log4j-1.2-api")); - return bundleContext.installBundle(apiPath.toUri().toString()); + final Path apiPath = getHere().resolveSibling("log4j-1.2-api").resolve("target").resolve(getBundleTestInfo().buildJarFileName("log4j-1.2-api")); + return getBundleContext().installBundle(apiPath.toUri().toString()); } @@ -314,7 +282,7 @@ public void testLog4J12Fragement() throws BundleException, ReflectiveOperationEx core.stop(); api.stop(); - + uninstall(api, core, compat); } diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java new file mode 100644 index 00000000000..bd47a89a428 --- /dev/null +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java @@ -0,0 +1,74 @@ +/* + * 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.osgi.tests; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.logging.log4j.osgi.tests.junit.BundleTestInfo; +import org.apache.logging.log4j.osgi.tests.junit.OsgiTestRule; +import org.junit.Before; +import org.junit.Rule; +import org.osgi.framework.BundleContext; +import org.osgi.framework.launch.FrameworkFactory; + +/** + * Tests a basic Log4J 'setup' in an OSGi container. + */ +public abstract class AbstractOsgiTest { + + private BundleContext bundleContext; + + private final BundleTestInfo bundleTestInfo; + + private Path here; + + @Rule + public OsgiTestRule osgi = new OsgiTestRule(getFactory()); + + /** + * Constructs a test for a given bundle. + */ + public AbstractOsgiTest() { + super(); + this.bundleTestInfo = new BundleTestInfo(); + } + + /** + * Called before each @Test. + */ + @Before + public void before() { + bundleContext = osgi.getFramework().getBundleContext(); + here = Paths.get(".").toAbsolutePath().normalize(); + } + + public BundleContext getBundleContext() { + return bundleContext; + } + + public BundleTestInfo getBundleTestInfo() { + return bundleTestInfo; + } + + protected abstract FrameworkFactory getFactory(); + + public Path getHere() { + return here; + } + +} From c7c7aaa460ba0f387abf9079415c0ad9576d2fd3 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 11:51:55 -0700 Subject: [PATCH 0038/2347] Javadoc. --- .../org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java index bd47a89a428..a717c464f5d 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractOsgiTest.java @@ -27,7 +27,7 @@ import org.osgi.framework.launch.FrameworkFactory; /** - * Tests a basic Log4J 'setup' in an OSGi container. + * Subclasses can tests a basic setup in an OSGi container. */ public abstract class AbstractOsgiTest { From 113611db542cf6566909239323a5795927e8d3cf Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 12:01:24 -0700 Subject: [PATCH 0039/2347] Refactoring in test framework before porting to Apache Commons Testing. --- .../logging/log4j/osgi/tests/AbstractLoadBundleTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java index 8b0a6656c29..5b63c6561d4 100644 --- a/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java +++ b/log4j-osgi/src/test/java/org/apache/logging/log4j/osgi/tests/AbstractLoadBundleTest.java @@ -26,7 +26,6 @@ import org.junit.Test; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; -import org.osgi.framework.launch.FrameworkFactory; /** * Tests a basic Log4J 'setup' in an OSGi container. @@ -55,8 +54,6 @@ private Bundle get12ApiBundle() throws BundleException { } - protected abstract FrameworkFactory getFactory(); - private void log(final Bundle dummy) throws ReflectiveOperationException { // use reflection to log in the context of the dummy bundle From fd21d224b519ce0a479bb0c468907f6a01917f87 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 7 Feb 2018 12:04:51 -0700 Subject: [PATCH 0040/2347] Remove unused class that is now in log4j-osgi. --- .../logging/log4j/junit/BundleTestInfo.java | 71 ------------------- 1 file changed, 71 deletions(-) delete mode 100644 log4j-api/src/test/java/org/apache/logging/log4j/junit/BundleTestInfo.java diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/junit/BundleTestInfo.java b/log4j-api/src/test/java/org/apache/logging/log4j/junit/BundleTestInfo.java deleted file mode 100644 index 7cdf46831da..00000000000 --- a/log4j-api/src/test/java/org/apache/logging/log4j/junit/BundleTestInfo.java +++ /dev/null @@ -1,71 +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.junit; - -import java.io.FileReader; -import java.io.IOException; - -import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; - -/** - * Provides tests with bundle information. Reads the {@code pom.xml} in the current directory to get project settings. - */ -public class BundleTestInfo { - - private final MavenProject project; - - /** - * Constructs a new helper objects and initializes itself. - */ - public BundleTestInfo() { - try (final FileReader reader = new FileReader("pom.xml")) { - // get a raw POM view, not a fully realized POM object. - final Model model = new MavenXpp3Reader().read(reader); - this.project = new MavenProject(model); - } catch (final IOException | XmlPullParserException e) { - throw new IllegalStateException("Could not read pom.xml", e); - } - } - - /** - * Gets the Maven artifact ID. - * - * @return the Maven artifact ID. - */ - public String getArtifactId() { - return project.getArtifactId(); - } - - /** - * Gets the Maven version String. - * - * @return the Maven version String. - */ - public String getVersion() { - return project.getVersion(); - } - - @Override - public String toString() { - return "BundleTestInfo [project=" + project + "]"; - } - -} From 5c5716bdf0494b70115960aa998776ce2de9dc66 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 8 Feb 2018 21:08:57 -0700 Subject: [PATCH 0041/2347] [LOG4J2-2243] Cannot see or copy all of certain JAnsi exception messages on Windows due to NUL characters. --- .../src/main/java/org/apache/logging/log4j/util/Chars.java | 3 +++ .../logging/log4j/core/appender/ConsoleAppender.java | 7 ++++++- src/changes/changes.xml | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Chars.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Chars.java index c6642eac3ff..996a5b13f52 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Chars.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Chars.java @@ -33,6 +33,9 @@ public final class Chars { /** Line Feed. */ public static final char LF = '\n'; + /** NUL. */ + public static final char NUL = 0; + /** Single Quote [']. */ public static final char QUOTE = '\''; 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 90d16e6a961..f6103e635f4 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 @@ -39,6 +39,7 @@ import org.apache.logging.log4j.core.util.Booleans; import org.apache.logging.log4j.core.util.CloseShieldOutputStream; import org.apache.logging.log4j.core.util.Throwables; +import org.apache.logging.log4j.util.Chars; import org.apache.logging.log4j.util.LoaderUtil; import org.apache.logging.log4j.util.PropertiesUtil; @@ -273,11 +274,15 @@ private static OutputStream getOutputStream(final boolean follow, final boolean } 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, Throwables.getRootCause(ex).toString().trim()); + LOGGER.warn("Unable to instantiate {} due to {}", JANSI_CLASS, clean(Throwables.getRootCause(ex).toString()).trim()); } return outputStream; } + private static String clean(String string) { + return string.replace(Chars.NUL, Chars.SPACE); + } + /** * An implementation of OutputStream that redirects to the current System.err. */ diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 469493ae421..23f5d08e577 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -193,6 +193,9 @@ Update Jackson from 2.9.3 to 2.9.4. + + Cannot see or copy all of certain JAnsi exception messages on Windows due to NUL characters. + From ad5a3a8deed0f3066cf1d08235dc56c21fee511d Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 10 Feb 2018 09:47:29 -0700 Subject: [PATCH 0042/2347] Remove comment that no longer applies since this is an interface and not a class with factory methods. --- .../java/org/apache/logging/log4j/core/lookup/StrLookup.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrLookup.java index e29d2804a27..cdef668b750 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrLookup.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/StrLookup.java @@ -26,10 +26,6 @@ * demand based on the key. *

*

- * This class comes complete with various factory methods. - * If these do not suffice, you can subclass and implement your own matcher. - *

- *

* For example, it would be possible to implement a lookup that used the * key as a primary key, and looked up the value on demand from the database *

From 585d5ca8d6b101603599385982609229ff8ee7bf Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 10 Feb 2018 09:54:34 -0700 Subject: [PATCH 0043/2347] [LOG4J2-2244] org.apache.logging.log4j.core.lookup.EnvironmentLookup may throw NPE. --- .../log4j/core/lookup/EnvironmentLookup.java | 15 ++++++++++----- src/changes/changes.xml | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/EnvironmentLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/EnvironmentLookup.java index 1d3b8115e3b..7f0d9355853 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/EnvironmentLookup.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/EnvironmentLookup.java @@ -26,13 +26,18 @@ public class EnvironmentLookup extends AbstractLookup { /** - * Looks up the value of the environment variable. - * @param event The current LogEvent (is ignored by this StrLookup). - * @param key the key to be looked up, may be null - * @return The value of the environment variable. + * Looks up the value of the given environment variable. + * + * @param event + * The current LogEvent (ignored by this StrLookup). + * @param key + * the key to look up, may be null + * @return the string value of the variable, or null if the variable is not defined in the system + * environment */ @Override public String lookup(final LogEvent event, final String key) { - return System.getenv(key); + // getenv throws NullPointerException if name is null + return key != null ? System.getenv(key) : null; } } diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 23f5d08e577..ea96b881de0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -55,6 +55,9 @@ Move JDBC code to a new module log4j-jdbc. + + org.apache.logging.log4j.core.lookup.EnvironmentLookup may throw NPE. + From f8158646d9aa324302026c033783909108ad9da5 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 10 Feb 2018 09:59:10 -0700 Subject: [PATCH 0044/2347] Fix incorrect Javadoc. --- .../logging/log4j/core/lookup/SystemPropertiesLookup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/SystemPropertiesLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/SystemPropertiesLookup.java index d2fb530d8c4..b74569a686e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/SystemPropertiesLookup.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/SystemPropertiesLookup.java @@ -33,7 +33,7 @@ public class SystemPropertiesLookup extends AbstractLookup { private static final Marker LOOKUP = MarkerManager.getMarker("LOOKUP"); /** - * Looks up the value for the key using the data in the LogEvent. + * Looks up the value for the key from system properties. * @param event The current LogEvent. * @param key the key to be looked up, may be null * @return The value associated with the key. From 9eb14d414fa92ad145a1ac2a469de708b155c4d6 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 10 Feb 2018 11:32:26 -0700 Subject: [PATCH 0045/2347] Javadoc fix. --- .../java/org/apache/logging/log4j/core/lookup/JavaLookup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JavaLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JavaLookup.java index 08e388530fa..4b230f970b4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JavaLookup.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/JavaLookup.java @@ -89,7 +89,7 @@ public String getVirtualMachine() { } /** - * Looks up the value of the environment variable. + * Looks up the value of the Java platform key. * * @param event * The current LogEvent (is ignored by this StrLookup). From 9c099b25169f77a0f217c939b1eedbc413553fae Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 10 Feb 2018 11:49:04 -0700 Subject: [PATCH 0046/2347] Javadoc. --- .../java/org/apache/logging/log4j/core/lookup/Interpolator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java index 122515c26ad..e09cd9e83dd 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/Interpolator.java @@ -32,7 +32,7 @@ import org.apache.logging.log4j.util.Constants; /** - * Proxies all the other {@link StrLookup}s. + * Proxies other {@link StrLookup}s using a keys within ${} markers. */ public class Interpolator extends AbstractConfigurationAwareLookup { From c580bb7beb1cbfa5f1a141363be15e43a1fcfaf8 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 10 Feb 2018 18:15:24 -0700 Subject: [PATCH 0047/2347] [LOG4J2-2245] Update Apache Commons Compress from 1.15 to 1.16.1. --- pom.xml | 2 +- src/changes/changes.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ed00dd87018..494fc7bf9f4 100644 --- a/pom.xml +++ b/pom.xml @@ -790,7 +790,7 @@ org.apache.commons commons-compress - 1.15 + 1.16.1 org.tukaani diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ea96b881de0..008b6820c04 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -199,6 +199,9 @@ Cannot see or copy all of certain JAnsi exception messages on Windows due to NUL characters. + + Update Apache Commons Compress from 1.15 to 1.16.1. + From 1175e4a89809d8fba68c5a25d0b780d2f044fbfe Mon Sep 17 00:00:00 2001 From: rpopma Date: Sun, 11 Feb 2018 17:47:43 +0900 Subject: [PATCH 0048/2347] Add TOC for Maven, Ivy, Gradle Artifacts page to left-nav menu --- src/site/site.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/site/site.xml b/src/site/site.xml index 6e0ac6293e0..b30d20147c9 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -37,7 +37,15 @@ - + + + + + + + + + From 1d55f0f1f9c16c376f4f61b7851f262c1a0f2830 Mon Sep 17 00:00:00 2001 From: rpopma Date: Fri, 16 Feb 2018 12:58:17 +0900 Subject: [PATCH 0049/2347] LOG4J2-2250 The internal status logger timestamp format is now configurable with system property `log4j2.StatusLogger.dateformat`. (cherry picked from commit 377570d) --- .../logging/log4j/status/StatusLogger.java | 10 ++++++- src/site/xdoc/manual/configuration.xml.vm | 28 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java index 25e85ffadc0..57da8f9ef1e 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java @@ -64,6 +64,13 @@ public final class StatusLogger extends AbstractLogger { */ public static final String DEFAULT_STATUS_LISTENER_LEVEL = "log4j2.StatusLogger.level"; + /** + * System property that can be configured with a date-time format string to use as the format for timestamps + * in the status logger output. See {@link java.text.SimpleDateFormat} for supported formats. + * @since 2.11.0 + */ + public static final String STATUS_DATE_FORMAT = "log4j2.StatusLogger.dateformat"; + private static final long serialVersionUID = 2L; private static final String NOT_AVAIL = "?"; @@ -96,7 +103,8 @@ public final class StatusLogger extends AbstractLogger { private StatusLogger(final String name, final MessageFactory messageFactory) { super(name, messageFactory); - this.logger = new SimpleLogger("StatusLogger", Level.ERROR, false, true, false, false, Strings.EMPTY, + this.logger = new SimpleLogger("StatusLogger", Level.ERROR, false, true, false, false, + System.getProperty(STATUS_DATE_FORMAT, Strings.EMPTY), messageFactory, PROPS, System.err); this.listenersLevel = Level.toLevel(DEFAULT_STATUS_LEVEL, Level.WARN).intLevel(); diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm index 525baa108fd..9c773c280a5 100644 --- a/src/site/xdoc/manual/configuration.xml.vm +++ b/src/site/xdoc/manual/configuration.xml.vm @@ -1623,7 +1623,17 @@ public class AwesomeTest { column contains the name used in properties files and system properties; Environemt Variable for the equivalent environment variable; and Legacy Property Name for the pre-2.10 name.

- + +
@@ -1699,7 +1709,8 @@ public class AwesomeTest { @@ -1708,7 +1719,8 @@ public class AwesomeTest { @@ -2022,6 +2034,16 @@ public class AwesomeTest { StatusLogger.getStatusData(). + + + + + + + From 08d2c1ef3cbdb7eb4512194c5981c81b693c051b Mon Sep 17 00:00:00 2001 From: rpopma Date: Fri, 16 Feb 2018 12:59:09 +0900 Subject: [PATCH 0050/2347] LOG4J2-2250 update change log (configurable status logger timestamps) (cherry picked from commit 7588d3f) --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 008b6820c04..58f434023c3 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -60,6 +60,9 @@ + + The internal status logger timestamp format is now configurable with system property `log4j2.StatusLogger.dateformat`. + Removed unnecessary dependency on jcommander since Log4j uses embedded picocli since 2.9. From 384e929d5d24bcb9669fa05d3a738865426eb8c0 Mon Sep 17 00:00:00 2001 From: rpopma Date: Fri, 16 Feb 2018 21:30:35 +0900 Subject: [PATCH 0051/2347] Move Legacy Property Name into same column as Property Name to prevent page from overflowing horizontally. (cherry picked from commit e83d0fa) --- src/site/xdoc/manual/configuration.xml.vm | 379 ++++++++++++++-------- 1 file changed, 247 insertions(+), 132 deletions(-) diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm index 9c773c280a5..b6d4a29a07a 100644 --- a/src/site/xdoc/manual/configuration.xml.vm +++ b/src/site/xdoc/manual/configuration.xml.vm @@ -1636,26 +1636,29 @@ public class AwesomeTest {
Log4j 2 global configuration properties
Property Nameorg.apache.logging.log4j.simple .SimpleLoggerContextFactory Factory class used by LogManager to bootstrap the logging implementation. - The core jar provides org.apache.logging.log4j.core.impl.Log4jContextFactory. + The core jar provides org.apache.logging.log4j.core + .impl.Log4jContextFactory.
log4j.configurationFactory   - Fully specified class name of a class extending org.apache.logging.log4j.core.config.ConfigurationFactory. + Fully specified class name of a class extending org.apache.logging.log4j.core + .config.ConfigurationFactory. If specified, an instance of this class is added to the list of configuration factories.
log4j2.statusLoggerDateformatLOG4J_STATUS_LOGGER_DATEFORMATlog4j2.StatusLogger.dateformat"yyyy/MM/dd HH:mm:ss:SSS zzz" + Date-time format string to use as the format for timestamps + in the status logger output. See java.text.SimpleDateFormat for supported formats. +
log4j2.asyncLoggerExceptionHandler LOG4J_ASYNC_LOGGER_EXCEPTION_HANDLER
- + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - --> - + - - - + - - - + - - - + - - - + - - - + - - - + - - - + - - - + - - - + - - + - - + - - + - - + - + - - + - - + - @@ -2074,9 +2151,11 @@ public class AwesomeTest { - + - @@ -2085,27 +2164,33 @@ public class AwesomeTest { - + - - + - - + - @@ -2114,11 +2199,13 @@ public class AwesomeTest { - + - - + - + - @@ -2138,9 +2227,11 @@ public class AwesomeTest { - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - From a3cd18e694674fd01e0d36b73e68161ee8197962 Mon Sep 17 00:00:00 2001 From: rpopma Date: Fri, 16 Feb 2018 21:39:46 +0900 Subject: [PATCH 0052/2347] LOG4J2-2250 (configurable status logger timestamps) bugfix: use PropertiesUtil instead of System properties; set showDateTime flag (cherry picked from commit 629fa2f) --- .../java/org/apache/logging/log4j/status/StatusLogger.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java index 57da8f9ef1e..3f9f6f36649 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java @@ -103,9 +103,10 @@ public final class StatusLogger extends AbstractLogger { private StatusLogger(final String name, final MessageFactory messageFactory) { super(name, messageFactory); - this.logger = new SimpleLogger("StatusLogger", Level.ERROR, false, true, false, false, - System.getProperty(STATUS_DATE_FORMAT, Strings.EMPTY), - messageFactory, PROPS, System.err); + final String dateFormat = PROPS.getStringProperty(STATUS_DATE_FORMAT, Strings.EMPTY); + final boolean showDateTime = !Strings.isEmpty(dateFormat); + this.logger = new SimpleLogger("StatusLogger", Level.ERROR, false, true, showDateTime, false, + dateFormat, messageFactory, PROPS, System.err); this.listenersLevel = Level.toLevel(DEFAULT_STATUS_LEVEL, Level.WARN).intLevel(); // LOG4J2-1813 if system property "log4j2.debug" is defined, print all status logging From 89756bb87d50eaee5a97cfc84a5725c2ade40f26 Mon Sep 17 00:00:00 2001 From: rpopma Date: Sat, 17 Feb 2018 13:56:44 +0900 Subject: [PATCH 0053/2347] LOG4J2-2250 (configurable status logger timestamps) renamed property to use CamelCase after community feedback --- .../main/java/org/apache/logging/log4j/status/StatusLogger.java | 2 +- src/changes/changes.xml | 2 +- src/site/xdoc/manual/configuration.xml.vm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java index 3f9f6f36649..3de75f65dde 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java @@ -69,7 +69,7 @@ public final class StatusLogger extends AbstractLogger { * in the status logger output. See {@link java.text.SimpleDateFormat} for supported formats. * @since 2.11.0 */ - public static final String STATUS_DATE_FORMAT = "log4j2.StatusLogger.dateformat"; + public static final String STATUS_DATE_FORMAT = "log4j2.StatusLogger.DateFormat"; private static final long serialVersionUID = 2L; diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 58f434023c3..95868a7f2ff 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -61,7 +61,7 @@ - The internal status logger timestamp format is now configurable with system property `log4j2.StatusLogger.dateformat`. + The internal status logger timestamp format is now configurable with system property `log4j2.StatusLogger.DateFormat`. Removed unnecessary dependency on jcommander since Log4j uses embedded picocli since 2.9. diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm index b6d4a29a07a..8acdd40e1ab 100644 --- a/src/site/xdoc/manual/configuration.xml.vm +++ b/src/site/xdoc/manual/configuration.xml.vm @@ -2106,7 +2106,7 @@ public class AwesomeTest { From 305831f340e54935e526fd63570e149cf7f499ed Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sat, 17 Feb 2018 16:33:38 -0700 Subject: [PATCH 0054/2347] LOG4J2-2255 - Use Spotbugs instead of Findbugs. Minimum version is Java 8 --- log4j-1.2-api/pom.xml | 7 +++--- log4j-api/pom.xml | 9 ++++---- log4j-appserver/pom.xml | 8 +++---- log4j-cassandra/pom.xml | 7 +++--- log4j-core/pom.xml | 8 +++---- log4j-couchdb/pom.xml | 7 +++--- log4j-csv/pom.xml | 7 +++--- log4j-flume-ng/pom.xml | 7 +++--- log4j-iostreams/pom.xml | 7 +++--- log4j-jcl/pom.xml | 7 +++--- log4j-jdbc-dbcp2/pom.xml | 7 +++--- log4j-jdbc/pom.xml | 7 +++--- log4j-jeromq/pom.xml | 7 +++--- log4j-jms/pom.xml | 7 +++--- log4j-jmx-gui/pom.xml | 7 +++--- log4j-jpa/pom.xml | 7 +++--- log4j-jul/pom.xml | 7 +++--- log4j-kafka/pom.xml | 7 +++--- log4j-liquibase/pom.xml | 7 +++--- log4j-mongodb2/pom.xml | 7 +++--- log4j-mongodb3/pom.xml | 7 +++--- log4j-osgi/pom.xml | 7 +++--- log4j-slf4j-impl/pom.xml | 7 +++--- log4j-smtp/pom.xml | 7 +++--- log4j-taglib/pom.xml | 7 +++--- log4j-to-slf4j/pom.xml | 7 +++--- log4j-web/pom.xml | 7 +++--- pom.xml | 22 +++++++++++++++---- ...-filter.xml => spotbugs-exclude-filter.xml | 2 +- src/site/xdoc/manual/layouts.xml.vm | 2 +- 30 files changed, 105 insertions(+), 114 deletions(-) rename findbugs-exclude-filter.xml => spotbugs-exclude-filter.xml (94%) diff --git a/log4j-1.2-api/pom.xml b/log4j-1.2-api/pom.xml index 95c6c9b3c59..c4212763157 100644 --- a/log4j-1.2-api/pom.xml +++ b/log4j-1.2-api/pom.xml @@ -170,15 +170,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml index 5ee38a4c2bd..8d9af2448e7 100644 --- a/log4j-api/pom.xml +++ b/log4j-api/pom.xml @@ -293,7 +293,9 @@ and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]> + false false + -Xdoclint:none true http://www.osgi.org/javadoc/r4v43/core/ @@ -309,15 +311,14 @@
- org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-appserver/pom.xml b/log4j-appserver/pom.xml index 79fbad84a2d..9c2f20bc92a 100644 --- a/log4j-appserver/pom.xml +++ b/log4j-appserver/pom.xml @@ -161,6 +161,7 @@ and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]> + ${javadoc.opts} false true @@ -177,15 +178,14 @@
- org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-cassandra/pom.xml b/log4j-cassandra/pom.xml index be370788737..34550225478 100644 --- a/log4j-cassandra/pom.xml +++ b/log4j-cassandra/pom.xml @@ -163,15 +163,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 76ac37ef38a..ab47ae60a10 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -509,6 +509,7 @@ and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]> + ${javadoc.opts} false true @@ -549,15 +550,14 @@
- org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-couchdb/pom.xml b/log4j-couchdb/pom.xml index 4e7e75a55fa..72b05050bdd 100644 --- a/log4j-couchdb/pom.xml +++ b/log4j-couchdb/pom.xml @@ -140,15 +140,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-csv/pom.xml b/log4j-csv/pom.xml index 3cec7bfa68c..69396cff19b 100644 --- a/log4j-csv/pom.xml +++ b/log4j-csv/pom.xml @@ -133,15 +133,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-flume-ng/pom.xml b/log4j-flume-ng/pom.xml index cdd2ca1ce30..64eb0e99601 100644 --- a/log4j-flume-ng/pom.xml +++ b/log4j-flume-ng/pom.xml @@ -211,15 +211,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-iostreams/pom.xml b/log4j-iostreams/pom.xml index 68efa5848a1..fc4179184ce 100644 --- a/log4j-iostreams/pom.xml +++ b/log4j-iostreams/pom.xml @@ -156,15 +156,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jcl/pom.xml b/log4j-jcl/pom.xml index 5113378123d..73c5d8d951c 100644 --- a/log4j-jcl/pom.xml +++ b/log4j-jcl/pom.xml @@ -146,15 +146,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jdbc-dbcp2/pom.xml b/log4j-jdbc-dbcp2/pom.xml index a9a77ff3b2e..6880b2ac0fa 100644 --- a/log4j-jdbc-dbcp2/pom.xml +++ b/log4j-jdbc-dbcp2/pom.xml @@ -138,15 +138,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jdbc/pom.xml b/log4j-jdbc/pom.xml index 195b7c28690..e56c2cdae8c 100644 --- a/log4j-jdbc/pom.xml +++ b/log4j-jdbc/pom.xml @@ -167,15 +167,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jeromq/pom.xml b/log4j-jeromq/pom.xml index 2f03dc6a09b..6064add9808 100644 --- a/log4j-jeromq/pom.xml +++ b/log4j-jeromq/pom.xml @@ -122,15 +122,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jms/pom.xml b/log4j-jms/pom.xml index 4d9d9929b31..89b9c940681 100644 --- a/log4j-jms/pom.xml +++ b/log4j-jms/pom.xml @@ -136,15 +136,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jmx-gui/pom.xml b/log4j-jmx-gui/pom.xml index ad6c84be334..9e242763b0e 100644 --- a/log4j-jmx-gui/pom.xml +++ b/log4j-jmx-gui/pom.xml @@ -140,15 +140,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jpa/pom.xml b/log4j-jpa/pom.xml index 9baa151647f..e434c1d08ca 100644 --- a/log4j-jpa/pom.xml +++ b/log4j-jpa/pom.xml @@ -146,15 +146,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-jul/pom.xml b/log4j-jul/pom.xml index a1d9ccbd693..d0c3399964a 100644 --- a/log4j-jul/pom.xml +++ b/log4j-jul/pom.xml @@ -162,15 +162,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-kafka/pom.xml b/log4j-kafka/pom.xml index 9f6d44960e0..22910852302 100644 --- a/log4j-kafka/pom.xml +++ b/log4j-kafka/pom.xml @@ -127,15 +127,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-liquibase/pom.xml b/log4j-liquibase/pom.xml index 34fb47d21c4..c7487669136 100644 --- a/log4j-liquibase/pom.xml +++ b/log4j-liquibase/pom.xml @@ -217,15 +217,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-mongodb2/pom.xml b/log4j-mongodb2/pom.xml index 9f22ba97eed..daeb6fde3b8 100644 --- a/log4j-mongodb2/pom.xml +++ b/log4j-mongodb2/pom.xml @@ -145,15 +145,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-mongodb3/pom.xml b/log4j-mongodb3/pom.xml index 2d6667db5a6..4142024414a 100644 --- a/log4j-mongodb3/pom.xml +++ b/log4j-mongodb3/pom.xml @@ -149,15 +149,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-osgi/pom.xml b/log4j-osgi/pom.xml index 6200b86a9a1..5cd98f47003 100644 --- a/log4j-osgi/pom.xml +++ b/log4j-osgi/pom.xml @@ -178,15 +178,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-slf4j-impl/pom.xml b/log4j-slf4j-impl/pom.xml index 2b5fcdd2d91..a2ea313b1cc 100644 --- a/log4j-slf4j-impl/pom.xml +++ b/log4j-slf4j-impl/pom.xml @@ -168,15 +168,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-smtp/pom.xml b/log4j-smtp/pom.xml index 99cb383bdea..f53b66293d3 100644 --- a/log4j-smtp/pom.xml +++ b/log4j-smtp/pom.xml @@ -122,15 +122,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-taglib/pom.xml b/log4j-taglib/pom.xml index 8c321a1b271..ba309b70cfd 100644 --- a/log4j-taglib/pom.xml +++ b/log4j-taglib/pom.xml @@ -161,15 +161,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-to-slf4j/pom.xml b/log4j-to-slf4j/pom.xml index e544bbde6cc..e123b91d27b 100644 --- a/log4j-to-slf4j/pom.xml +++ b/log4j-to-slf4j/pom.xml @@ -151,15 +151,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/log4j-web/pom.xml b/log4j-web/pom.xml index 1d4300c8594..69bc40a5173 100644 --- a/log4j-web/pom.xml +++ b/log4j-web/pom.xml @@ -149,15 +149,14 @@ - org.codehaus.mojo - findbugs-maven-plugin - ${findbugs.plugin.version} + com.github.spotbugs + spotbugs-maven-plugin true -Duser.language=en Normal Default - ${log4jParentDir}/findbugs-exclude-filter.xml + ${log4jParentDir}/spotbugs-exclude-filter.xml diff --git a/pom.xml b/pom.xml index 494fc7bf9f4..3d406c98b2d 100644 --- a/pom.xml +++ b/pom.xml @@ -190,7 +190,8 @@ 3.6.1 3.7.0 3.8 - 3.0.5 + 3.1.0-RC7 + 3.1.1 2.12.1 3.0.0 @@ -215,8 +216,8 @@ 1.5 1.5 ${project.build.outputDirectory}/META-INF/MANIFEST.MF - 1.7 - 1.7 + 1.8 + 1.8 Site Documentation 1.2 @@ -831,7 +832,7 @@ de.flapdoodle.embed.mongo 2.0.1 test - + @@ -976,6 +977,19 @@ maven-assembly-plugin 3.1.0 + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs.plugin.version} + + + + com.github.spotbugs + spotbugs + ${spotbugs.version} + + + diff --git a/findbugs-exclude-filter.xml b/spotbugs-exclude-filter.xml similarity index 94% rename from findbugs-exclude-filter.xml rename to spotbugs-exclude-filter.xml index 327be31718b..b77b2f6e7ab 100644 --- a/findbugs-exclude-filter.xml +++ b/spotbugs-exclude-filter.xml @@ -17,7 +17,7 @@ --> - + diff --git a/src/site/xdoc/manual/layouts.xml.vm b/src/site/xdoc/manual/layouts.xml.vm index 1f404273ece..1340787ef30 100644 --- a/src/site/xdoc/manual/layouts.xml.vm +++ b/src/site/xdoc/manual/layouts.xml.vm @@ -1646,7 +1646,7 @@ WARN [main]: Message 2
From 8a8cb421d835bf8b4e815367f797a3ff04987424 Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sat, 17 Feb 2018 16:35:27 -0700 Subject: [PATCH 0055/2347] LOG4J2-2255 - Use Spotbugs instead of Findbugs. Minimum version is Java 8 --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 95868a7f2ff..8348f4902bb 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -31,6 +31,9 @@ - "remove" - Removed --> + + Use Spotbugs instead of Findbugs. Minimum version is Java 8. + Renamed package core.util.datetime to core.time.internal.format to clarify these classes are to be considered private. From a9e7cd6caf9caaf7dbc241390b8f587914d77933 Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sun, 18 Feb 2018 20:46:34 -0700 Subject: [PATCH 0056/2347] LOG4J2-2247 - NullPointerException would occur when header was provided to a Layout on RollingRandingAccessFileAppender with DirectWriteRolloverStrategy. --- .../core/appender/rolling/RollingRandomAccessFileManager.java | 2 +- log4j-core/src/test/resources/log4j-rolling-random-direct.xml | 2 +- src/changes/changes.xml | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java index 0d60483495a..e8b6cb909de 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java @@ -87,7 +87,7 @@ private void writeHeader() { return; } try { - if (randomAccessFile.length() == 0) { + if (randomAccessFile != null && randomAccessFile.length() == 0) { // write to the file, not to the buffer: the buffer may not be empty randomAccessFile.write(header, 0, header.length); } diff --git a/log4j-core/src/test/resources/log4j-rolling-random-direct.xml b/log4j-core/src/test/resources/log4j-rolling-random-direct.xml index 4be5b625baf..0d1dc18983d 100644 --- a/log4j-core/src/test/resources/log4j-rolling-random-direct.xml +++ b/log4j-core/src/test/resources/log4j-rolling-random-direct.xml @@ -27,7 +27,7 @@ - + %d %p %C{1.} [%t] %m%n diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8348f4902bb..ff63006ffe0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -63,6 +63,10 @@ + + NullPointerException would occur when header was provided to a Layout on RollingRandingAccessFileAppender + with DirectWriteRolloverStrategy. + The internal status logger timestamp format is now configurable with system property `log4j2.StatusLogger.DateFormat`. From ec3c623a87d648e134d15ffb711b4067272d86e3 Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sun, 18 Feb 2018 22:03:46 -0700 Subject: [PATCH 0057/2347] LOG4J2-2254 - Incorrect automatics module name header was being included in manifests. --- log4j-api/pom.xml | 2 +- log4j-core/pom.xml | 2 +- pom.xml | 52 ++++++++++++++++++++++++----------------- src/changes/changes.xml | 3 +++ 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml index 8d9af2448e7..016b4858a8b 100644 --- a/log4j-api/pom.xml +++ b/log4j-api/pom.xml @@ -165,7 +165,7 @@ jar - + ${manifestfile} diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index ab47ae60a10..b791acc6bd3 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -406,7 +406,7 @@ jar - + ${manifestfile} diff --git a/pom.xml b/pom.xml index 3d406c98b2d..2c8f327be80 100644 --- a/pom.xml +++ b/pom.xml @@ -990,6 +990,36 @@ + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + default-jar + + jar + + + + ${manifestfile} + + ${project.name} + ${project.version} + ${project.organization.name} + ${project.name} + ${project.version} + ${project.organization.name} + org.apache + ${maven.compiler.source} + ${maven.compiler.target} + ${module.name} + + + + + + @@ -1001,28 +1031,6 @@ maven-clean-plugin 3.0.0 - - org.apache.maven.plugins - maven-jar-plugin - 3.0.2 - - - ${manifestfile} - - ${project.name} - ${project.version} - ${project.organization.name} - ${project.name} - ${project.version} - ${project.organization.name} - org.apache - ${maven.compiler.source} - ${maven.compiler.target} - ${module.name} - - - - maven-resources-plugin 3.0.2 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ff63006ffe0..d3f9420d1d8 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -63,6 +63,9 @@ + + Incorrect automatics module name header was being included in manifests. + NullPointerException would occur when header was provided to a Layout on RollingRandingAccessFileAppender with DirectWriteRolloverStrategy. From 0eb5212e4ac56030f07e88b9de432977e3808e48 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 19 Feb 2018 19:09:06 -0700 Subject: [PATCH 0058/2347] [LOG4J2-2237] Move Jackson-based layouts to their own modules: JSON, XML, and YAML. --- log4j-bom/pom.xml | 24 ++ log4j-core-its/pom.xml | 24 +- .../log4j/core/appender/HttpAppenderTest.java | 2 +- .../JsonCompleteFileAppenderTest.java | 4 +- ...SecureSocketAppenderSocketOptionsTest.java | 0 .../SocketAppenderBufferSizeTest.java | 0 .../SocketAppenderSocketOptionsTest.java | 0 .../core/appender/SocketAppenderTest.java | 9 +- .../appender/XmlCompactFileAppenderTest.java | 5 +- .../XmlCompactFileAppenderValidationTest.java | 0 ...ompactFileAsyncAppenderValidationTest.java | 0 .../appender/XmlCompleteFileAppenderTest.java | 7 +- .../core/appender/XmlFileAppenderTest.java | 6 +- .../XmlRandomAccessFileAppenderTest.java | 5 +- log4j-core/pom.xml | 6 - .../log4j/core/jackson/Initializers.java | 98 ----- .../logging/log4j/core/layout/GelfLayout.java | 2 +- .../log4j/core/layout/JacksonFactory.java | 237 ----------- .../parser/AbstractJacksonLogEventParser.java | 4 +- .../log4j/core/impl/ThrowableProxyTest.java | 18 +- .../log4j/core/layout/LogEventFixtures.java | 6 +- ...t.java => AbstractLogEventParserTest.java} | 6 +- .../src/test/resources/log4j2-xml-layout.xml | 31 ++ log4j-layout-jackson-json/pom.xml | 167 ++++++++ .../json/JsonSetupContextInitializer.java | 51 +++ .../log4j/jackson/json}/Log4jJsonModule.java | 13 +- .../jackson/json}/Log4jJsonObjectMapper.java | 2 +- .../json/layout/JsonJacksonFactory.java | 60 +++ .../jackson/json}/layout/JsonLayout.java | 234 ++++++----- .../json}/parser/JsonLogEventParser.java | 7 +- .../src/site/manual/index.md | 33 ++ log4j-layout-jackson-json/src/site/site.xml | 52 +++ .../json}/JacksonIssue429MyNamesTest.java | 4 +- .../jackson/json}/JacksonIssue429Test.java | 4 +- .../jackson/json}/LevelMixInJsonTest.java | 6 +- .../jackson/json}/MarkerMixInJsonTest.java | 9 +- .../json/StackTraceElementJsonMixInTest.java | 41 +- .../ConcurrentLoggingWithJsonLayoutTest.java | 57 +-- .../jackson/json}/layout/JsonLayoutTest.java | 212 +++++----- .../json/layout/ThrowableProxyJsonTest.java | 33 ++ .../json}/parser/JsonLogEventParserTest.java | 60 +-- .../src/test/resources/log4j2-json-layout.xml | 31 ++ .../log4j/jackson/xml}/Log4jXmlModule.java | 7 +- .../jackson/xml}/Log4jXmlObjectMapper.java | 2 +- .../log4j/jackson/xml/XmlInstantMixIn.java | 56 +++ .../xml/XmlLogEventWithContextListMixIn.java | 50 +++ .../log4j/jackson/xml/XmlMarkerMixIn.java | 79 ++++ .../xml/XmlSetupContextInitializer.java | 42 ++ .../xml/XmlStackTraceElementMixIn.java | 39 ++ .../xml/layout/Log4jXmlPrettyPrinter.java | 41 ++ .../jackson/xml/layout/XmlJacksonFactory.java | 54 +++ .../log4j/jackson/xml}/layout/XmlLayout.java | 188 +++++---- .../xml}/parser/XmlLogEventParser.java | 5 +- log4j-layout-jackson-xml/pom.xml | 171 ++++++++ .../jackson/xml/AbstractLogEventXmlMixIn.java | 135 +++++++ .../ContextDataAsEntryListXmlSerializer.java | 37 ++ .../ExtendedStackTraceElementXmlMixIn.java | 68 ++++ .../log4j/jackson/xml/InstantXmlMixIn.java | 56 +++ .../log4j/jackson/xml/Log4jXmlModule.java | 52 +++ .../jackson/xml/Log4jXmlObjectMapper.java | 48 +++ .../xml/LogEventWithContextListXmlMixIn.java | 48 +++ .../log4j/jackson/xml/MarkerXmlMixIn.java | 79 ++++ .../xml/StackTraceElementXmlMixIn.java | 40 ++ ...leProxyWithStacktraceAsStringXmlMixIn.java | 29 +- ...rowableProxyWithoutStacktraceXmlMixIn.java | 60 +++ .../jackson/xml/ThrowableProxyXmlMixIn.java | 24 +- .../log4j/jackson/xml/XmlMapEntry.java | 41 ++ .../xml/XmlSetupContextInitializer.java | 38 ++ .../xml/layout/Log4jXmlPrettyPrinter.java | 41 ++ .../jackson/xml/layout/XmlJacksonFactory.java | 54 +++ .../log4j/jackson/xml/layout/XmlLayout.java | 226 +++++++++++ .../jackson/xml/parser/XmlLogEventParser.java | 32 ++ .../src/site/manual/index.md | 33 ++ log4j-layout-jackson-xml/src/site/site.xml | 52 +++ .../log4j/jackson/xml}/LevelMixInXmlTest.java | 5 +- .../jackson/xml}/MarkerMixInXmlTest.java | 8 +- .../xml/StackTraceElementXmlMixInTest.java | 82 ++++ .../ConcurrentLoggingWithXmlLayoutTest.java | 116 ++++++ .../xml/layout/ThrowableProxyXmlTest.java | 33 ++ .../jackson/xml}/layout/XmlLayoutTest.java | 255 +++++++----- .../xml}/parser/XmlLogEventParserTest.java | 60 +-- .../src/test/resources/log4j2-xml-layout.xml | 31 ++ log4j-layout-jackson-yaml/pom.xml | 171 ++++++++ .../log4j/jackson/yaml}/Log4jYamlModule.java | 18 +- .../jackson/yaml}/Log4jYamlObjectMapper.java | 2 +- .../yaml/YamlSetupContextInitializer.java | 47 +++ .../jackson/yaml/layout/YamlConstants.java | 35 ++ .../yaml/layout/YamlJacksonFactory.java | 68 ++++ .../jackson/yaml}/layout/YamlLayout.java | 227 ++++++----- .../yaml}/parser/YamlLogEventParser.java | 5 +- .../src/site/manual/index.md | 33 ++ log4j-layout-jackson-yaml/src/site/site.xml | 52 +++ .../jackson/yaml}/LevelMixInYamlTest.java | 6 +- .../jackson/yaml}/MarkerMixInYamlTest.java | 8 +- .../yaml/StackTraceElementYamlMixInTest.java | 83 ++++ .../ConcurrentLoggingWithYamlLayoutTest.java | 113 ++++++ .../jackson/yaml}/layout/YamlLayoutTest.java | 114 +++--- .../yaml}/parser/YamlLogEventParserTest.java | 58 +-- .../src/test/resources/log4j2-yaml-layout.xml | 31 ++ log4j-layout-jackson/pom.xml | 214 ++++++++++ .../log4j/jackson/AbstractJacksonFactory.java | 74 ++++ .../log4j/jackson}/AbstractJacksonLayout.java | 293 +++++++------- .../log4j/jackson/AbstractLogEventMixIn.java | 84 ++++ .../ContextDataAsEntryListDeserializer.java | 10 +- .../ContextDataAsEntryListSerializer.java | 21 +- .../jackson/ContextDataDeserializer.java | 2 +- .../log4j}/jackson/ContextDataSerializer.java | 28 +- .../ExtendedStackTraceElementMixIn.java | 66 +-- .../logging/log4j}/jackson/InstantMixIn.java | 32 +- .../logging/log4j}/jackson/JsonConstants.java | 3 +- .../logging/log4j}/jackson/LevelMixIn.java | 4 +- .../jackson/ListOfMapEntryDeserializer.java | 2 +- .../jackson/ListOfMapEntrySerializer.java | 8 +- .../Log4jStackTraceElementDeserializer.java | 2 +- .../log4j}/jackson/LogEventJsonMixIn.java | 76 ++-- .../jackson/LogEventWithContextListMixIn.java | 47 +-- .../logging/log4j}/jackson/MapEntry.java | 13 +- .../logging/log4j}/jackson/MarkerMixIn.java | 13 +- .../log4j}/jackson/MessageSerializer.java | 6 +- ...MutableThreadContextStackDeserializer.java | 2 +- .../jackson/ObjectMessageSerializer.java | 8 +- .../jackson/SetupContextInitializer.java | 38 ++ .../jackson/SimpleMessageDeserializer.java | 8 +- .../jackson/SimpleModuleInitializer.java | 26 ++ .../jackson/StackTraceElementConstants.java | 30 ++ .../jackson/StackTraceElementMixIn.java | 43 +- .../log4j/jackson/ThrowableProxyMixIn.java | 70 ++++ ...wableProxyWithStacktraceAsStringMixIn.java | 70 ++++ .../ThrowableProxyWithoutStacktraceMixIn.java | 18 +- .../logging/log4j}/jackson/XmlConstants.java | 2 +- .../jackson/layout/AbstractJacksonLayout.java | 378 ++++++++++++++++++ .../logging/log4j}/jackson/package-info.java | 2 +- log4j-layout-jackson/src/site/manual/index.md | 33 ++ log4j-layout-jackson/src/site/site.xml | 52 +++ .../jackson/AbstractMarkerMixInTest.java | 41 +- .../log4j}/jackson/LevelMixInTest.java | 8 +- .../jackson/ThrowableProxyJacksonTest.java | 51 +++ pom.xml | 4 + src/changes/changes.xml | 3 + 139 files changed, 5507 insertions(+), 1536 deletions(-) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java (99%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java (99%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java (100%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java (100%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java (100%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java (99%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java (97%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java (100%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java (100%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java (98%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java (96%) rename {log4j-core => log4j-core-its}/src/test/java/org/apache/logging/log4j/core/appender/XmlRandomAccessFileAppenderTest.java (97%) delete mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java delete mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java rename log4j-core/src/test/java/org/apache/logging/log4j/core/parser/{LogEventParserTest.java => AbstractLogEventParserTest.java} (96%) create mode 100644 log4j-core/src/test/resources/log4j2-xml-layout.xml create mode 100644 log4j-layout-jackson-json/pom.xml create mode 100644 log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json}/Log4jJsonModule.java (81%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json}/Log4jJsonObjectMapper.java (97%) create mode 100644 log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonJacksonFactory.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json}/layout/JsonLayout.java (88%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json}/parser/JsonLogEventParser.java (78%) create mode 100644 log4j-layout-jackson-json/src/site/manual/index.md create mode 100644 log4j-layout-jackson-json/src/site/site.xml rename {log4j-core/src/test/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json}/JacksonIssue429MyNamesTest.java (99%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json}/JacksonIssue429Test.java (98%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json}/LevelMixInJsonTest.java (91%) rename {log4j-core/src/test/java/org/apache/logging/log4j => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json}/MarkerMixInJsonTest.java (85%) rename log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java (91%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json}/layout/ConcurrentLoggingWithJsonLayoutTest.java (95%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json}/layout/JsonLayoutTest.java (96%) create mode 100644 log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json}/parser/JsonLogEventParserTest.java (94%) create mode 100644 log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml rename {log4j-core/src/main/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml}/Log4jXmlModule.java (84%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml}/Log4jXmlObjectMapper.java (97%) create mode 100644 log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java create mode 100644 log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java create mode 100644 log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java create mode 100644 log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java create mode 100644 log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java create mode 100644 log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java create mode 100644 log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml}/layout/XmlLayout.java (71%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml}/parser/XmlLogEventParser.java (84%) create mode 100644 log4j-layout-jackson-xml/pom.xml create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java rename log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java => log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java (84%) create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java rename log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java => log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java (86%) create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java create mode 100644 log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java create mode 100644 log4j-layout-jackson-xml/src/site/manual/index.md create mode 100644 log4j-layout-jackson-xml/src/site/site.xml rename {log4j-core/src/test/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml}/LevelMixInXmlTest.java (92%) rename {log4j-core/src/test/java/org/apache/logging/log4j => log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml}/MarkerMixInXmlTest.java (86%) create mode 100644 log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java create mode 100644 log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java create mode 100644 log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml}/layout/XmlLayoutTest.java (67%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml}/parser/XmlLogEventParserTest.java (94%) create mode 100644 log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml create mode 100644 log4j-layout-jackson-yaml/pom.xml rename {log4j-core/src/main/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml}/Log4jYamlModule.java (78%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml}/Log4jYamlObjectMapper.java (97%) create mode 100644 log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java create mode 100644 log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java create mode 100644 log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml}/layout/YamlLayout.java (68%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml}/parser/YamlLogEventParser.java (85%) create mode 100644 log4j-layout-jackson-yaml/src/site/manual/index.md create mode 100644 log4j-layout-jackson-yaml/src/site/site.xml rename {log4j-core/src/test/java/org/apache/logging/log4j/core/jackson => log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml}/LevelMixInYamlTest.java (91%) rename {log4j-core/src/test/java/org/apache/logging/log4j => log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml}/MarkerMixInYamlTest.java (85%) create mode 100644 log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java create mode 100644 log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml}/layout/YamlLayoutTest.java (98%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml}/parser/YamlLogEventParserTest.java (94%) create mode 100644 log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-layout.xml create mode 100644 log4j-layout-jackson/pom.xml create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core/layout => log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson}/AbstractJacksonLayout.java (80%) create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ContextDataAsEntryListDeserializer.java (88%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ContextDataAsEntryListSerializer.java (77%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ContextDataDeserializer.java (97%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ContextDataSerializer.java (98%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ExtendedStackTraceElementMixIn.java (52%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/InstantMixIn.java (68%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/JsonConstants.java (94%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/LevelMixIn.java (94%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ListOfMapEntryDeserializer.java (97%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ListOfMapEntrySerializer.java (88%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/Log4jStackTraceElementDeserializer.java (98%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/LogEventJsonMixIn.java (61%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/LogEventWithContextListMixIn.java (68%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/MapEntry.java (87%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/MarkerMixIn.java (79%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/MessageSerializer.java (90%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/MutableThreadContextStackDeserializer.java (97%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ObjectMessageSerializer.java (86%) create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/SimpleMessageDeserializer.java (83%) create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SimpleModuleInitializer.java create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/StackTraceElementConstants.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/StackTraceElementMixIn.java (54%) create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/ThrowableProxyWithoutStacktraceMixIn.java (72%) rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/XmlConstants.java (97%) create mode 100644 log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java rename {log4j-core/src/main/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/main/java/org/apache/logging/log4j}/jackson/package-info.java (95%) create mode 100644 log4j-layout-jackson/src/site/manual/index.md create mode 100644 log4j-layout-jackson/src/site/site.xml rename log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInTest.java => log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/AbstractMarkerMixInTest.java (95%) rename {log4j-core/src/test/java/org/apache/logging/log4j/core => log4j-layout-jackson/src/test/java/org/apache/logging/log4j}/jackson/LevelMixInTest.java (98%) create mode 100644 log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java diff --git a/log4j-bom/pom.xml b/log4j-bom/pom.xml index 97021b2cf80..5ee35e8d8ce 100644 --- a/log4j-bom/pom.xml +++ b/log4j-bom/pom.xml @@ -42,6 +42,30 @@ log4j-core ${project.version} + + + org.apache.logging.log4j + log4j-layout-jackson + ${project.version} + + + + org.apache.logging.log4j + log4j-layout-jackson-json + ${project.version} + + + + org.apache.logging.log4j + log4j-layout-jackson-xml + ${project.version} + + + + org.apache.logging.log4j + log4j-layout-jackson-yaml + ${project.version} + org.apache.logging.log4j diff --git a/log4j-core-its/pom.xml b/log4j-core-its/pom.xml index 2a0cec1a2a8..513fce383aa 100644 --- a/log4j-core-its/pom.xml +++ b/log4j-core-its/pom.xml @@ -29,13 +29,14 @@ Integration Tests for the Apache Log4j Implementation ${basedir}/.. - Core Documentation - /core + Core Integration Tests Documentation + /log4j-core-its org.apache.logging.log4j log4j-api + test org.apache.logging.log4j @@ -46,6 +47,19 @@ org.apache.logging.log4j log4j-core + test + + + org.apache.logging.log4j + log4j-layout-jackson-json + ${project.version} + test + + + org.apache.logging.log4j + log4j-layout-jackson-xml + ${project.version} + test org.apache.logging.log4j @@ -53,6 +67,12 @@ test-jar test + + + com.github.tomakehurst + wiremock + test + com.lmax diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java similarity index 99% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java index 25261f95d98..4e9a07c28c6 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java @@ -35,12 +35,12 @@ import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.config.Property; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.layout.JsonLayout; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration; import org.apache.logging.log4j.core.net.ssl.SslConfiguration; import org.apache.logging.log4j.core.net.ssl.TestConstants; import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration; +import org.apache.logging.log4j.jackson.json.layout.JsonLayout; import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.status.StatusData; diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java similarity index 99% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java index 853f7e3f7c2..4c2da52e3a5 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/JsonCompleteFileAppenderTest.java @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.appender; +import static org.junit.Assert.assertTrue; + import java.io.File; import java.nio.charset.Charset; import java.nio.file.Files; @@ -39,8 +41,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static org.junit.Assert.*; - /** * Tests a "complete" JSON file. */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java similarity index 99% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java index 8aee640ca23..e02590c5f30 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java @@ -35,8 +35,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import com.fasterxml.jackson.databind.MappingIterator; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LoggingException; import org.apache.logging.log4j.ThreadContext; @@ -45,11 +43,11 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper; -import org.apache.logging.log4j.core.layout.JsonLayout; import org.apache.logging.log4j.core.net.Protocol; import org.apache.logging.log4j.core.util.Constants; import org.apache.logging.log4j.core.util.Throwables; +import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper; +import org.apache.logging.log4j.jackson.json.layout.JsonLayout; import org.apache.logging.log4j.test.AvailablePortFinder; import org.junit.After; import org.junit.AfterClass; @@ -58,6 +56,9 @@ import org.junit.Ignore; import org.junit.Test; +import com.fasterxml.jackson.databind.MappingIterator; +import com.fasterxml.jackson.databind.ObjectMapper; + /** * */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java similarity index 97% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java index c59ad9d13ae..eea989a5a51 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderTest.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.core.appender; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -29,8 +32,6 @@ import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.junit.Assert.*; - /** * Tests a "compact" XML file, no extra spaces or end of lines. */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAppenderValidationTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java similarity index 100% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompactFileAsyncAppenderValidationTest.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java index c77b464723c..9d86f6edf39 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlCompleteFileAppenderTest.java @@ -16,12 +16,15 @@ */ package org.apache.logging.log4j.core.appender; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.nio.charset.Charset; import java.nio.file.Files; -import java.nio.file.Paths; import java.util.List; import org.apache.logging.log4j.Logger; @@ -39,8 +42,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import static org.junit.Assert.*; - /** * Tests a "complete" XML file a.k.a. a well-formed XML file. */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java index f9cdff382eb..107ef227879 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlFileAppenderTest.java @@ -16,9 +16,9 @@ */ package org.apache.logging.log4j.core.appender; -import java.io.BufferedReader; +import static org.junit.Assert.assertTrue; + import java.io.File; -import java.io.FileReader; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.List; @@ -32,8 +32,6 @@ import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.junit.Assert.*; - /** * Tests a "complete" XML file a.k.a. a well-formed XML file. */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlRandomAccessFileAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlRandomAccessFileAppenderTest.java similarity index 97% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlRandomAccessFileAppenderTest.java rename to log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlRandomAccessFileAppenderTest.java index a907c7fe496..1794160b78f 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/XmlRandomAccessFileAppenderTest.java +++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/XmlRandomAccessFileAppenderTest.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.core.appender; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -30,8 +33,6 @@ import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.junit.Assert.*; - /** * Tests a "complete" XML file a.k.a. a well-formed XML file. */ diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index b791acc6bd3..196e4e55e49 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -279,12 +279,6 @@ groovy-all test - - - com.github.tomakehurst - wiremock - test - com.google.code.java-allocation-instrumenter diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java deleted file mode 100644 index 3bc34470452..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Initializers.java +++ /dev/null @@ -1,98 +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.jackson; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; -import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.message.ObjectMessage; - -import com.fasterxml.jackson.databind.Module.SetupContext; -import com.fasterxml.jackson.databind.module.SimpleModule; -import org.apache.logging.log4j.core.time.Instant; - -/** - * Initialization utils. - *

- * Consider this class private. - *

- */ -class Initializers { - - /** - * Used to set up {@link SetupContext} from different {@link SimpleModule}s. - */ - static class SetupContextInitializer { - - void setupModule(final SetupContext context, final boolean includeStacktrace, final boolean stacktraceAsString) { - // JRE classes: we cannot edit those with Jackson annotations - context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class); - // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not depend on Jackson. - context.setMixInAnnotations(Marker.class, MarkerMixIn.class); - context.setMixInAnnotations(Level.class, LevelMixIn.class); - context.setMixInAnnotations(Instant.class, InstantMixIn.class); - context.setMixInAnnotations(LogEvent.class, LogEventWithContextListMixIn.class); - // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. - context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class); - context.setMixInAnnotations(ThrowableProxy.class, - includeStacktrace ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class ) : ThrowableProxyWithoutStacktraceMixIn.class); - } - } - - /** - * Used to set up {@link SetupContext} from different {@link SimpleModule}s. - * Differs from SetupContextInitializer by installing {@code LogEventJsonMixIn} for LogEvents, - * not {@code LogEventMixIn}, so it handles ThreadContext serialization differently. - */ - static class SetupContextJsonInitializer { - - void setupModule(final SetupContext context, final boolean includeStacktrace, final boolean stacktraceAsString) { - // JRE classes: we cannot edit those with Jackson annotations - context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class); - // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not depend on Jackson. - context.setMixInAnnotations(Marker.class, MarkerMixIn.class); - context.setMixInAnnotations(Level.class, LevelMixIn.class); - context.setMixInAnnotations(Instant.class, InstantMixIn.class); - context.setMixInAnnotations(LogEvent.class, LogEventJsonMixIn.class); // different ThreadContext handling - // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. - context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class); - context.setMixInAnnotations(ThrowableProxy.class, - includeStacktrace ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class ) : ThrowableProxyWithoutStacktraceMixIn.class); - } - } - - /** - * Used to set up {@link SimpleModule} from different {@link SimpleModule} subclasses. - */ - static class SimpleModuleInitializer { - void initialize(final SimpleModule simpleModule, final boolean objectMessageAsJsonObject) { - // Workaround because mix-ins do not work for classes that already have a built-in deserializer. - // See Jackson issue 429. - simpleModule.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); - simpleModule.addDeserializer(ContextStack.class, new MutableThreadContextStackDeserializer()); - if (objectMessageAsJsonObject) { - simpleModule.addSerializer(ObjectMessage.class, new ObjectMessageSerializer()); - } - simpleModule.addSerializer(Message.class, new MessageSerializer()); - } - } - -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java index 45c5f4f8983..7f01f8ef526 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/GelfLayout.java @@ -294,7 +294,7 @@ public Map getContentFormat() { @Override public String getContentType() { - return JsonLayout.CONTENT_TYPE + "; charset=" + this.getCharset(); + return "application/json; charset=" + this.getCharset(); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java deleted file mode 100644 index b4c914c183e..00000000000 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JacksonFactory.java +++ /dev/null @@ -1,237 +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.layout; - -import java.util.HashSet; -import java.util.Set; - -import javax.xml.stream.XMLStreamException; - -import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.jackson.JsonConstants; -import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper; -import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper; -import org.apache.logging.log4j.core.jackson.Log4jYamlObjectMapper; -import org.apache.logging.log4j.core.jackson.XmlConstants; -import org.codehaus.stax2.XMLStreamWriter2; - -import com.fasterxml.jackson.core.PrettyPrinter; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.core.util.MinimalPrettyPrinter; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; -import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; -import com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter; - -abstract class JacksonFactory { - - static class JSON extends JacksonFactory { - - private final boolean encodeThreadContextAsList; - private final boolean includeStacktrace; - private final boolean stacktraceAsString; - private final boolean objectMessageAsJsonObject; - - public JSON(final boolean encodeThreadContextAsList, final boolean includeStacktrace, final boolean stacktraceAsString, final boolean objectMessageAsJsonObject) { - this.encodeThreadContextAsList = encodeThreadContextAsList; - this.includeStacktrace = includeStacktrace; - this.stacktraceAsString = stacktraceAsString; - this.objectMessageAsJsonObject = objectMessageAsJsonObject; - } - - @Override - protected String getPropertNameForContextMap() { - return JsonConstants.ELT_CONTEXT_MAP; - } - - @Override - protected String getPropertNameForSource() { - return JsonConstants.ELT_SOURCE; - } - - @Override - protected String getPropertNameForNanoTime() { - return JsonConstants.ELT_NANO_TIME; - } - - @Override - protected PrettyPrinter newCompactPrinter() { - return new MinimalPrettyPrinter(); - } - - @Override - protected ObjectMapper newObjectMapper() { - return new Log4jJsonObjectMapper(encodeThreadContextAsList, includeStacktrace, stacktraceAsString, objectMessageAsJsonObject); - } - - @Override - protected PrettyPrinter newPrettyPrinter() { - return new DefaultPrettyPrinter(); - } - - } - - static class XML extends JacksonFactory { - - static final int DEFAULT_INDENT = 1; - - private final boolean includeStacktrace; - private final boolean stacktraceAsString; - - - public XML(final boolean includeStacktrace, final boolean stacktraceAsString) { - this.includeStacktrace = includeStacktrace; - this.stacktraceAsString = stacktraceAsString; - } - - @Override - protected String getPropertNameForContextMap() { - return XmlConstants.ELT_CONTEXT_MAP; - } - - @Override - protected String getPropertNameForSource() { - return XmlConstants.ELT_SOURCE; - } - - @Override - protected String getPropertNameForNanoTime() { - return JsonConstants.ELT_NANO_TIME; - } - - @Override - protected PrettyPrinter newCompactPrinter() { - // Yes, null is the proper answer. - return null; - } - - @Override - protected ObjectMapper newObjectMapper() { - return new Log4jXmlObjectMapper(includeStacktrace, stacktraceAsString); - } - - @Override - protected PrettyPrinter newPrettyPrinter() { - return new Log4jXmlPrettyPrinter(DEFAULT_INDENT); - } - } - - static class YAML extends JacksonFactory { - - private final boolean includeStacktrace; - private final boolean stacktraceAsString; - - - public YAML(final boolean includeStacktrace, final boolean stacktraceAsString) { - this.includeStacktrace = includeStacktrace; - this.stacktraceAsString = stacktraceAsString; - } - - @Override - protected String getPropertNameForContextMap() { - return JsonConstants.ELT_CONTEXT_MAP; - } - - @Override - protected String getPropertNameForSource() { - return JsonConstants.ELT_SOURCE; - } - - @Override - protected String getPropertNameForNanoTime() { - return JsonConstants.ELT_NANO_TIME; - } - - @Override - protected PrettyPrinter newCompactPrinter() { - return new MinimalPrettyPrinter(); - } - - @Override - protected ObjectMapper newObjectMapper() { - return new Log4jYamlObjectMapper(false, includeStacktrace, stacktraceAsString); - } - - @Override - protected PrettyPrinter newPrettyPrinter() { - return new DefaultPrettyPrinter(); - } - } - - /** - * When <Event>s are written into a XML file; the "Event" object is not the root element, but an element named - * <Events> created using {@link XmlLayout#getHeader()} and {@link XmlLayout#getFooter()} methods. - *

- * {@link com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter} is used to print the Event object into - * XML; hence it assumes <Event> tag as the root element, so it prints the <Event> tag without any - * indentation. To add an indentation to the <Event> tag; hence an additional indentation for any - * sub-elements, this class is written. As an additional task, to avoid the blank line printed after the ending - * </Event> tag, {@link #writePrologLinefeed(XMLStreamWriter2)} method is also overridden. - *

- */ - static class Log4jXmlPrettyPrinter extends DefaultXmlPrettyPrinter { - - private static final long serialVersionUID = 1L; - - Log4jXmlPrettyPrinter(final int nesting) { - _nesting = nesting; - } - - @Override - public void writePrologLinefeed(final XMLStreamWriter2 sw) throws XMLStreamException { - // nothing - } - - /** - * Sets the nesting level to 1 rather than 0, so the "Event" tag will get indentation of next level below root. - */ - @Override - public DefaultXmlPrettyPrinter createInstance() { - return new Log4jXmlPrettyPrinter(XML.DEFAULT_INDENT); - } - - } - - abstract protected String getPropertNameForContextMap(); - - abstract protected String getPropertNameForSource(); - - abstract protected String getPropertNameForNanoTime(); - - abstract protected PrettyPrinter newCompactPrinter(); - - abstract protected ObjectMapper newObjectMapper(); - - abstract protected PrettyPrinter newPrettyPrinter(); - - ObjectWriter newWriter(final boolean locationInfo, final boolean properties, final boolean compact) { - final SimpleFilterProvider filters = new SimpleFilterProvider(); - final Set except = new HashSet<>(2); - if (!locationInfo) { - except.add(this.getPropertNameForSource()); - } - if (!properties) { - except.add(this.getPropertNameForContextMap()); - } - except.add(this.getPropertNameForNanoTime()); - filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except)); - final ObjectWriter writer = this.newObjectMapper().writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter()); - return writer.with(filters); - } - -} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java index c7643680610..8c36c1100e7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/AbstractJacksonLogEventParser.java @@ -24,10 +24,10 @@ import java.io.IOException; -class AbstractJacksonLogEventParser implements TextLogEventParser { +public class AbstractJacksonLogEventParser implements TextLogEventParser { private final ObjectReader objectReader; - AbstractJacksonLogEventParser(final ObjectMapper objectMapper) { + protected AbstractJacksonLogEventParser(final ObjectMapper objectMapper) { objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); this.objectReader = objectMapper.readerFor(Log4jLogEvent.class); } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java index 813a5b76464..ba09c99ea8b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/ThrowableProxyTest.java @@ -35,22 +35,22 @@ import java.util.HashMap; import java.util.Map; import java.util.Stack; + import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.spec.IvParameterSpec; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.config.plugins.convert.Base64Converter; -import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper; -import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper; import org.apache.logging.log4j.core.pattern.PlainTextRenderer; import org.apache.logging.log4j.util.Strings; import org.junit.Test; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; + /** * */ @@ -113,16 +113,6 @@ private void testIoContainer(final ObjectMapper objectMapper ) throws IOExceptio assertEquals(expected.proxy, actual.proxy); } - @Test - public void testIoContainerAsJson() throws IOException { - testIoContainer(new Log4jJsonObjectMapper()); - } - - @Test - public void testIoContainerAsXml() throws IOException { - testIoContainer(new Log4jXmlObjectMapper()); - } - /** * Attempts to instantiate a class that cannot initialize and then logs the stack trace of the Error. The logger * must not fail when using {@link ThrowableProxy} to inspect the frames of the stack trace. diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/LogEventFixtures.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/LogEventFixtures.java index 0bdaaca4cba..4e85eb751a9 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/LogEventFixtures.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/LogEventFixtures.java @@ -35,12 +35,12 @@ import org.apache.logging.log4j.spi.DefaultThreadContextStack; import org.apache.logging.log4j.util.StringMap; -class LogEventFixtures { +public class LogEventFixtures { /** * @return a log event that uses all the bells and whistles, features, nooks and crannies */ - static Log4jLogEvent createLogEvent() { + public static Log4jLogEvent createLogEvent() { final Marker cMarker = MarkerManager.getMarker("Marker1"); final Marker pMarker1 = MarkerManager.getMarker("ParentMarker1"); final Marker pMarker2 = MarkerManager.getMarker("ParentMarker2"); @@ -84,7 +84,7 @@ static Log4jLogEvent createLogEvent() { } @SuppressWarnings("deprecation") - static void assertEqualLogEvents(final LogEvent expected, final LogEvent actual, final boolean includeSource, + public static void assertEqualLogEvents(final LogEvent expected, final LogEvent actual, final boolean includeSource, final boolean includeContext, final boolean includeStacktrace) { assertEquals(expected.getClass(), actual.getClass()); assertEquals(includeContext ? expected.getContextData() : ContextDataFactory.createContextData(), actual.getContextData()); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/AbstractLogEventParserTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/core/parser/AbstractLogEventParserTest.java index cdb3bef3359..69c00c59a9b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/LogEventParserTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/AbstractLogEventParserTest.java @@ -27,7 +27,11 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; -public abstract class LogEventParserTest { +/** + * Subclassed by JSON, XML, and YAML modules. + */ +public abstract class AbstractLogEventParserTest { + protected void assertLogEvent(final LogEvent logEvent) { assertThat(logEvent, is(notNullValue())); assertThat(logEvent.getInstant().getEpochMillisecond(), equalTo(1493121664118L)); diff --git a/log4j-core/src/test/resources/log4j2-xml-layout.xml b/log4j-core/src/test/resources/log4j2-xml-layout.xml new file mode 100644 index 00000000000..c6355d0b702 --- /dev/null +++ b/log4j-core/src/test/resources/log4j2-xml-layout.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/log4j-layout-jackson-json/pom.xml b/log4j-layout-jackson-json/pom.xml new file mode 100644 index 00000000000..e7823384d77 --- /dev/null +++ b/log4j-layout-jackson-json/pom.xml @@ -0,0 +1,167 @@ + + + + + + org.apache.logging.log4j + log4j + 3.0.0-SNAPSHOT + + 4.0.0 + + log4j-layout-jackson-json + Apache Log4j Layout for Jackson JSON + + Apache Log4j Layout for Jackson JSON. + + + ${basedir}/.. + Log4j Layout for Jackson JSON Documentation + /log4j-layout-json + org.apache.logging.log4j.jackson.json + + + + + org.apache.logging.log4j + log4j-layout-jackson + ${project.version} + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + org.apache.logging.log4j + log4j-layout-jackson + test-jar + ${project.version} + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.jackson.json + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

]]>
+ + false + true +
+ + + non-aggregate + + javadoc + + + +
+ + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + +
+
+
diff --git a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java new file mode 100644 index 00000000000..e7c90a25fe9 --- /dev/null +++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/JsonSetupContextInitializer.java @@ -0,0 +1,51 @@ +package org.apache.logging.log4j.jackson.json; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.ExtendedStackTraceElementMixIn; +import org.apache.logging.log4j.jackson.InstantMixIn; +import org.apache.logging.log4j.jackson.LevelMixIn; +import org.apache.logging.log4j.jackson.LogEventJsonMixIn; +import org.apache.logging.log4j.jackson.MarkerMixIn; +import org.apache.logging.log4j.jackson.StackTraceElementMixIn; +import org.apache.logging.log4j.jackson.ThrowableProxyMixIn; +import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn; +import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn; + +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Used to set up {@link SetupContext} from different {@link SimpleModule}s. + *

+ * Differs from SetupContextInitializer by installing {@code LogEventJsonMixIn} for LogEvents, not + * {@code LogEventMixIn}, so it handles {@link ThreadContext} serialization differently. + *

+ *

+ * Consider this class private. + *

+ */ +public class JsonSetupContextInitializer { + + public void setupModule(final SetupContext context, final boolean includeStacktrace, + final boolean stacktraceAsString) { + // JRE classes: we cannot edit those with Jackson annotations + context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class); + // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not + // depend on Jackson. + context.setMixInAnnotations(Marker.class, MarkerMixIn.class); + context.setMixInAnnotations(Level.class, LevelMixIn.class); + context.setMixInAnnotations(Instant.class, InstantMixIn.class); + context.setMixInAnnotations(LogEvent.class, LogEventJsonMixIn.class); // different ThreadContext handling + // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. + context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class); + context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace + ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class) + : ThrowableProxyWithoutStacktraceMixIn.class); + } +} \ No newline at end of file diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/Log4jJsonModule.java similarity index 81% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java rename to log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/Log4jJsonModule.java index ceb53b46269..ab7741138e4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonModule.java +++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/Log4jJsonModule.java @@ -14,11 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.json; -import org.apache.logging.log4j.core.jackson.Initializers.SetupContextInitializer; -import org.apache.logging.log4j.core.jackson.Initializers.SetupContextJsonInitializer; -import org.apache.logging.log4j.core.jackson.Initializers.SimpleModuleInitializer; +import org.apache.logging.log4j.jackson.SetupContextInitializer; +import org.apache.logging.log4j.jackson.SimpleModuleInitializer; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.module.SimpleModule; @@ -34,15 +33,13 @@ class Log4jJsonModule extends SimpleModule { private final boolean encodeThreadContextAsList; private final boolean includeStacktrace; private final boolean stacktraceAsString; - private final boolean objectMessageAsJsonObject; Log4jJsonModule(final boolean encodeThreadContextAsList, final boolean includeStacktrace, final boolean stacktraceAsString, final boolean objectMessageAsJsonObject) { super(Log4jJsonModule.class.getName(), new Version(2, 0, 0, null, null, null)); this.encodeThreadContextAsList = encodeThreadContextAsList; this.includeStacktrace = includeStacktrace; this.stacktraceAsString = stacktraceAsString; - this.objectMessageAsJsonObject = objectMessageAsJsonObject; - // MUST init here. + // MUST initialize() here. // Calling this from setupModule is too late! //noinspection ThisEscapedInObjectConstruction new SimpleModuleInitializer().initialize(this, objectMessageAsJsonObject); @@ -55,7 +52,7 @@ public void setupModule(final SetupContext context) { if (encodeThreadContextAsList) { new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); } else { - new SetupContextJsonInitializer().setupModule(context, includeStacktrace, stacktraceAsString); + new JsonSetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/Log4jJsonObjectMapper.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java rename to log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/Log4jJsonObjectMapper.java index 4997c9135f8..f0df03b2b92 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jJsonObjectMapper.java +++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/Log4jJsonObjectMapper.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.json; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonJacksonFactory.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonJacksonFactory.java new file mode 100644 index 00000000000..dd7b789ef5d --- /dev/null +++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonJacksonFactory.java @@ -0,0 +1,60 @@ +package org.apache.logging.log4j.jackson.json.layout; + +import org.apache.logging.log4j.jackson.AbstractJacksonFactory; +import org.apache.logging.log4j.jackson.JsonConstants; +import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper; + +import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.core.util.MinimalPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +class JsonJacksonFactory extends AbstractJacksonFactory { + + private final boolean encodeThreadContextAsList; + private final boolean objectMessageAsJsonObject; + + public JsonJacksonFactory(final boolean encodeThreadContextAsList, final boolean includeStacktrace, + final boolean stacktraceAsString, final boolean objectMessageAsJsonObject) { + super(includeStacktrace, stacktraceAsString); + this.encodeThreadContextAsList = encodeThreadContextAsList; + this.objectMessageAsJsonObject = objectMessageAsJsonObject; + } + + @Override + protected String getPropertyNameForContextMap() { + return JsonConstants.ELT_CONTEXT_MAP; + } + + @Override + protected String getPropertyNameForNanoTime() { + return JsonConstants.ELT_NANO_TIME; + } + + @Override + protected String getPropertyNameForSource() { + return JsonConstants.ELT_SOURCE; + } + + @Override + protected String getPropertyNameForStackTrace() { + return JsonConstants.ELT_EXTENDED_STACK_TRACE; + } + + @Override + protected PrettyPrinter newCompactPrinter() { + return new MinimalPrettyPrinter(); + } + + @Override + protected ObjectMapper newObjectMapper() { + return new Log4jJsonObjectMapper(encodeThreadContextAsList, includeStacktrace, stacktraceAsString, + objectMessageAsJsonObject); + } + + @Override + protected PrettyPrinter newPrettyPrinter() { + return new DefaultPrettyPrinter(); + } + +} \ No newline at end of file diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java similarity index 88% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java rename to log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java index 607ec43baf7..224cfb4bacc 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/JsonLayout.java +++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/layout/JsonLayout.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.jackson.json.layout; import java.io.IOException; import java.io.Writer; @@ -32,7 +32,14 @@ import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.jackson.AbstractJacksonLayout; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonRootName; +import com.fasterxml.jackson.annotation.JsonUnwrapped; /** * Appends a series of JSON events as strings serialized as bytes. @@ -68,12 +75,6 @@ @Plugin(name = "JsonLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) public final class JsonLayout extends AbstractJacksonLayout { - private static final String DEFAULT_FOOTER = "]"; - - private static final String DEFAULT_HEADER = "["; - - static final String CONTENT_TYPE = "application/json"; - public static class Builder> extends AbstractJacksonLayout.Builder implements org.apache.logging.log4j.core.util.Builder { @@ -102,120 +103,71 @@ public JsonLayout build() { getAdditionalFields(), getObjectMessageAsJsonObject()); } - public boolean isPropertiesAsList() { - return propertiesAsList; - } - - public B setPropertiesAsList(final boolean propertiesAsList) { - this.propertiesAsList = propertiesAsList; - return asBuilder(); + @Override + public KeyValuePair[] getAdditionalFields() { + return additionalFields; } public boolean getObjectMessageAsJsonObject() { return objectMessageAsJsonObject; } - public B setObjectMessageAsJsonObject(final boolean objectMessageAsJsonObject) { - this.objectMessageAsJsonObject = objectMessageAsJsonObject; - return asBuilder(); + public boolean isPropertiesAsList() { + return propertiesAsList; } @Override - public KeyValuePair[] getAdditionalFields() { - return additionalFields; + public B setAdditionalFields(final KeyValuePair[] additionalFields) { + this.additionalFields = additionalFields; + return asBuilder(); } - @Override - public B setAdditionalFields(KeyValuePair[] additionalFields) { - this.additionalFields = additionalFields; + public B setObjectMessageAsJsonObject(final boolean objectMessageAsJsonObject) { + this.objectMessageAsJsonObject = objectMessageAsJsonObject; return asBuilder(); } - } - /** - * @deprecated Use {@link #newBuilder()} instead - */ - @Deprecated - protected JsonLayout(final Configuration config, final boolean locationInfo, final boolean properties, - final boolean encodeThreadContextAsList, - final boolean complete, final boolean compact, final boolean eventEol, final String headerPattern, - final String footerPattern, final Charset charset, final boolean includeStacktrace) { - super(config, new JacksonFactory.JSON(encodeThreadContextAsList, includeStacktrace, false, false).newWriter( - locationInfo, properties, compact), - charset, compact, complete, eventEol, - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(), - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(), - false, null); + public B setPropertiesAsList(final boolean propertiesAsList) { + this.propertiesAsList = propertiesAsList; + return asBuilder(); + } } - private JsonLayout(final Configuration config, final boolean locationInfo, final boolean properties, - final boolean encodeThreadContextAsList, - final boolean complete, final boolean compact, final boolean eventEol, - final String headerPattern, final String footerPattern, final Charset charset, - final boolean includeStacktrace, final boolean stacktraceAsString, - final boolean includeNullDelimiter, - final KeyValuePair[] additionalFields, final boolean objectMessageAsJsonObject) { - super(config, new JacksonFactory.JSON(encodeThreadContextAsList, includeStacktrace, stacktraceAsString, objectMessageAsJsonObject).newWriter( - locationInfo, properties, compact), - charset, compact, complete, eventEol, - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(), - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(), - includeNullDelimiter, - additionalFields); - } + @JsonRootName(XmlConstants.ELT_EVENT) + public static class JsonLogEventWithAdditionalFields extends LogEventWithAdditionalFields { - /** - * Returns appropriate JSON header. - * - * @return a byte array containing the header, opening the JSON array. - */ - @Override - public byte[] getHeader() { - if (!this.complete) { - return null; + public JsonLogEventWithAdditionalFields(final Object logEvent, final Map additionalFields) { + super(logEvent, additionalFields); } - final StringBuilder buf = new StringBuilder(); - final String str = serializeToString(getHeaderSerializer()); - if (str != null) { - buf.append(str); - } - buf.append(this.eol); - return getBytes(buf.toString()); - } - /** - * Returns appropriate JSON footer. - * - * @return a byte array containing the footer, closing the JSON array. - */ - @Override - public byte[] getFooter() { - if (!this.complete) { - return null; + @Override + @JsonAnyGetter + public Map getAdditionalFields() { + return super.getAdditionalFields(); } - final StringBuilder buf = new StringBuilder(); - buf.append(this.eol); - final String str = serializeToString(getFooterSerializer()); - if (str != null) { - buf.append(str); + + @Override + @JsonUnwrapped + public Object getLogEvent() { + return super.getLogEvent(); } - buf.append(this.eol); - return getBytes(buf.toString()); } - @Override - public Map getContentFormat() { - final Map result = new HashMap<>(); - result.put("version", "2.0"); - return result; - } + private static final String DEFAULT_FOOTER = "]"; + + private static final String DEFAULT_HEADER = "["; + + + static final String CONTENT_TYPE = "application/json"; /** - * @return The content type. + * Creates a JSON Layout using the default settings. Useful for testing. + * + * @return A JSON Layout. */ - @Override - public String getContentType() { - return CONTENT_TYPE + "; charset=" + this.getCharset(); + public static JsonLayout createDefaultLayout() { + return new JsonLayout(new DefaultConfiguration(), false, false, false, false, false, false, + DEFAULT_HEADER, DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, null, false); } /** @@ -274,13 +226,95 @@ public static > B newBuilder() { } /** - * Creates a JSON Layout using the default settings. Useful for testing. + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + protected JsonLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean encodeThreadContextAsList, + final boolean complete, final boolean compact, final boolean eventEol, final String headerPattern, + final String footerPattern, final Charset charset, final boolean includeStacktrace) { + super(config, new JsonJacksonFactory(encodeThreadContextAsList, includeStacktrace, false, false).newWriter( + locationInfo, properties, compact), + charset, compact, complete, eventEol, + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(), + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(), + false, null); + } + + private JsonLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean encodeThreadContextAsList, + final boolean complete, final boolean compact, final boolean eventEol, + final String headerPattern, final String footerPattern, final Charset charset, + final boolean includeStacktrace, final boolean stacktraceAsString, + final boolean includeNullDelimiter, + final KeyValuePair[] additionalFields, final boolean objectMessageAsJsonObject) { + super(config, new JsonJacksonFactory(encodeThreadContextAsList, includeStacktrace, stacktraceAsString, objectMessageAsJsonObject).newWriter( + locationInfo, properties, compact), + charset, compact, complete, eventEol, + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(), + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(), + includeNullDelimiter, + additionalFields); + } + + @Override + protected LogEventWithAdditionalFields createLogEventWithAdditionalFields(final LogEvent event, + final Map additionalFieldsMap) { + return new JsonLogEventWithAdditionalFields(event, additionalFieldsMap); + } + + @Override + public Map getContentFormat() { + final Map result = new HashMap<>(); + result.put("version", "2.0"); + return result; + } + + /** + * @return The content type. + */ + @Override + public String getContentType() { + return CONTENT_TYPE + "; charset=" + this.getCharset(); + } + + /** + * Returns appropriate JSON footer. * - * @return A JSON Layout. + * @return a byte array containing the footer, closing the JSON array. */ - public static JsonLayout createDefaultLayout() { - return new JsonLayout(new DefaultConfiguration(), false, false, false, false, false, false, - DEFAULT_HEADER, DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, null, false); + @Override + public byte[] getFooter() { + if (!this.complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + buf.append(this.eol); + final String str = serializeToString(getFooterSerializer()); + if (str != null) { + buf.append(str); + } + buf.append(this.eol); + return getBytes(buf.toString()); + } + + /** + * Returns appropriate JSON header. + * + * @return a byte array containing the header, opening the JSON array. + */ + @Override + public byte[] getHeader() { + if (!this.complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + final String str = serializeToString(getHeaderSerializer()); + if (str != null) { + buf.append(str); + } + buf.append(this.eol); + return getBytes(buf.toString()); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/JsonLogEventParser.java b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParser.java similarity index 78% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/parser/JsonLogEventParser.java rename to log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParser.java index 084ca4c09bb..28279d18433 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/JsonLogEventParser.java +++ b/log4j-layout-jackson-json/src/main/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParser.java @@ -14,13 +14,14 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.parser; +package org.apache.logging.log4j.jackson.json.parser; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper; +import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser; +import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper; /** - * Parses the output from JsonLayout layout into instances of {@link LogEvent}. + * Parses the output from XmlLayout layout into instances of {@link LogEvent}. */ public class JsonLogEventParser extends AbstractJacksonLogEventParser { diff --git a/log4j-layout-jackson-json/src/site/manual/index.md b/log4j-layout-jackson-json/src/site/manual/index.md new file mode 100644 index 00000000000..6cadb785073 --- /dev/null +++ b/log4j-layout-jackson-json/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j Layout for Jackson JSON module + +As of Log4j 3.0.0, the layout based on Jackson JSON has moved from the existing module logj-core to the new modules log4j-layout-jackson-json. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires Jackson. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-layout-jackson-json/src/site/site.xml b/log4j-layout-jackson-json/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-layout-jackson-json/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/JacksonIssue429MyNamesTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429MyNamesTest.java similarity index 99% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/JacksonIssue429MyNamesTest.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429MyNamesTest.java index 63c79198f9c..acc15c2ece4 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/JacksonIssue429MyNamesTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429MyNamesTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.json; import java.io.IOException; @@ -22,6 +22,7 @@ import org.apache.logging.log4j.util.Strings; import org.junit.Assert; import org.junit.Test; +import org.junit.experimental.categories.Category; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonParser; @@ -33,7 +34,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.junit.experimental.categories.Category; @Category(Layouts.Json.class) public class JacksonIssue429MyNamesTest { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/JacksonIssue429Test.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429Test.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/JacksonIssue429Test.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429Test.java index 6cbccc68fef..93d1d53c2af 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/JacksonIssue429Test.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/JacksonIssue429Test.java @@ -14,13 +14,14 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.json; import java.io.IOException; import org.apache.logging.log4j.categories.Layouts; import org.junit.Assert; import org.junit.Test; +import org.junit.experimental.categories.Category; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonParser; @@ -30,7 +31,6 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.junit.experimental.categories.Category; @Category(Layouts.Json.class) public class JacksonIssue429Test { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/LevelMixInJsonTest.java similarity index 91% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/LevelMixInJsonTest.java index 14b015bec74..7f75148e2aa 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInJsonTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/LevelMixInJsonTest.java @@ -15,12 +15,14 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.json; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.categories.Layouts; +import org.apache.logging.log4j.jackson.LevelMixInTest; import org.junit.experimental.categories.Category; +import com.fasterxml.jackson.databind.ObjectMapper; + @Category(Layouts.Json.class) public class LevelMixInJsonTest extends LevelMixInTest { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInJsonTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/MarkerMixInJsonTest.java similarity index 85% rename from log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInJsonTest.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/MarkerMixInJsonTest.java index 8777696585d..db9588b4a20 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInJsonTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/MarkerMixInJsonTest.java @@ -15,15 +15,16 @@ * limitations under the license. */ -package org.apache.logging.log4j; +package org.apache.logging.log4j.jackson.json; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.categories.Layouts; -import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper; +import org.apache.logging.log4j.jackson.AbstractMarkerMixInTest; import org.junit.experimental.categories.Category; +import com.fasterxml.jackson.databind.ObjectMapper; + @Category(Layouts.Json.class) -public class MarkerMixInJsonTest extends MarkerMixInTest { +public class MarkerMixInJsonTest extends AbstractMarkerMixInTest { @Override protected ObjectMapper newObjectMapper() { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java similarity index 91% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java index f14a26eec0f..fc0b4599abe 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixInTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/StackTraceElementJsonMixInTest.java @@ -14,32 +14,27 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.json; import java.io.IOException; import org.apache.logging.log4j.categories.Layouts; +import org.apache.logging.log4j.jackson.Log4jStackTraceElementDeserializer; import org.junit.Assert; import org.junit.Test; +import org.junit.experimental.categories.Category; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.junit.experimental.categories.Category; @Category(Layouts.Json.class) -public class StackTraceElementMixInTest { - - @Test - public void testLog4jJsonObjectMapper() throws Exception { - this.roundtrip(new Log4jJsonObjectMapper()); - } +public class StackTraceElementJsonMixInTest { - @Test - public void testLog4jYamlObjectMapper() throws Exception { - this.roundtrip(new Log4jYamlObjectMapper()); + protected String aposToQuotes(final String json) { + return json.replace("'", "\""); } /** @@ -57,18 +52,10 @@ private void roundtrip(final ObjectMapper mapper) throws JsonProcessingException } @Test - public void testLog4jXmlObjectMapper() throws Exception { - this.roundtrip(new Log4jXmlObjectMapper()); - } - - protected String aposToQuotes(final String json) { - return json.replace("'", "\""); - } - - @Test - public void testFromJsonWithSimpleModule() throws Exception { + public void testFromJsonWithLog4jModule() throws Exception { final ObjectMapper mapper = new ObjectMapper(); - final SimpleModule module = new SimpleModule(); + final boolean encodeThreadContextAsList = false; + final SimpleModule module = new Log4jJsonModule(encodeThreadContextAsList, true, false, false); module.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); mapper.registerModule(module); final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", 123); @@ -78,10 +65,9 @@ public void testFromJsonWithSimpleModule() throws Exception { } @Test - public void testFromJsonWithLog4jModule() throws Exception { + public void testFromJsonWithSimpleModule() throws Exception { final ObjectMapper mapper = new ObjectMapper(); - final boolean encodeThreadContextAsList = false; - final SimpleModule module = new Log4jJsonModule(encodeThreadContextAsList, true, false, false); + final SimpleModule module = new SimpleModule(); module.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); mapper.registerModule(module); final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", 123); @@ -89,4 +75,9 @@ public void testFromJsonWithLog4jModule() throws Exception { final StackTraceElement actual = mapper.readValue(s, StackTraceElement.class); Assert.assertEquals(expected, actual); } + + @Test + public void testLog4jJsonObjectMapper() throws Exception { + this.roundtrip(new Log4jJsonObjectMapper()); + } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ConcurrentLoggingWithJsonLayoutTest.java similarity index 95% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ConcurrentLoggingWithJsonLayoutTest.java index 0e4ad52ecc4..5d6f02d27f9 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/ConcurrentLoggingWithJsonLayoutTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ConcurrentLoggingWithJsonLayoutTest.java @@ -14,7 +14,11 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.jackson.json.layout; + +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertThat; import java.io.File; import java.nio.charset.Charset; @@ -31,18 +35,38 @@ import org.junit.ClassRule; import org.junit.Test; -import static org.hamcrest.CoreMatchers.*; - -import static org.junit.Assert.*; - /** * Test for LOG4J2-1769. * * @since 2.8 */ public class ConcurrentLoggingWithJsonLayoutTest { + + private class LoggingThread extends Thread { + private final Set threads; + private final Logger log; + + LoggingThread(final Set threads, final Logger log) { + this.threads = threads; + this.log = log; + } + + @Override + public void run() { + log.info(threads.size()); + try { + for (int i = 0; i < 64; i++) { + log.info("First message."); + log.info("Second message."); + } + } finally { + threads.remove(this); + } + } + } @ClassRule public static LoggerContextRule context = new LoggerContextRule("log4j2-json-layout.xml"); + private static final String PATH = "target/test-json-layout.log"; @AfterClass @@ -90,27 +114,4 @@ public void uncaughtException(final Thread t, final Throwable e) { } } } - - private class LoggingThread extends Thread { - private final Set threads; - private final Logger log; - - LoggingThread(final Set threads, final Logger log) { - this.threads = threads; - this.log = log; - } - - @Override - public void run() { - log.info(threads.size()); - try { - for (int i = 0; i < 64; i++) { - log.info("First message."); - log.info("Second message."); - } - } finally { - threads.remove(this); - } - } - } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java similarity index 96% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java index dba5cf36b77..f8afb51c674 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/JsonLayoutTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.jackson.json.layout; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -36,9 +36,11 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper; +import org.apache.logging.log4j.core.layout.LogEventFixtures; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.jackson.AbstractJacksonLayout; +import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper; import org.apache.logging.log4j.message.ObjectMessage; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.AbstractLogger; @@ -55,6 +57,18 @@ */ @Category(Layouts.Json.class) public class JsonLayoutTest { + private static class TestClass { + private int value; + + public int getValue() { + return value; + } + + public void setValue(final int value) { + this.value = value; + } + } + static ConfigurationFactory cf = new BasicConfigurationFactory(); private static final String DQUOTE = "\""; @@ -123,6 +137,58 @@ private void checkPropertyNameAbsent(final String name, final boolean compact, f assertFalse(str, str.contains(DQUOTE + name + DQUOTE + propSep)); } + private String prepareJsonForObjectMessageAsJsonObjectTests(final int value, final boolean objectMessageAsJsonObject) { + final TestClass testClass = new TestClass(); + testClass.setValue(value); + // @formatter:off + final Log4jLogEvent expected = Log4jLogEvent.newBuilder() + .setLoggerName("a.B") + .setLoggerFqcn("f.q.c.n") + .setLevel(Level.DEBUG) + .setMessage(new ObjectMessage(testClass)) + .setThreadName("threadName") + .setTimeMillis(1).build(); + // @formatter:off + final AbstractJacksonLayout layout = JsonLayout.newBuilder() + .setCompact(true) + .setObjectMessageAsJsonObject(objectMessageAsJsonObject) + .build(); + // @formatter:off + return layout.toSerializable(expected); + } + + private String prepareJsonForStacktraceTests(final boolean stacktraceAsString) { + final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + // @formatter:off + final AbstractJacksonLayout layout = JsonLayout.newBuilder() + .setCompact(true) + .setIncludeStacktrace(true) + .setStacktraceAsString(stacktraceAsString) + .build(); + // @formatter:off + return layout.toSerializable(expected); + } + + @Test + public void testAdditionalFields() throws Exception { + final AbstractJacksonLayout layout = JsonLayout.newBuilder() + .setLocationInfo(false) + .setProperties(false) + .setComplete(false) + .setCompact(true) + .setEventEol(false) + .setIncludeStacktrace(false) + .setAdditionalFields(new KeyValuePair[] { + new KeyValuePair("KEY1", "VALUE1"), + new KeyValuePair("KEY2", "${java:runtime}"), }) + .setCharset(StandardCharsets.UTF_8) + .setConfiguration(ctx.getConfiguration()) + .build(); + final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); + assertTrue(str, str.contains("\"KEY1\":\"VALUE1\"")); + assertTrue(str, str.contains("\"KEY2\":\"" + new JavaLookup().getRuntime() + "\"")); + } + private void testAllFeatures(final boolean locationInfo, final boolean compact, final boolean eventEol, final boolean includeContext, final boolean contextMapAslist, final boolean includeStacktrace) throws Exception { @@ -254,6 +320,31 @@ public void testEscapeLayout() throws Exception { } } + @Test + public void testExcludeStacktrace() throws Exception { + this.testAllFeatures(false, false, false, false, false, false); + } + + @Test + public void testIncludeNullDelimiterFalse() throws Exception { + final AbstractJacksonLayout layout = JsonLayout.newBuilder() + .setCompact(true) + .setIncludeNullDelimiter(false) + .build(); + final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); + assertFalse(str.endsWith("\0")); + } + + @Test + public void testIncludeNullDelimiterTrue() throws Exception { + final AbstractJacksonLayout layout = JsonLayout.newBuilder() + .setCompact(true) + .setIncludeNullDelimiter(true) + .build(); + final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); + assertTrue(str.endsWith("\0")); + } + /** * Test case for MDC conversion pattern. */ @@ -348,36 +439,11 @@ public void testLayoutLoggerName() throws Exception { assertEquals(expected, actual); } - @Test - public void testAdditionalFields() throws Exception { - final AbstractJacksonLayout layout = JsonLayout.newBuilder() - .setLocationInfo(false) - .setProperties(false) - .setComplete(false) - .setCompact(true) - .setEventEol(false) - .setIncludeStacktrace(false) - .setAdditionalFields(new KeyValuePair[] { - new KeyValuePair("KEY1", "VALUE1"), - new KeyValuePair("KEY2", "${java:runtime}"), }) - .setCharset(StandardCharsets.UTF_8) - .setConfiguration(ctx.getConfiguration()) - .build(); - final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); - assertTrue(str, str.contains("\"KEY1\":\"VALUE1\"")); - assertTrue(str, str.contains("\"KEY2\":\"" + new JavaLookup().getRuntime() + "\"")); - } - @Test public void testLocationOffCompactOffMdcOff() throws Exception { this.testAllFeatures(false, false, false, false, false, true); } - @Test - public void testLocationOnCompactOnMdcOn() throws Exception { - this.testAllFeatures(true, true, false, true, false, true); - } - @Test public void testLocationOnCompactOnEventEolOnMdcOn() throws Exception { this.testAllFeatures(true, true, true, true, false, true); @@ -389,99 +455,35 @@ public void testLocationOnCompactOnEventEolOnMdcOnMdcAsList() throws Exception { } @Test - public void testExcludeStacktrace() throws Exception { - this.testAllFeatures(false, false, false, false, false, false); - } - - @Test - public void testStacktraceAsString() throws Exception { - final String str = prepareJSONForStacktraceTests(true); - assertTrue(str, str.contains("\"extendedStackTrace\":\"java.lang.NullPointerException")); + public void testLocationOnCompactOnMdcOn() throws Exception { + this.testAllFeatures(true, true, false, true, false, true); } @Test - public void testStacktraceAsNonString() throws Exception { - final String str = prepareJSONForStacktraceTests(false); - assertTrue(str, str.contains("\"extendedStackTrace\":[")); + public void testObjectMessageAsJsonObject() { + final String str = prepareJsonForObjectMessageAsJsonObjectTests(1234, true); + assertTrue(str, str.contains("\"message\":{\"value\":1234}")); } - private String prepareJSONForStacktraceTests(final boolean stacktraceAsString) { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); - // @formatter:off - final AbstractJacksonLayout layout = JsonLayout.newBuilder() - .setCompact(true) - .setIncludeStacktrace(true) - .setStacktraceAsString(stacktraceAsString) - .build(); - // @formatter:off - return layout.toSerializable(expected); - } - @Test public void testObjectMessageAsJsonString() { - final String str = prepareJSONForObjectMessageAsJsonObjectTests(1234, false); + final String str = prepareJsonForObjectMessageAsJsonObjectTests(1234, false); assertTrue(str, str.contains("\"message\":\"" + this.getClass().getCanonicalName() + "$TestClass@")); } - - @Test - public void testObjectMessageAsJsonObject() { - final String str = prepareJSONForObjectMessageAsJsonObjectTests(1234, true); - assertTrue(str, str.contains("\"message\":{\"value\":1234}")); - } - - private String prepareJSONForObjectMessageAsJsonObjectTests(final int value, final boolean objectMessageAsJsonObject) { - final TestClass testClass = new TestClass(); - testClass.setValue(value); - // @formatter:off - final Log4jLogEvent expected = Log4jLogEvent.newBuilder() - .setLoggerName("a.B") - .setLoggerFqcn("f.q.c.n") - .setLevel(Level.DEBUG) - .setMessage(new ObjectMessage(testClass)) - .setThreadName("threadName") - .setTimeMillis(1).build(); - // @formatter:off - final AbstractJacksonLayout layout = JsonLayout.newBuilder() - .setCompact(true) - .setObjectMessageAsJsonObject(objectMessageAsJsonObject) - .build(); - // @formatter:off - return layout.toSerializable(expected); - } @Test - public void testIncludeNullDelimiterTrue() throws Exception { - final AbstractJacksonLayout layout = JsonLayout.newBuilder() - .setCompact(true) - .setIncludeNullDelimiter(true) - .build(); - final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); - assertTrue(str.endsWith("\0")); + public void testStacktraceAsNonString() throws Exception { + final String str = prepareJsonForStacktraceTests(false); + assertTrue(str, str.contains("\"extendedStackTrace\":[")); } @Test - public void testIncludeNullDelimiterFalse() throws Exception { - final AbstractJacksonLayout layout = JsonLayout.newBuilder() - .setCompact(true) - .setIncludeNullDelimiter(false) - .build(); - final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); - assertFalse(str.endsWith("\0")); + public void testStacktraceAsString() throws Exception { + final String str = prepareJsonForStacktraceTests(true); + assertTrue(str, str.contains("\"extendedStackTrace\":\"java.lang.NullPointerException")); } - - private String toPropertySeparator(final boolean compact) { + + private String toPropertySeparator(final boolean compact) { return compact ? ":" : " : "; } - - private static class TestClass { - private int value; - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - } } diff --git a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java new file mode 100644 index 00000000000..c5b03551347 --- /dev/null +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/ThrowableProxyJsonTest.java @@ -0,0 +1,33 @@ +/* + * 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.jackson.json.layout; + +import java.io.IOException; + +import org.apache.logging.log4j.jackson.ThrowableProxyJacksonTest; +import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper; +import org.junit.Test; + +public class ThrowableProxyJsonTest extends ThrowableProxyJacksonTest { + + @Test + public void testIoContainerAsJson() throws IOException { + testIoContainer(new Log4jJsonObjectMapper()); + } + +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParserTest.java similarity index 94% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java rename to log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParserTest.java index 9683d636f95..a6b3cc771a5 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/JsonLogEventParserTest.java +++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/parser/JsonLogEventParserTest.java @@ -14,17 +14,17 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.parser; +package org.apache.logging.log4j.jackson.json.parser; + +import java.nio.charset.StandardCharsets; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.parser.AbstractLogEventParserTest; +import org.apache.logging.log4j.core.parser.ParseException; import org.junit.Before; import org.junit.Test; -import java.nio.charset.StandardCharsets; - -public class JsonLogEventParserTest extends LogEventParserTest { - - private JsonLogEventParser parser; +public class JsonLogEventParserTest extends AbstractLogEventParserTest { private static final String JSON = "{\n" + " \"timeMillis\" : 1493121664118,\n" + @@ -73,11 +73,31 @@ public class JsonLogEventParserTest extends LogEventParserTest { " }\n" + "}"; + private JsonLogEventParser parser; + @Before public void setup() { parser = new JsonLogEventParser(); } + @Test + public void testByteArray() throws ParseException { + final LogEvent logEvent = parser.parseFrom(JSON.getBytes(StandardCharsets.UTF_8)); + assertLogEvent(logEvent); + } + + @Test + public void testByteArrayOffsetLength() throws ParseException { + final byte[] bytes = ("abc" + JSON + "def").getBytes(StandardCharsets.UTF_8); + final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6); + assertLogEvent(logEvent); + } + + @Test + public void testEmptyObject() throws ParseException { + parser.parseFrom("{}"); + } + @Test public void testString() throws ParseException { final LogEvent logEvent = parser.parseFrom(JSON); @@ -89,6 +109,11 @@ public void testStringEmpty() throws ParseException { parser.parseFrom(""); } + @Test + public void testStringIgnoreInvalidProperty() throws ParseException { + parser.parseFrom("{\"foo\":\"bar\"}"); + } + @Test(expected = ParseException.class) public void testStringInvalidJson() throws ParseException { parser.parseFrom("foobar"); @@ -99,32 +124,9 @@ public void testStringJsonArray() throws ParseException { parser.parseFrom("[]"); } - @Test - public void testEmptyObject() throws ParseException { - parser.parseFrom("{}"); - } - @Test(expected = ParseException.class) public void testStringWrongPropertyType() throws ParseException { parser.parseFrom("{\"threadId\":\"foobar\"}"); } - @Test - public void testStringIgnoreInvalidProperty() throws ParseException { - parser.parseFrom("{\"foo\":\"bar\"}"); - } - - @Test - public void testByteArray() throws ParseException { - final LogEvent logEvent = parser.parseFrom(JSON.getBytes(StandardCharsets.UTF_8)); - assertLogEvent(logEvent); - } - - @Test - public void testByteArrayOffsetLength() throws ParseException { - final byte[] bytes = ("abc" + JSON + "def").getBytes(StandardCharsets.UTF_8); - final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6); - assertLogEvent(logEvent); - } - } diff --git a/log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml b/log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml new file mode 100644 index 00000000000..c7af4e9561c --- /dev/null +++ b/log4j-layout-jackson-json/src/test/resources/log4j2-json-layout.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlModule.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java similarity index 84% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlModule.java rename to log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java index 34f0f6870e6..0980f9435d1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlModule.java +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java @@ -14,10 +14,9 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.xml; -import org.apache.logging.log4j.core.jackson.Initializers.SetupContextInitializer; -import org.apache.logging.log4j.core.jackson.Initializers.SimpleModuleInitializer; +import org.apache.logging.log4j.core.jackson.SimpleModuleInitializer; import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; @@ -45,6 +44,6 @@ final class Log4jXmlModule extends JacksonXmlModule { public void setupModule(final SetupContext context) { // Calling super is a MUST! super.setupModule(context); - new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); + new XmlSetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlObjectMapper.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlObjectMapper.java rename to log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java index b390a3f279d..632b83fe4cf 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlObjectMapper.java +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.xml; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java new file mode 100644 index 00000000000..0e18154709c --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlInstantMixIn.java @@ -0,0 +1,56 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.jackson.InstantMixIn; +import org.apache.logging.log4j.core.time.Instant; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Jackson mix-in for {@link Instant}. + *

+ * Consider this class private. + *

+ * + * @see Marker + */ +abstract class XmlInstantMixIn extends InstantMixIn { + + @JsonCreator + protected XmlInstantMixIn( + // @formatter:off + @JsonProperty(ATTR_EPOCH_SECOND) final long epochSecond, + @JsonProperty(ATTR_NANO_OF_SECOND) final int nanoOfSecond) + // @formatter:on + { + super(epochSecond, nanoOfSecond); + } + + @Override + @JacksonXmlProperty(localName = ATTR_EPOCH_SECOND, isAttribute = true) + protected abstract long getEpochSecond(); + + @Override + @JacksonXmlProperty(localName = ATTR_NANO_OF_SECOND, isAttribute = true) + protected abstract int getNanoOfSecond(); + +} diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java new file mode 100644 index 00000000000..771f955ec2b --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlLogEventWithContextListMixIn.java @@ -0,0 +1,50 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.core.jackson.AbstractXmlLogEventMixIn; +import org.apache.logging.log4j.core.jackson.ContextDataAsEntryListDeserializer; +import org.apache.logging.log4j.core.jackson.ContextDataAsEntryListSerializer; +import org.apache.logging.log4j.core.jackson.XmlConstants; +import org.apache.logging.log4j.util.ReadOnlyStringMap; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + *
+ * AbstractLogEventMixIn
+*├─ XmlLogEventMixIn
+*├──── XmlLogEventWithContextListMixIn
+*├──── XmlLogEventWithContextMapMixIn
+*├─ JsonLogEventMixIn
+*├──── JsonLogEventWithContextListMixIn
+*├──── JsonLogEventWithContextMapMixIn
+ * 
+ */ +public abstract class XmlLogEventWithContextListMixIn extends AbstractXmlLogEventMixIn { + + private static final long serialVersionUID = 1L; + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) + @JsonSerialize(using = ContextDataAsEntryListSerializer.class) + @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class) + @Override + public abstract ReadOnlyStringMap getContextData(); + +} diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java new file mode 100644 index 00000000000..9fa0e8a56ec --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java @@ -0,0 +1,79 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.jackson.MarkerMixIn; +import org.apache.logging.log4j.core.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Jackson mix-in for {@link Marker}. + *

+ * If we want to deal with more than one {@link Marker} implementation then recode these annotations to include + * metadata. + *

+ *

+ * Consider this class private. + *

+ *

+ * Example XML: + *

+ * + *
+<Marker name="Marker1">
+    <Parents>
+        <Marker name="ParentMarker1">
+            <Parents>
+                <Marker name="GrandMotherMarker"/>
+                <Marker name="GrandFatherMarker"/>
+            </Parents>
+        </Marker>
+        <Marker name="ParentMarker2"/>
+    </Parents>
+</Marker>
+ * 
+ * + * @see Marker + */ +// Alternate for multiple Marker implementation. +// @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") +@JsonDeserialize(as = org.apache.logging.log4j.MarkerManager.Log4jMarker.class) +abstract class XmlMarkerMixIn extends MarkerMixIn { + public static final String ATTR_NAME = "name"; + private static final long serialVersionUID = 1L; + + @JsonCreator + protected XmlMarkerMixIn(@JsonProperty(ATTR_NAME) final String name) { + super(name); + } + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getName(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_PARENTS) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) + public abstract Marker[] getParents(); + +} diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java new file mode 100644 index 00000000000..442f9abad02 --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java @@ -0,0 +1,42 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.jackson.ExtendedStackTraceElementMixIn; +import org.apache.logging.log4j.core.jackson.LevelMixIn; +import org.apache.logging.log4j.core.jackson.ThrowableProxyMixIn; +import org.apache.logging.log4j.core.jackson.ThrowableProxyWithStacktraceAsStringMixIn; +import org.apache.logging.log4j.core.jackson.ThrowableProxyWithoutStacktraceMixIn; +import org.apache.logging.log4j.core.time.Instant; + +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Used to set up {@link SetupContext} from different {@link SimpleModule}s. + *

+ * Consider this class private. + *

+ */ +class XmlSetupContextInitializer { + + public void setupModule(final SetupContext context, final boolean includeStacktrace, + final boolean stacktraceAsString) { + // JRE classes: we cannot edit those with Jackson annotations + context.setMixInAnnotations(StackTraceElement.class, XmlStackTraceElementMixIn.class); + // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not + // depend on Jackson. + context.setMixInAnnotations(Marker.class, XmlMarkerMixIn.class); + context.setMixInAnnotations(Level.class, LevelMixIn.class); + context.setMixInAnnotations(Instant.class, XmlInstantMixIn.class); + context.setMixInAnnotations(LogEvent.class, XmlLogEventWithContextListMixIn.class); + // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. + context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class); + context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace + ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class) + : ThrowableProxyWithoutStacktraceMixIn.class); + } +} \ No newline at end of file diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java new file mode 100644 index 00000000000..abdba98a8de --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java @@ -0,0 +1,39 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.core.jackson.StackTraceElementMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +abstract class XmlStackTraceElementMixIn extends StackTraceElementMixIn { + + @JsonCreator + protected XmlStackTraceElementMixIn( + // @formatter:off + @JsonProperty(ATTR_CLASS) final String declaringClass, + @JsonProperty(ATTR_METHOD) final String methodName, + @JsonProperty(ATTR_FILE) final String fileName, + @JsonProperty(ATTR_LINE) final int lineNumber) + // @formatter:on + { + super(declaringClass, methodName, fileName, lineNumber); + } + + @Override + @JacksonXmlProperty(localName = ATTR_CLASS, isAttribute = true) + protected abstract String getClassName(); + + @Override + @JacksonXmlProperty(localName = ATTR_FILE, isAttribute = true) + protected abstract String getFileName(); + + @Override + @JacksonXmlProperty(localName = ATTR_LINE, isAttribute = true) + protected abstract int getLineNumber(); + + @Override + @JacksonXmlProperty(localName = ATTR_METHOD, isAttribute = true) + protected abstract String getMethodName(); + +} diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java new file mode 100644 index 00000000000..24c5ef01c8f --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java @@ -0,0 +1,41 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import javax.xml.stream.XMLStreamException; + +import org.codehaus.stax2.XMLStreamWriter2; + +import com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter; + +/** + * When <Event>s are written into a XML file; the "Event" object is not the root element, but an element named + * <Events> created using {@link XmlLayout#getHeader()} and {@link XmlLayout#getFooter()} methods. + *

+ * {@link com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter} is used to print the Event object into + * XML; hence it assumes <Event> tag as the root element, so it prints the <Event> tag without any + * indentation. To add an indentation to the <Event> tag; hence an additional indentation for any + * sub-elements, this class is written. As an additional task, to avoid the blank line printed after the ending + * </Event> tag, {@link #writePrologLinefeed(XMLStreamWriter2)} method is also overridden. + *

+ */ +class Log4jXmlPrettyPrinter extends DefaultXmlPrettyPrinter { + + private static final long serialVersionUID = 1L; + + Log4jXmlPrettyPrinter(final int nesting) { + _nesting = nesting; + } + + /** + * Sets the nesting level to 1 rather than 0, so the "Event" tag will get indentation of next level below root. + */ + @Override + public DefaultXmlPrettyPrinter createInstance() { + return new Log4jXmlPrettyPrinter(XmlJacksonFactory.DEFAULT_INDENT); + } + + @Override + public void writePrologLinefeed(final XMLStreamWriter2 sw) throws XMLStreamException { + // nothing + } + +} \ No newline at end of file diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java new file mode 100644 index 00000000000..0289c7173cf --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java @@ -0,0 +1,54 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import org.apache.logging.log4j.core.jackson.AbstractJacksonFactory; +import org.apache.logging.log4j.core.jackson.JsonConstants; +import org.apache.logging.log4j.core.jackson.XmlConstants; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; + +import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +class XmlJacksonFactory extends AbstractJacksonFactory { + + static final int DEFAULT_INDENT = 1; + + public XmlJacksonFactory(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(includeStacktrace, stacktraceAsString); + } + + @Override + protected String getPropertyNameForContextMap() { + return XmlConstants.ELT_CONTEXT_MAP; + } + + @Override + protected String getPropertyNameForNanoTime() { + return JsonConstants.ELT_NANO_TIME; + } + + @Override + protected String getPropertyNameForSource() { + return XmlConstants.ELT_SOURCE; + } + + @Override + protected String getPropertyNameForStackTrace() { + return XmlConstants.ELT_EXTENDED_STACK_TRACE; + } + + @Override + protected PrettyPrinter newCompactPrinter() { + // Yes, null is the proper answer. + return null; + } + + @Override + protected ObjectMapper newObjectMapper() { + return new Log4jXmlObjectMapper(includeStacktrace, stacktraceAsString); + } + + @Override + protected PrettyPrinter newPrettyPrinter() { + return new Log4jXmlPrettyPrinter(DEFAULT_INDENT); + } +} \ No newline at end of file diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java similarity index 71% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java rename to log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java index b09add7a59f..c305c33e317 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/XmlLayout.java +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.jackson.xml.layout; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -22,13 +22,17 @@ import java.util.Map; import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Node; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.jackson.AbstractJacksonLayout; import org.apache.logging.log4j.core.jackson.XmlConstants; import org.apache.logging.log4j.core.util.KeyValuePair; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + /** * Appends a series of {@code event} elements as defined in the log4j.dtd. * @@ -55,17 +59,15 @@ *

Additional Fields

*

* This property allows addition of custom fields into generated JSON. - * {@code } inserts {@code bar} directly - * into XML output. Supports Lookup expressions. + * {@code } inserts {@code bar} directly into XML + * output. Supports Lookup expressions. *

*/ @Plugin(name = "XmlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) public final class XmlLayout extends AbstractJacksonLayout { - private static final String ROOT_TAG = "Events"; - public static class Builder> extends AbstractJacksonLayout.Builder - implements org.apache.logging.log4j.core.util.Builder { + implements org.apache.logging.log4j.core.util.Builder { public Builder() { super(); @@ -74,70 +76,86 @@ public Builder() { @Override public XmlLayout build() { - return new XmlLayout(getConfiguration(), isLocationInfo(), isProperties(), isComplete(), - isCompact(), getCharset(), isIncludeStacktrace(), isStacktraceAsString(), - isIncludeNullDelimiter(), getAdditionalFields()); + return new XmlLayout(getConfiguration(), isLocationInfo(), isProperties(), isComplete(), isCompact(), + getCharset(), isIncludeStacktrace(), isStacktraceAsString(), isIncludeNullDelimiter(), + getAdditionalFields()); + } + } + + @JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) + public static class XmlLogEventWithAdditionalFields extends LogEventWithAdditionalFields { + + public XmlLogEventWithAdditionalFields(final Object logEvent, final Map additionalFields) { + super(logEvent, additionalFields); } + } + private static final String ROOT_TAG = "Events"; + /** + * Creates an XML Layout using the default settings. + * + * @return an XML Layout. + */ + public static XmlLayout createDefaultLayout() { + return new XmlLayout(null, false, false, false, false, StandardCharsets.UTF_8, true, false, false, null); + } + + /** + * Creates an XML Layout. + * + * @param locationInfo + * If "true", includes the location information in the generated XML. + * @param properties + * If "true", includes the thread context map in the generated XML. + * @param complete + * If "true", includes the XML header and footer, defaults to "false". + * @param compact + * If "true", does not use end-of-lines and indentation, defaults to "false". + * @param charset + * The character set to use, if {@code null}, uses "UTF-8". + * @param includeStacktrace + * If "true", includes the stacktrace of any Throwable in the generated XML, defaults to "true". + * @return An XML Layout. + * * @deprecated Use {@link #newBuilder()} instead */ @Deprecated - protected XmlLayout(final boolean locationInfo, final boolean properties, final boolean complete, - final boolean compact, final Charset charset, final boolean includeStacktrace) { - this(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, false, null); + public static XmlLayout createLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + return new XmlLayout(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, + false, null); } - private XmlLayout(final Configuration config, final boolean locationInfo, final boolean properties, - final boolean complete, final boolean compact, final Charset charset, - final boolean includeStacktrace, final boolean stacktraceAsString, - final boolean includeNullDelimiter, - final KeyValuePair[] additionalFields) { - super(config, new JacksonFactory.XML(includeStacktrace, stacktraceAsString).newWriter( - locationInfo, properties, compact), - charset, compact, complete, false, null, null, includeNullDelimiter, - additionalFields); + @PluginBuilderFactory + public static > B newBuilder() { + return new Builder().asBuilder(); } /** - * Returns appropriate XML headers. - *
    - *
  1. XML processing instruction
  2. - *
  3. XML root element
  4. - *
- * - * @return a byte array containing the header. + * @deprecated Use {@link #newBuilder()} instead */ - @Override - public byte[] getHeader() { - if (!complete) { - return null; - } - final StringBuilder buf = new StringBuilder(); - buf.append(""); - buf.append(this.eol); - // Make the log4j namespace the default namespace, no need to use more space with a namespace prefix. - buf.append('<'); - buf.append(ROOT_TAG); - buf.append(" xmlns=\"" + XmlConstants.XML_NAMESPACE + "\">"); - buf.append(this.eol); - return buf.toString().getBytes(this.getCharset()); + @Deprecated + protected XmlLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + this(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, false, null); + } + + private XmlLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean complete, final boolean compact, final Charset charset, final boolean includeStacktrace, + final boolean stacktraceAsString, final boolean includeNullDelimiter, + final KeyValuePair[] additionalFields) { + super(config, + new XmlJacksonFactory(includeStacktrace, stacktraceAsString).newWriter(locationInfo, properties, + compact), + charset, compact, complete, false, null, null, includeNullDelimiter, additionalFields); } - /** - * Returns appropriate XML footer. - * - * @return a byte array containing the footer, closing the XML root element. - */ @Override - public byte[] getFooter() { - if (!complete) { - return null; - } - return getBytes("' + this.eol); + protected LogEventWithAdditionalFields createLogEventWithAdditionalFields(final LogEvent event, + final Map additionalFieldsMap) { + return new XmlLogEventWithAdditionalFields(event, additionalFieldsMap); } /** @@ -146,7 +164,7 @@ public byte[] getFooter() { *
  • Key: "dtd" Value: "log4j-events.dtd"
  • *
  • Key: "version" Value: "2.0"
  • * - * + * * @return Map of content format keys supporting XmlLayout */ @Override @@ -167,42 +185,42 @@ public String getContentType() { } /** - * Creates an XML Layout. - * - * @param locationInfo If "true", includes the location information in the generated XML. - * @param properties If "true", includes the thread context map in the generated XML. - * @param complete If "true", includes the XML header and footer, defaults to "false". - * @param compact If "true", does not use end-of-lines and indentation, defaults to "false". - * @param charset The character set to use, if {@code null}, uses "UTF-8". - * @param includeStacktrace - * If "true", includes the stacktrace of any Throwable in the generated XML, defaults to "true". - * @return An XML Layout. + * Returns appropriate XML footer. * - * @deprecated Use {@link #newBuilder()} instead + * @return a byte array containing the footer, closing the XML root element. */ - @Deprecated - public static XmlLayout createLayout( - final boolean locationInfo, - final boolean properties, - final boolean complete, - final boolean compact, - final Charset charset, - final boolean includeStacktrace) { - return new XmlLayout(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, - false, null); - } - - @PluginBuilderFactory - public static > B newBuilder() { - return new Builder().asBuilder(); + @Override + public byte[] getFooter() { + if (!complete) { + return null; + } + return getBytes("' + this.eol); } /** - * Creates an XML Layout using the default settings. + * Returns appropriate XML headers. + *
      + *
    1. XML processing instruction
    2. + *
    3. XML root element
    4. + *
    * - * @return an XML Layout. + * @return a byte array containing the header. */ - public static XmlLayout createDefaultLayout() { - return new XmlLayout(null, false, false, false, false, StandardCharsets.UTF_8, true, false, false, null); + @Override + public byte[] getHeader() { + if (!complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + buf.append(""); + buf.append(this.eol); + // Make the log4j namespace the default namespace, no need to use more space with a namespace prefix. + buf.append('<'); + buf.append(ROOT_TAG); + buf.append(" xmlns=\"" + XmlConstants.XML_NAMESPACE + "\">"); + buf.append(this.eol); + return buf.toString().getBytes(this.getCharset()); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/XmlLogEventParser.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java similarity index 84% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/parser/XmlLogEventParser.java rename to log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java index e5b5a3a992d..32776a2f862 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/XmlLogEventParser.java +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java @@ -14,10 +14,11 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.parser; +package org.apache.logging.log4j.jackson.xml.parser; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper; +import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; /** * Parses the output from XmlLayout layout into instances of {@link LogEvent}. diff --git a/log4j-layout-jackson-xml/pom.xml b/log4j-layout-jackson-xml/pom.xml new file mode 100644 index 00000000000..4a8989db5fe --- /dev/null +++ b/log4j-layout-jackson-xml/pom.xml @@ -0,0 +1,171 @@ + + + + + + org.apache.logging.log4j + log4j + 3.0.0-SNAPSHOT + + 4.0.0 + + log4j-layout-jackson-xml + Apache Log4j Layout for Jackson XML + + Apache Log4j Layout for Jackson XML. + + + ${basedir}/.. + Log4j Layout for Jackson XML Documentation + /log4j-layout-xml + org.apache.logging.log4j.jackson.xml + + + + + org.apache.logging.log4j + log4j-layout-jackson + ${project.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + org.apache.logging.log4j + log4j-layout-jackson + test-jar + ${project.version} + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.jackson.xml + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
    + Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

    ]]>
    + + false + true +
    + + + non-aggregate + + javadoc + + + +
    + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + +
    +
    +
    diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java new file mode 100644 index 00000000000..9d8687d6829 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java @@ -0,0 +1,135 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext.ContextStack; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.AbstractLogEventMixIn; +import org.apache.logging.log4j.jackson.ContextDataAsEntryListDeserializer; +import org.apache.logging.log4j.jackson.Log4jStackTraceElementDeserializer; +import org.apache.logging.log4j.jackson.MessageSerializer; +import org.apache.logging.log4j.jackson.SimpleMessageDeserializer; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; + +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** +*
    AbstractLogEventMixIn
    +*├─ XmlLogEventMixIn
    +*├──── XmlLogEventWithContextListMixIn
    +*├──── XmlLogEventWithContextMapMixIn
    +*├─ JsonLogEventMixIn
    +*├──── JsonLogEventWithContextListMixIn
    +*├──── JsonLogEventWithContextMapMixIn
    +*/ +@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) +@JsonFilter(AbstractLogEventMixIn.JSON_FILTER_ID) +@JsonPropertyOrder({ + // @formatter:off + AbstractLogEventMixIn.ATTR_THREAD, + AbstractLogEventMixIn.ATTR_LEVEL, + AbstractLogEventMixIn.ATTR_LOGGER_NAME, + AbstractLogEventMixIn.ATTR_LOGGER_FQCN, + AbstractLogEventMixIn.ATTR_END_OF_BATCH, + XmlConstants.ELT_INSTANT, + XmlConstants.ELT_MARKER, + XmlConstants.ELT_MESSAGE, + AbstractLogEventXmlMixIn.ELT_THROWN, + XmlConstants.ELT_CONTEXT_MAP, + XmlConstants.ELT_CONTEXT_STACK, + XmlConstants.ELT_SOURCE}) + // @formatter:on +public abstract class AbstractLogEventXmlMixIn extends AbstractLogEventMixIn { + + public static final String ELT_THROWN = "Thrown"; + + private static final long serialVersionUID = 1L; + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) + @JsonSerialize(using = ContextDataAsEntryListXmlSerializer.class) + @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class) + @Override + public abstract ReadOnlyStringMap getContextData(); + + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK_ITEM) + @Override + public abstract ContextStack getContextStack(); + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_INSTANT) + @Override + public abstract Instant getInstant(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract Level getLevel(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract String getLoggerFqcn(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract String getLoggerName(); + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) + @Override + public abstract Marker getMarker(); + + @JsonSerialize(using = MessageSerializer.class) + @JsonDeserialize(using = SimpleMessageDeserializer.class) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MESSAGE) + @Override + public abstract Message getMessage(); + + @JsonDeserialize(using = Log4jStackTraceElementDeserializer.class) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SOURCE) + @Override + public abstract StackTraceElement getSource(); + + @Override + @JacksonXmlProperty(isAttribute = true, localName = ATTR_THREAD_ID) + public abstract long getThreadId(); + + @Override + @JacksonXmlProperty(isAttribute = true, localName = ATTR_THREAD) + public abstract String getThreadName(); + + @Override + @JacksonXmlProperty(isAttribute = true, localName = ATTR_THREAD_PRIORITY) + public abstract int getThreadPriority(); + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_THROWN) + @Override + public abstract ThrowableProxy getThrownProxy(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract boolean isEndOfBatch(); + +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java new file mode 100644 index 00000000000..b916c44e2a5 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java @@ -0,0 +1,37 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.ContextDataAsEntryListSerializer; +import org.apache.logging.log4j.jackson.MapEntry; + +public class ContextDataAsEntryListXmlSerializer extends ContextDataAsEntryListSerializer { + + private static final long serialVersionUID = 1L; + + @Override + protected MapEntry createMapEntry(final String key, final String value) { + return new XmlMapEntry(key, value); + } + + @Override + protected MapEntry[] createMapEntryArray(final int size) { + return new XmlMapEntry[size]; + } + +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java new file mode 100644 index 00000000000..224ef40e4b2 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java @@ -0,0 +1,68 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.core.impl.ExtendedClassInfo; +import org.apache.logging.log4j.jackson.ExtendedStackTraceElementMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public abstract class ExtendedStackTraceElementXmlMixIn extends ExtendedStackTraceElementMixIn { + + private static final long serialVersionUID = 1L; + + @JsonCreator + public ExtendedStackTraceElementXmlMixIn( + // @formatter:off + @JsonProperty(ATTR_CLASS) final String declaringClass, + @JsonProperty(ATTR_METHOD) final String methodName, + @JsonProperty(ATTR_FILE) final String fileName, + @JsonProperty(ATTR_LINE) final int lineNumber, + @JsonProperty(ATTR_EXACT) final boolean exact, + @JsonProperty(ATTR_LOCATION) final String location, + @JsonProperty(ATTR_VERSION) final String version + // @formatter:on + ) { + super(declaringClass, methodName, fileName, lineNumber, exact, location, version); + } + + @Override + @JacksonXmlProperty(localName = ATTR_CLASS, isAttribute = true) + public abstract String getClassName(); + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract boolean getExact(); + + @Override + @JsonIgnore + public abstract ExtendedClassInfo getExtraClassInfo(); + + @Override + @JacksonXmlProperty(localName = ATTR_FILE, isAttribute = true) + public abstract String getFileName(); + + @Override + @JacksonXmlProperty(localName = ATTR_LINE, isAttribute = true) + public abstract int getLineNumber(); + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getLocation(); + + @Override + @JacksonXmlProperty(localName = ATTR_METHOD, isAttribute = true) + public abstract String getMethodName(); + + @JsonIgnore + abstract StackTraceElement getStackTraceElement(); + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getVersion(); + + @Override + @JsonIgnore + public abstract boolean isNativeMethod(); +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java new file mode 100644 index 00000000000..df5a5cee7ae --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java @@ -0,0 +1,56 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.InstantMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Jackson mix-in for {@link Instant}. + *

    + * Consider this class private. + *

    + * + * @see Marker + */ +abstract class InstantXmlMixIn extends InstantMixIn { + + @JsonCreator + protected InstantXmlMixIn( + // @formatter:off + @JsonProperty(ATTR_EPOCH_SECOND) final long epochSecond, + @JsonProperty(ATTR_NANO_OF_SECOND) final int nanoOfSecond) + // @formatter:on + { + super(epochSecond, nanoOfSecond); + } + + @Override + @JacksonXmlProperty(localName = ATTR_EPOCH_SECOND, isAttribute = true) + public abstract long getEpochSecond(); + + @Override + @JacksonXmlProperty(localName = ATTR_NANO_OF_SECOND, isAttribute = true) + public abstract int getNanoOfSecond(); + +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java new file mode 100644 index 00000000000..76166b07f83 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java @@ -0,0 +1,52 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.SimpleModuleInitializer; + +import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; + +/** + *

    + * Consider this class private. + *

    + *

    + * Extends Jackson's {@link JacksonXmlModule} for Log4j XML's specific needs. + *

    + */ +final class Log4jXmlModule extends JacksonXmlModule { + + private static final long serialVersionUID = 1L; + private final boolean includeStacktrace; + private final boolean stacktraceAsString; + + Log4jXmlModule(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(); + this.includeStacktrace = includeStacktrace; + this.stacktraceAsString = stacktraceAsString; + // MUST init here. + // Calling this from setupModule is too late! + new SimpleModuleInitializer().initialize(this, false); + } + + @Override + public void setupModule(final SetupContext context) { + // Calling super is a MUST! + super.setupModule(context); + new XmlSetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); + } +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java new file mode 100644 index 00000000000..ec802f46050 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java @@ -0,0 +1,48 @@ +/* + * 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.jackson.xml; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +/** + * A Jackson XML {@link ObjectMapper} initialized for Log4j. + *

    + * Consider this class private. + *

    + */ +public class Log4jXmlObjectMapper extends XmlMapper { + + private static final long serialVersionUID = 1L; + + /** + * Create a new instance using the {@code Log4jXmlModule}. + */ + public Log4jXmlObjectMapper() { + this(true, false); + } + + /** + * Create a new instance using the {@code Log4jXmlModule}. + */ + public Log4jXmlObjectMapper(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(new Log4jXmlModule(includeStacktrace, stacktraceAsString)); + this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + } + +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java new file mode 100644 index 00000000000..04f1d3d5820 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java @@ -0,0 +1,48 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.ContextDataAsEntryListDeserializer; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.util.ReadOnlyStringMap; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + *
    + * AbstractLogEventMixIn
    +*├─ AbstractLogEventXmlMixIn
    +*├──── LogEventWithContextListXmlMixIn
    +*├──── LogEventWithContextMapXmlMixIn
    +*├─ JsonLogEventMixIn
    +*├──── JsonLogEventWithContextListMixIn
    +*├──── JsonLogEventWithContextMapMixIn
    + * 
    + */ +public abstract class LogEventWithContextListXmlMixIn extends AbstractLogEventXmlMixIn { + + private static final long serialVersionUID = 1L; + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) + @JsonSerialize(using = ContextDataAsEntryListXmlSerializer.class) + @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class) + @Override + public abstract ReadOnlyStringMap getContextData(); + +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java new file mode 100644 index 00000000000..a101ed567ae --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java @@ -0,0 +1,79 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.jackson.MarkerMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Jackson mix-in for {@link Marker}. + *

    + * If we want to deal with more than one {@link Marker} implementation then recode these annotations to include + * metadata. + *

    + *

    + * Consider this class private. + *

    + *

    + * Example XML: + *

    + * + *
    +<Marker name="Marker1">
    +    <Parents>
    +        <Marker name="ParentMarker1">
    +            <Parents>
    +                <Marker name="GrandMotherMarker"/>
    +                <Marker name="GrandFatherMarker"/>
    +            </Parents>
    +        </Marker>
    +        <Marker name="ParentMarker2"/>
    +    </Parents>
    +</Marker>
    + * 
    + * + * @see Marker + */ +// Alternate for multiple Marker implementation. +// @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") +@JsonDeserialize(as = org.apache.logging.log4j.MarkerManager.Log4jMarker.class) +abstract class MarkerXmlMixIn extends MarkerMixIn { + public static final String ATTR_NAME = "name"; + private static final long serialVersionUID = 1L; + + @JsonCreator + protected MarkerXmlMixIn(@JsonProperty(ATTR_NAME) final String name) { + super(name); + } + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getName(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_PARENTS) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) + public abstract Marker[] getParents(); + +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java new file mode 100644 index 00000000000..93a3a45676c --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java @@ -0,0 +1,40 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.jackson.StackTraceElementConstants; +import org.apache.logging.log4j.jackson.StackTraceElementMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +abstract class StackTraceElementXmlMixIn extends StackTraceElementMixIn { + + @JsonCreator + protected StackTraceElementXmlMixIn( + // @formatter:off + @JsonProperty(StackTraceElementConstants.ATTR_CLASS) final String declaringClass, + @JsonProperty(StackTraceElementConstants.ATTR_METHOD) final String methodName, + @JsonProperty(StackTraceElementConstants.ATTR_FILE) final String fileName, + @JsonProperty(StackTraceElementConstants.ATTR_LINE) final int lineNumber) + // @formatter:on + { + super(declaringClass, methodName, fileName, lineNumber); + } + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_CLASS, isAttribute = true) + protected abstract String getClassName(); + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_FILE, isAttribute = true) + protected abstract String getFileName(); + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_LINE, isAttribute = true) + protected abstract int getLineNumber(); + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_METHOD, isAttribute = true) + protected abstract String getMethodName(); + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java similarity index 84% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java rename to log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java index f169d35082d..9cc85c349f4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java @@ -14,64 +14,63 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; + +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; -import org.apache.logging.log4j.core.impl.ThrowableProxy; -/** - * Mix-in for {@link org.apache.logging.log4j.core.impl.ThrowableProxy}. - */ -abstract class ThrowableProxyWithStacktraceAsStringMixIn { +public abstract class ThrowableProxyWithStacktraceAsStringXmlMixIn extends ThrowableProxyWithStacktraceAsStringMixIn { - @JsonProperty(JsonConstants.ELT_CAUSE) @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE) private ThrowableProxyWithStacktraceAsStringMixIn causeProxy; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private int commonElementCount; @JsonIgnore private ExtendedStackTraceElement[] extendedStackTrace; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private String localizedMessage; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private String message; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private String name; @JsonIgnore private transient Throwable throwable; + @Override @JsonIgnore public abstract String getCauseStackTraceAsString(); - @JsonProperty(JsonConstants.ELT_EXTENDED_STACK_TRACE) + @Override @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE) public abstract String getExtendedStackTraceAsString(); + @Override @JsonIgnore public abstract StackTraceElement[] getStackTrace(); - @JsonProperty(JsonConstants.ELT_SUPPRESSED) + @Override @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED) @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM) public abstract ThrowableProxy[] getSuppressedProxies(); + @Override @JsonIgnore public abstract String getSuppressedStackTrace(); + @Override @JsonIgnore public abstract Throwable getThrowable(); diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java new file mode 100644 index 00000000000..4ecffae243e --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java @@ -0,0 +1,60 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public abstract class ThrowableProxyWithoutStacktraceXmlMixIn extends ThrowableProxyWithoutStacktraceMixIn { + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE) + private ThrowableProxyWithoutStacktraceMixIn causeProxy; + + @JacksonXmlProperty(isAttribute = true) + private int commonElementCount; + + @JsonIgnore + private ExtendedStackTraceElement[] extendedStackTrace; + + @JacksonXmlProperty(isAttribute = true) + private String localizedMessage; + + @JacksonXmlProperty(isAttribute = true) + private String message; + + @JacksonXmlProperty(isAttribute = true) + private String name; + + @JsonIgnore + private transient Throwable throwable; + + @Override + @JsonIgnore + public abstract String getCauseStackTraceAsString(); + + @Override + @JsonIgnore + public abstract String getExtendedStackTraceAsString(); + + @Override + @JsonIgnore + public abstract StackTraceElement[] getStackTrace(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM) + public abstract ThrowableProxy[] getSuppressedProxies(); + + @Override + @JsonIgnore + public abstract String getSuppressedStackTrace(); + + @Override + @JsonIgnore + public abstract Throwable getThrowable(); + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java similarity index 86% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java rename to log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java index a36c1b41858..b52f7f6be1c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyMixIn.java +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java @@ -14,66 +14,64 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; + +package org.apache.logging.log4j.jackson.xml; import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.jackson.ThrowableProxyMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -/** - * Mix-in for {@link ThrowableProxy}. - */ -abstract class ThrowableProxyMixIn { +public abstract class ThrowableProxyXmlMixIn extends ThrowableProxyMixIn { - @JsonProperty(JsonConstants.ELT_CAUSE) @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE) private ThrowableProxyMixIn causeProxy; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private int commonElementCount; - @JsonProperty(JsonConstants.ELT_EXTENDED_STACK_TRACE) @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE) @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE_ITEM) private ExtendedStackTraceElement[] extendedStackTrace; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private String localizedMessage; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private String message; - @JsonProperty @JacksonXmlProperty(isAttribute = true) private String name; @JsonIgnore private transient Throwable throwable; + @Override @JsonIgnore public abstract String getCauseStackTraceAsString(); + @Override @JsonIgnore public abstract String getExtendedStackTraceAsString(); + @Override @JsonIgnore public abstract StackTraceElement[] getStackTrace(); - @JsonProperty(JsonConstants.ELT_SUPPRESSED) + @Override @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED) @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM) public abstract ThrowableProxy[] getSuppressedProxies(); + @Override @JsonIgnore public abstract String getSuppressedStackTrace(); + @Override @JsonIgnore public abstract Throwable getThrowable(); diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java new file mode 100644 index 00000000000..2500c11aa21 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java @@ -0,0 +1,41 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.MapEntry; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +@JsonPropertyOrder({ "key", "value" }) +class XmlMapEntry extends MapEntry { + + @JacksonXmlProperty(isAttribute = true) + private String key; + + @JacksonXmlProperty(isAttribute = true) + private String value; + + @JsonCreator + public XmlMapEntry(@JsonProperty("key") final String key, @JsonProperty("value") final String value) { + super(key, value); + } + +} \ No newline at end of file diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java new file mode 100644 index 00000000000..4cc5124d922 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java @@ -0,0 +1,38 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.LevelMixIn; + +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Used to set up {@link SetupContext} from different {@link SimpleModule}s. + *

    + * Consider this class private. + *

    + */ +class XmlSetupContextInitializer { + + public void setupModule(final SetupContext context, final boolean includeStacktrace, + final boolean stacktraceAsString) { + // JRE classes: we cannot edit those with Jackson annotations + context.setMixInAnnotations(StackTraceElement.class, StackTraceElementXmlMixIn.class); + // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not + // depend on Jackson. + context.setMixInAnnotations(Marker.class, MarkerXmlMixIn.class); + context.setMixInAnnotations(Level.class, LevelMixIn.class); + context.setMixInAnnotations(Instant.class, InstantXmlMixIn.class); + context.setMixInAnnotations(LogEvent.class, LogEventWithContextListXmlMixIn.class); + // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. + context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementXmlMixIn.class); + context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace + ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringXmlMixIn.class : ThrowableProxyXmlMixIn.class) + : ThrowableProxyWithoutStacktraceXmlMixIn.class); + } +} \ No newline at end of file diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java new file mode 100644 index 00000000000..69568614bf9 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java @@ -0,0 +1,41 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import javax.xml.stream.XMLStreamException; + +import org.codehaus.stax2.XMLStreamWriter2; + +import com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter; + +/** + * When <Event>s are written into a XML file; the "Event" object is not the root element, but an element named + * <Events> created using {@link XmlLayout#getHeader()} and {@link XmlLayout#getFooter()} methods. + *

    + * {@link com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter} is used to print the Event object into + * XML; hence it assumes <Event> tag as the root element, so it prints the <Event> tag without any + * indentation. To add an indentation to the <Event> tag; hence an additional indentation for any + * sub-elements, this class is written. As an additional task, to avoid the blank line printed after the ending + * </Event> tag, the {@code #writePrologLinefeed(XMLStreamWriter2)} method is also overridden. + *

    + */ +class Log4jXmlPrettyPrinter extends DefaultXmlPrettyPrinter { + + private static final long serialVersionUID = 1L; + + Log4jXmlPrettyPrinter(final int nesting) { + _nesting = nesting; + } + + /** + * Sets the nesting level to 1 rather than 0, so the "Event" tag will get indentation of next level below root. + */ + @Override + public DefaultXmlPrettyPrinter createInstance() { + return new Log4jXmlPrettyPrinter(XmlJacksonFactory.DEFAULT_INDENT); + } + + @Override + public void writePrologLinefeed(final XMLStreamWriter2 sw) throws XMLStreamException { + // nothing + } + +} \ No newline at end of file diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java new file mode 100644 index 00000000000..0cfba5bf92a --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java @@ -0,0 +1,54 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import org.apache.logging.log4j.jackson.AbstractJacksonFactory; +import org.apache.logging.log4j.jackson.JsonConstants; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; + +import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +class XmlJacksonFactory extends AbstractJacksonFactory { + + static final int DEFAULT_INDENT = 1; + + public XmlJacksonFactory(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(includeStacktrace, stacktraceAsString); + } + + @Override + protected String getPropertyNameForContextMap() { + return XmlConstants.ELT_CONTEXT_MAP; + } + + @Override + protected String getPropertyNameForNanoTime() { + return JsonConstants.ELT_NANO_TIME; + } + + @Override + protected String getPropertyNameForSource() { + return XmlConstants.ELT_SOURCE; + } + + @Override + protected String getPropertyNameForStackTrace() { + return XmlConstants.ELT_EXTENDED_STACK_TRACE; + } + + @Override + protected PrettyPrinter newCompactPrinter() { + // Yes, null is the proper answer. + return null; + } + + @Override + protected ObjectMapper newObjectMapper() { + return new Log4jXmlObjectMapper(includeStacktrace, stacktraceAsString); + } + + @Override + protected PrettyPrinter newPrettyPrinter() { + return new Log4jXmlPrettyPrinter(DEFAULT_INDENT); + } +} \ No newline at end of file diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java new file mode 100644 index 00000000000..6d723b0dfd2 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java @@ -0,0 +1,226 @@ +/* + * 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.jackson.xml.layout; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.jackson.AbstractJacksonLayout; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Appends a series of {@code event} elements as defined in the log4j.dtd. + * + *

    Complete well-formed XML vs. fragment XML

    + *

    + * If you configure {@code complete="true"}, the appender outputs a well-formed XML document where the default namespace + * is the log4j namespace {@value XmlConstants#XML_NAMESPACE}. By default, with {@code complete="false"}, you should + * include the output as an external entity in a separate file to form a well-formed XML document. + *

    + *

    + * If {@code complete="false"}, the appender does not write the XML processing instruction and the root element. + *

    + *

    Encoding

    + *

    + * Appenders using this layout should have their {@code charset} set to {@code UTF-8} or {@code UTF-16}, otherwise + * events containing non-ASCII characters could result in corrupted log files. + *

    + *

    Pretty vs. compact XML

    + *

    + * By default, the XML layout is not compact (compact = not "pretty") with {@code compact="false"}, which means the + * appender uses end-of-line characters and indents lines to format the XML. If {@code compact="true"}, then no + * end-of-line or indentation is used. Message content may contain, of course, end-of-lines. + *

    + *

    Additional Fields

    + *

    + * This property allows addition of custom fields into generated JSON. + * {@code } inserts {@code bar} directly into XML + * output. Supports Lookup expressions. + *

    + */ +@Plugin(name = "XmlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) +public final class XmlLayout extends AbstractJacksonLayout { + + public static class Builder> extends AbstractJacksonLayout.Builder + implements org.apache.logging.log4j.core.util.Builder { + + public Builder() { + super(); + setCharset(StandardCharsets.UTF_8); + } + + @Override + public XmlLayout build() { + return new XmlLayout(getConfiguration(), isLocationInfo(), isProperties(), isComplete(), isCompact(), + getCharset(), isIncludeStacktrace(), isStacktraceAsString(), isIncludeNullDelimiter(), + getAdditionalFields()); + } + } + + @JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) + public static class XmlLogEventWithAdditionalFields extends LogEventWithAdditionalFields { + + public XmlLogEventWithAdditionalFields(final Object logEvent, final Map additionalFields) { + super(logEvent, additionalFields); + } + + } + + private static final String ROOT_TAG = "Events"; + + /** + * Creates an XML Layout using the default settings. + * + * @return an XML Layout. + */ + public static XmlLayout createDefaultLayout() { + return new XmlLayout(null, false, false, false, false, StandardCharsets.UTF_8, true, false, false, null); + } + + /** + * Creates an XML Layout. + * + * @param locationInfo + * If "true", includes the location information in the generated XML. + * @param properties + * If "true", includes the thread context map in the generated XML. + * @param complete + * If "true", includes the XML header and footer, defaults to "false". + * @param compact + * If "true", does not use end-of-lines and indentation, defaults to "false". + * @param charset + * The character set to use, if {@code null}, uses "UTF-8". + * @param includeStacktrace + * If "true", includes the stacktrace of any Throwable in the generated XML, defaults to "true". + * @return An XML Layout. + * + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + public static XmlLayout createLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + return new XmlLayout(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, + false, null); + } + + @PluginBuilderFactory + public static > B newBuilder() { + return new Builder().asBuilder(); + } + + /** + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + protected XmlLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + this(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, false, null); + } + + private XmlLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean complete, final boolean compact, final Charset charset, final boolean includeStacktrace, + final boolean stacktraceAsString, final boolean includeNullDelimiter, + final KeyValuePair[] additionalFields) { + super(config, + new XmlJacksonFactory(includeStacktrace, stacktraceAsString).newWriter(locationInfo, properties, + compact), + charset, compact, complete, false, null, null, includeNullDelimiter, additionalFields); + } + + @Override + protected LogEventWithAdditionalFields createLogEventWithAdditionalFields(final LogEvent event, + final Map additionalFieldsMap) { + return new XmlLogEventWithAdditionalFields(event, additionalFieldsMap); + } + + /** + * Gets this XmlLayout's content format. Specified by: + *
      + *
    • Key: "dtd" Value: "log4j-events.dtd"
    • + *
    • Key: "version" Value: "2.0"
    • + *
    + * + * @return Map of content format keys supporting XmlLayout + */ + @Override + public Map getContentFormat() { + final Map result = new HashMap<>(); + // result.put("dtd", "log4j-events.dtd"); + result.put("xsd", "log4j-events.xsd"); + result.put("version", "2.0"); + return result; + } + + /** + * @return The content type. + */ + @Override + public String getContentType() { + return "text/xml; charset=" + this.getCharset(); + } + + /** + * Returns appropriate XML footer. + * + * @return a byte array containing the footer, closing the XML root element. + */ + @Override + public byte[] getFooter() { + if (!complete) { + return null; + } + return getBytes("' + this.eol); + } + + /** + * Returns appropriate XML headers. + *
      + *
    1. XML processing instruction
    2. + *
    3. XML root element
    4. + *
    + * + * @return a byte array containing the header. + */ + @Override + public byte[] getHeader() { + if (!complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + buf.append(""); + buf.append(this.eol); + // Make the log4j namespace the default namespace, no need to use more space with a namespace prefix. + buf.append('<'); + buf.append(ROOT_TAG); + buf.append(" xmlns=\"" + XmlConstants.XML_NAMESPACE + "\">"); + buf.append(this.eol); + return buf.toString().getBytes(this.getCharset()); + } +} diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java new file mode 100644 index 00000000000..32776a2f862 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java @@ -0,0 +1,32 @@ +/* + * 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.jackson.xml.parser; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; + +/** + * Parses the output from XmlLayout layout into instances of {@link LogEvent}. + */ +public class XmlLogEventParser extends AbstractJacksonLogEventParser { + + public XmlLogEventParser() { + super(new Log4jXmlObjectMapper()); + } + +} diff --git a/log4j-layout-jackson-xml/src/site/manual/index.md b/log4j-layout-jackson-xml/src/site/manual/index.md new file mode 100644 index 00000000000..216fe056881 --- /dev/null +++ b/log4j-layout-jackson-xml/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j Layout for Jackson XML module + +As of Log4j 3.0.0, the layout based on Jackson XML has moved from the existing module logj-core to the new modules log4j-layout-jackson-xml. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires Jackson. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-layout-jackson-xml/src/site/site.xml b/log4j-layout-jackson-xml/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-layout-jackson-xml/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInXmlTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/LevelMixInXmlTest.java similarity index 92% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInXmlTest.java rename to log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/LevelMixInXmlTest.java index 3332d1a66f3..36e85326bb5 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInXmlTest.java +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/LevelMixInXmlTest.java @@ -15,13 +15,14 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.xml; import org.apache.logging.log4j.categories.Layouts; +import org.apache.logging.log4j.jackson.LevelMixInTest; import org.junit.Ignore; +import org.junit.experimental.categories.Category; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.experimental.categories.Category; @Ignore("Fails for #testNameOnly()") @Category(Layouts.Xml.class) diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInXmlTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/MarkerMixInXmlTest.java similarity index 86% rename from log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInXmlTest.java rename to log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/MarkerMixInXmlTest.java index 963d3f6d068..b909453ac89 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInXmlTest.java +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/MarkerMixInXmlTest.java @@ -15,16 +15,16 @@ * limitations under the license. */ -package org.apache.logging.log4j; +package org.apache.logging.log4j.jackson.xml; import org.apache.logging.log4j.categories.Layouts; -import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper; +import org.apache.logging.log4j.jackson.AbstractMarkerMixInTest; +import org.junit.experimental.categories.Category; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.experimental.categories.Category; @Category(Layouts.Xml.class) -public class MarkerMixInXmlTest extends MarkerMixInTest { +public class MarkerMixInXmlTest extends AbstractMarkerMixInTest { @Override protected ObjectMapper newObjectMapper() { diff --git a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java new file mode 100644 index 00000000000..1d45672d64c --- /dev/null +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixInTest.java @@ -0,0 +1,82 @@ +/* + * 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.jackson.xml; + +import java.io.IOException; + +import org.apache.logging.log4j.categories.Layouts; +import org.apache.logging.log4j.jackson.Log4jStackTraceElementDeserializer; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +@Category(Layouts.Json.class) +public class StackTraceElementXmlMixInTest { + + protected String aposToQuotes(final String json) { + return json.replace("'", "\""); + } + + private void roundtrip(final ObjectMapper mapper) + throws JsonProcessingException, IOException, JsonParseException, JsonMappingException { + final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", + 123); + final String s = mapper.writeValueAsString(expected); + final StackTraceElement actual = mapper.readValue(s, StackTraceElement.class); + Assert.assertEquals(expected, actual); + } + + @Test + public void testFromJsonWithLog4jModule() throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + final boolean encodeThreadContextAsList = false; + final Log4jXmlModule module = new Log4jXmlModule(true, false); + module.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); + mapper.registerModule(module); + final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", + 123); + final String s = this + .aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':123}"); + final StackTraceElement actual = mapper.readValue(s, StackTraceElement.class); + Assert.assertEquals(expected, actual); + } + + @Test + public void testFromJsonWithSimpleModule() throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + final SimpleModule module = new SimpleModule(); + module.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); + mapper.registerModule(module); + final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", + 123); + final String s = this + .aposToQuotes("{'class':'package.SomeClass','method':'someMethod','file':'SomeClass.java','line':123}"); + final StackTraceElement actual = mapper.readValue(s, StackTraceElement.class); + Assert.assertEquals(expected, actual); + } + + @Test + public void testLog4jXmlObjectMapper() throws Exception { + this.roundtrip(new Log4jXmlObjectMapper()); + } +} diff --git a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java new file mode 100644 index 00000000000..afbff8a9464 --- /dev/null +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ConcurrentLoggingWithXmlLayoutTest.java @@ -0,0 +1,116 @@ +/* + * 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.jackson.xml.layout; + +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertThat; + +import java.io.File; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.AfterClass; +import org.junit.ClassRule; +import org.junit.Test; + +/** + * Like the test for LOG4J2-1769. + */ +public class ConcurrentLoggingWithXmlLayoutTest { + + private class LoggingThread extends Thread { + private final Set threads; + private final Logger log; + + LoggingThread(final Set threads, final Logger log) { + this.threads = threads; + this.log = log; + } + + @Override + public void run() { + log.info(threads.size()); + try { + for (int i = 0; i < 64; i++) { + log.info("First message."); + log.info("Second message."); + } + } finally { + threads.remove(this); + } + } + } + + @ClassRule + public static LoggerContextRule context = new LoggerContextRule("log4j2-xml-layout.xml"); + + private static final String PATH = "target/test-xml-layout.log"; + + @AfterClass + public static void after() { + new File(PATH).delete(); + } + + @Test + public void testConcurrentLogging() throws Throwable { + final Logger log = context.getLogger(ConcurrentLoggingWithXmlLayoutTest.class); + final Set threads = Collections.synchronizedSet(new HashSet()); + final List thrown = Collections.synchronizedList(new ArrayList()); + + for (int x = 0; x < Runtime.getRuntime().availableProcessors() * 2; x++) { + final Thread t = new LoggingThread(threads, log); + threads.add(t); + + // Appender is configured with ignoreExceptions="false"; + // any exceptions are propagated to the caller, so we can catch them here. + t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(final Thread t, final Throwable e) { + thrown.add(e); + } + }); + t.start(); + } + + while (!threads.isEmpty()) { + log.info("not done going to sleep..."); + Thread.sleep(10); + } + + // if any error occurred, fail this test + if (!thrown.isEmpty()) { + throw thrown.get(0); + } + + // simple test to ensure content is not corrupted + if (new File(PATH).exists()) { + final List lines = Files.readAllLines(new File(PATH).toPath(), Charset.defaultCharset()); + for (final String line : lines) { + assertThat(line, startsWith("")); + } + } + } +} diff --git a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java new file mode 100644 index 00000000000..7fb917721c4 --- /dev/null +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/ThrowableProxyXmlTest.java @@ -0,0 +1,33 @@ +/* + * 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.jackson.xml.layout; + +import java.io.IOException; + +import org.apache.logging.log4j.jackson.ThrowableProxyJacksonTest; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; +import org.junit.Test; + +public class ThrowableProxyXmlTest extends ThrowableProxyJacksonTest { + + @Test + public void testIoContainerAsXml() throws IOException { + testIoContainer(new Log4jXmlObjectMapper()); + } + +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java similarity index 67% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java rename to log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java index 4ee8f1eac65..532316352de 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/XmlLayoutTest.java +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java @@ -14,7 +14,12 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.jackson.xml.layout; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -32,9 +37,13 @@ import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper; +import org.apache.logging.log4j.core.layout.LogEventFixtures; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.jackson.AbstractJacksonLayout; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.jackson.xml.AbstractLogEventXmlMixIn; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; import org.apache.logging.log4j.junit.ThreadContextRule; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.AbstractLogger; @@ -44,25 +53,22 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; +import org.junit.experimental.categories.Category; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; -import org.junit.experimental.categories.Category; - -import static org.junit.Assert.*; /** * Tests {@link XmlLayout}. */ @Category(Layouts.Xml.class) public class XmlLayoutTest { + private static final int NOT_FOUND = -1; private static final String body = "empty mdc"; static ConfigurationFactory cf = new BasicConfigurationFactory(); private static final String markerTag = ""; - @Rule - public final ThreadContextRule threadContextRule = new ThreadContextRule(); - @AfterClass public static void cleanupClass() { ConfigurationFactory.removeConfigurationFactory(cf); @@ -75,6 +81,9 @@ public static void setupClass() { ctx.reconfigure(); } + @Rule + public final ThreadContextRule threadContextRule = new ThreadContextRule(); + LoggerContext ctx = LoggerContext.getContext(); Logger rootLogger = this.ctx.getRootLogger(); @@ -97,18 +106,23 @@ private void checkContains(final String expected, final List list) { Assert.fail("Cannot find " + expected + " in " + list); } - private void checkElement(final String key, final String value, final boolean compact, final String str) { + private void checkContextMapElement(final String key, final String value, final boolean compact, final String str) { // assertTrue(str, str.contains(String.format("", key, value))); } - private void checkElementName(final String name, final boolean compact, final String str, final boolean withAttributes, - final boolean withChildren) { + private void checkContextStackElement(final String value, final boolean compact, final String str) { + // stack_msg1 + assertTrue(str, str.contains(String.format("%s", value))); + } + + private void checkElementName(final String name, final boolean compact, final String str, + final boolean withAttributes, final boolean withChildren) { // simple checks, don't try to be too smart here, we're just looking for the names and basic shape. // start final String startStr = withAttributes ? "<" + name + " " : "<" + name + ">"; final int startPos = str.indexOf(startStr); - Assert.assertTrue(str, startPos >= 0); + Assert.assertTrue(String.format("Missing text '%s' in: %s", startStr, str), startPos >= 0); // end final String endStr = withChildren ? "" : "/>"; final int endPos = str.indexOf(endStr, startPos + startStr.length()); @@ -119,35 +133,111 @@ private void checkElementNameAbsent(final String name, final boolean compact, fi Assert.assertFalse(str.contains("<" + name)); } + private void checkJsonPropertyOrder(final boolean includeContextStack, final boolean includeContextMap, + final boolean includeStacktrace, final String str) { + final JsonPropertyOrder annotation = AbstractLogEventXmlMixIn.class.getAnnotation(JsonPropertyOrder.class); + Assert.assertNotNull(annotation); + int previousIndex = 0; + String previousName = null; + for (final String name : annotation.value()) { + final int currentIndex = str.indexOf(name); + if (!includeContextStack && XmlConstants.ELT_CONTEXT_STACK.equals(name)) { + Assert.assertTrue(String.format("Unexpected element '%s' in: %s", name, str), + currentIndex == NOT_FOUND); + break; + } + if (!includeContextMap && XmlConstants.ELT_CONTEXT_MAP.equals(name)) { + Assert.assertTrue(String.format("Unexpected element '%s' in: %s", name, str), + currentIndex == NOT_FOUND); + break; + } + if (!includeStacktrace && XmlConstants.ELT_EXTENDED_STACK_TRACE.equals(name)) { + Assert.assertTrue(String.format("Unexpected element '%s' in: %s", name, str), + currentIndex == NOT_FOUND); + break; + } + if (!includeStacktrace && XmlConstants.ELT_EXTENDED_STACK_TRACE_ITEM.equals(name)) { + Assert.assertTrue(String.format("Unexpected element '%s' in: %s", name, str), + currentIndex == NOT_FOUND); + break; + } + // TODO + // Bug: The method + // com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._sortProperties(Map) messes up the order defined in AbstractXmlLogEventMixIn's JsonPropertyOrder + // annotations. + // Assert.assertTrue(String.format("name='%s', previousIndex=%,d, previousName='%s', currentIndex=%,d: %s", + // name, previousIndex, previousName, currentIndex, str), previousIndex < currentIndex); + previousIndex = currentIndex; + previousName = name; + } + } + + private String prepareXMLForStacktraceTests(final boolean stacktraceAsString) { + final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + // @formatter:off + final AbstractJacksonLayout layout = XmlLayout.newBuilder() + .setCompact(true) + .setIncludeStacktrace(true) + .setStacktraceAsString(stacktraceAsString) + .build(); + // @formatter:off + return layout.toSerializable(expected); + } + + @Test + public void testAdditionalFields() throws Exception { + final AbstractJacksonLayout layout = XmlLayout.newBuilder().setLocationInfo(false).setProperties(false) + .setIncludeStacktrace(false) + .setAdditionalFields(new KeyValuePair[] { new KeyValuePair("KEY1", "VALUE1"), + new KeyValuePair("KEY2", "${java:runtime}"), }) + .setCharset(StandardCharsets.UTF_8).setConfiguration(ctx.getConfiguration()).build(); + final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); + assertTrue(str, str.contains("VALUE1")); + assertTrue(str, str.contains("" + new JavaLookup().getRuntime() + "")); + } + /** - * @param includeSource TODO + * @param includeLocationInfo + * TODO * @param compact - * @param includeContext TODO + * @param includeContextMap + * TODO + * @param includeContextStack + * TODO * @throws IOException * @throws JsonParseException * @throws JsonMappingException */ - private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean includeContext, final boolean includeStacktrace) throws IOException, - JsonParseException, JsonMappingException { + private void testAllFeatures(final boolean includeLocationInfo, final boolean compact, + final boolean includeContextMap, final boolean includeContextStack, final boolean includeStacktrace) + throws IOException, JsonParseException, JsonMappingException { final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + // @formatter:off final XmlLayout layout = XmlLayout.newBuilder() - .setLocationInfo(includeSource) - .setProperties(includeContext) + .setLocationInfo(includeLocationInfo) + .setProperties(includeContextMap) .setComplete(false) .setCompact(compact) .setIncludeStacktrace(includeStacktrace) .setCharset(StandardCharsets.UTF_8) .build(); final String str = layout.toSerializable(expected); + // @formatter:on // System.out.println(str); assertEquals(str, !compact, str.contains("\n")); - assertEquals(str, includeSource, str.contains("Source")); - assertEquals(str, includeContext, str.contains("ContextMap")); + assertEquals(str, includeLocationInfo, str.contains("Source")); + assertEquals(str, includeContextMap, str.contains("ContextMap")); final Log4jLogEvent actual = new Log4jXmlObjectMapper().readValue(str, Log4jLogEvent.class); - LogEventFixtures.assertEqualLogEvents(expected, actual, includeSource, includeContext, includeStacktrace); - if (includeContext) { - this.checkElement("MDC.A", "A_Value", compact, str); - this.checkElement("MDC.B", "B_Value", compact, str); + LogEventFixtures.assertEqualLogEvents(expected, actual, includeLocationInfo, includeContextMap, + includeStacktrace); + if (includeContextMap) { + this.checkContextMapElement("MDC.A", "A_Value", compact, str); + this.checkContextMapElement("MDC.B", "B_Value", compact, str); + } + if (includeContextStack) { + this.checkContextStackElement("stack_msg1", compact, str); + this.checkContextStackElement("stack_msg2", compact, str); } // @@ -158,14 +248,14 @@ private void testAllFeatures(final boolean includeSource, final boolean compact, // make sure short names are used assertTrue(str, str.contains("VALUE1")); - assertTrue(str, str.contains("" + new JavaLookup().getRuntime() + "")); - } - @Test public void testLocationOffCompactOffMdcOff() throws Exception { - this.testAllFeatures(false, false, false, true); + this.testAllFeatures(false, false, false, false, true); } @Test public void testLocationOnCompactOnMdcOn() throws Exception { - this.testAllFeatures(true, true, true, true); - } - - @Test - public void testExcludeStacktrace() throws Exception { - this.testAllFeatures(false, false, false, false); + this.testAllFeatures(true, true, true, true, true); } @Test - public void testStacktraceAsString() throws Exception { - final String str = prepareXMLForStacktraceTests(true); - assertTrue(str, str.contains("java.lang.NullPointerException")); + public void testLocationOnCompactOnNdcOn() throws Exception { + this.testAllFeatures(false, false, false, true, false); } @Test @@ -353,35 +432,9 @@ public void testStacktraceAsNonString() throws Exception { assertTrue(str, str.contains("java.lang.NullPointerException")); } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParserTest.java similarity index 94% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java rename to log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParserTest.java index 72da8ff34f5..93e30b5a80d 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/XmlLogEventParserTest.java +++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParserTest.java @@ -14,17 +14,17 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.parser; +package org.apache.logging.log4j.jackson.xml.parser; + +import java.nio.charset.StandardCharsets; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.parser.AbstractLogEventParserTest; +import org.apache.logging.log4j.core.parser.ParseException; import org.junit.Before; import org.junit.Test; -import java.nio.charset.StandardCharsets; - -public class XmlLogEventParserTest extends LogEventParserTest { - - private XmlLogEventParser parser; +public class XmlLogEventParserTest extends AbstractLogEventParserTest { private static final String XML = "\n" + ""; + private XmlLogEventParser parser; + @Before public void setup() { parser = new XmlLogEventParser(); } + @Test + public void testByteArray() throws ParseException { + final LogEvent logEvent = parser.parseFrom(XML.getBytes(StandardCharsets.UTF_8)); + assertLogEvent(logEvent); + } + + @Test + public void testByteArrayOffsetLength() throws ParseException { + final byte[] bytes = ("abc" + XML + "def").getBytes(StandardCharsets.UTF_8); + final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6); + assertLogEvent(logEvent); + } + + @Test + public void testEmptyObject() throws ParseException { + parser.parseFrom(""); + } + @Test public void testString() throws ParseException { final LogEvent logEvent = parser.parseFrom(XML); @@ -89,16 +109,16 @@ public void testStringEmpty() throws ParseException { parser.parseFrom(""); } + @Test + public void testStringIgnoreInvalidProperty() throws ParseException { + parser.parseFrom("bar"); + } + @Test(expected = ParseException.class) public void testStringInvalidXml() throws ParseException { parser.parseFrom("foobar"); } - @Test - public void testEmptyObject() throws ParseException { - parser.parseFrom(""); - } - @Test(expected = ParseException.class) public void testStringWrongPropertyType() throws ParseException { parser.parseFrom("foobar"); @@ -109,22 +129,4 @@ public void testTimeMillisIgnored() throws ParseException { parser.parseFrom("foobar"); } - @Test - public void testStringIgnoreInvalidProperty() throws ParseException { - parser.parseFrom("bar"); - } - - @Test - public void testByteArray() throws ParseException { - final LogEvent logEvent = parser.parseFrom(XML.getBytes(StandardCharsets.UTF_8)); - assertLogEvent(logEvent); - } - - @Test - public void testByteArrayOffsetLength() throws ParseException { - final byte[] bytes = ("abc" + XML + "def").getBytes(StandardCharsets.UTF_8); - final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6); - assertLogEvent(logEvent); - } - } diff --git a/log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml b/log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml new file mode 100644 index 00000000000..f0b17095ad9 --- /dev/null +++ b/log4j-layout-jackson-xml/src/test/resources/log4j2-xml-layout.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/log4j-layout-jackson-yaml/pom.xml b/log4j-layout-jackson-yaml/pom.xml new file mode 100644 index 00000000000..9df9743c49d --- /dev/null +++ b/log4j-layout-jackson-yaml/pom.xml @@ -0,0 +1,171 @@ + + + + + + org.apache.logging.log4j + log4j + 3.0.0-SNAPSHOT + + 4.0.0 + + log4j-layout-jackson-yaml + Apache Log4j Layout for Jackson YAML + + Apache Log4j Layout for Jackson YAML. + + + ${basedir}/.. + Log4j Layout for Jackson YAML Documentation + /log4j-layout-yaml + org.apache.logging.log4j.jackson.yaml + + + + + org.apache.logging.log4j + log4j-layout-jackson + ${project.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + org.apache.logging.log4j + log4j-layout-jackson + test-jar + ${project.version} + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.jackson.yaml + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
    + Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

    ]]>
    + + false + true +
    + + + non-aggregate + + javadoc + + + +
    + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + +
    +
    +
    diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlModule.java similarity index 78% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java rename to log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlModule.java index c7b92f00500..8446a9d7332 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlModule.java +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlModule.java @@ -14,11 +14,10 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.yaml; -import org.apache.logging.log4j.core.jackson.Initializers.SetupContextInitializer; -import org.apache.logging.log4j.core.jackson.Initializers.SetupContextJsonInitializer; -import org.apache.logging.log4j.core.jackson.Initializers.SimpleModuleInitializer; +import org.apache.logging.log4j.jackson.SetupContextInitializer; +import org.apache.logging.log4j.jackson.SimpleModuleInitializer; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.databind.module.SimpleModule; @@ -35,25 +34,26 @@ final class Log4jYamlModule extends SimpleModule { private final boolean includeStacktrace; private final boolean stacktraceAsString; - Log4jYamlModule(final boolean encodeThreadContextAsList, final boolean includeStacktrace, final boolean stacktraceAsString) { + Log4jYamlModule(final boolean encodeThreadContextAsList, final boolean includeStacktrace, + final boolean stacktraceAsString) { super(Log4jYamlModule.class.getName(), new Version(2, 0, 0, null, null, null)); this.encodeThreadContextAsList = encodeThreadContextAsList; this.includeStacktrace = includeStacktrace; this.stacktraceAsString = stacktraceAsString; - // MUST init here. + // MUST call initialize() here. // Calling this from setupModule is too late! - //noinspection ThisEscapedInObjectConstruction + // noinspection ThisEscapedInObjectConstruction new SimpleModuleInitializer().initialize(this, false); } @Override public void setupModule(final SetupContext context) { - // Calling super is a MUST! + // MUST call super here. super.setupModule(context); if (encodeThreadContextAsList) { new SetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); } else { - new SetupContextJsonInitializer().setupModule(context, includeStacktrace, stacktraceAsString); + new YamlSetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); } } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlObjectMapper.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java rename to log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlObjectMapper.java index 0b80591d6b1..62c6483e3ea 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jYamlObjectMapper.java +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/Log4jYamlObjectMapper.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.yaml; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java new file mode 100644 index 00000000000..67f6fd13cf8 --- /dev/null +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/YamlSetupContextInitializer.java @@ -0,0 +1,47 @@ +package org.apache.logging.log4j.jackson.yaml; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.ExtendedStackTraceElementMixIn; +import org.apache.logging.log4j.jackson.InstantMixIn; +import org.apache.logging.log4j.jackson.LevelMixIn; +import org.apache.logging.log4j.jackson.LogEventJsonMixIn; +import org.apache.logging.log4j.jackson.MarkerMixIn; +import org.apache.logging.log4j.jackson.StackTraceElementMixIn; +import org.apache.logging.log4j.jackson.ThrowableProxyMixIn; +import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn; +import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn; + +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Used to set up {@link SetupContext} from different {@link SimpleModule}s. + *

    + * Consider this class private. + *

    + */ +class YamlSetupContextInitializer { + + public void setupModule(final SetupContext context, final boolean includeStacktrace, + final boolean stacktraceAsString) { + // JRE classes: we cannot edit those with Jackson annotations + context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class); + // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not + // depend on Jackson. + context.setMixInAnnotations(Marker.class, MarkerMixIn.class); + context.setMixInAnnotations(Level.class, LevelMixIn.class); + context.setMixInAnnotations(Instant.class, InstantMixIn.class); + context.setMixInAnnotations(LogEvent.class, LogEventJsonMixIn.class); // different ThreadContext handling + // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. + context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class); + context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace + ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class) + : ThrowableProxyWithoutStacktraceMixIn.class); + } + +} \ No newline at end of file diff --git a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java new file mode 100644 index 00000000000..856a201fe2d --- /dev/null +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlConstants.java @@ -0,0 +1,35 @@ +/* + * 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.jackson.yaml.layout; + +public class YamlConstants { + + static final String EVENT = "event"; + static final String ELT_CAUSE = "cause"; + static final String ELT_CONTEXT_MAP = "contextMap"; + static final String ELT_CONTEXT_STACK = "contextStack"; + static final String ELT_MARKER = "marker"; + static final String ELT_PARENTS = "parents"; + static final String ELT_SOURCE = "source"; + static final String ELT_SUPPRESSED = "suppressed"; + static final String ELT_THROWN = "thrown"; + static final String ELT_MESSAGE = "message"; + static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace"; + static final String ELT_NANO_TIME = "nanoTime"; + static final String ELT_INSTANT = "instant"; +} diff --git a/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java new file mode 100644 index 00000000000..e32041adfe2 --- /dev/null +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlJacksonFactory.java @@ -0,0 +1,68 @@ +/* + * 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.jackson.yaml.layout; + +import org.apache.logging.log4j.jackson.AbstractJacksonFactory; +import org.apache.logging.log4j.jackson.yaml.Log4jYamlObjectMapper; + +import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.core.util.MinimalPrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +class YamlJacksonFactory extends AbstractJacksonFactory { + + public YamlJacksonFactory(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(includeStacktrace, stacktraceAsString); + } + + @Override + protected String getPropertyNameForContextMap() { + return YamlConstants.ELT_CONTEXT_MAP; + } + + @Override + protected String getPropertyNameForNanoTime() { + return YamlConstants.ELT_NANO_TIME; + } + + @Override + protected String getPropertyNameForSource() { + return YamlConstants.ELT_SOURCE; + } + + @Override + protected String getPropertyNameForStackTrace() { + return YamlConstants.ELT_EXTENDED_STACK_TRACE; + } + + @Override + protected PrettyPrinter newCompactPrinter() { + return new MinimalPrettyPrinter(); + } + + @Override + protected ObjectMapper newObjectMapper() { + return new Log4jYamlObjectMapper(false, includeStacktrace, stacktraceAsString); + } + + @Override + protected PrettyPrinter newPrettyPrinter() { + return new DefaultPrettyPrinter(); + } +} \ No newline at end of file diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/YamlLayout.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java similarity index 68% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/layout/YamlLayout.java rename to log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java index 1d8576f2ea9..418ef9a0c7c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/YamlLayout.java +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayout.java @@ -14,7 +14,8 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; + +package org.apache.logging.log4j.jackson.yaml.layout; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -22,14 +23,21 @@ import java.util.Map; import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.config.Node; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.jackson.AbstractJacksonLayout; import org.apache.logging.log4j.util.Strings; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonRootName; +import com.fasterxml.jackson.annotation.JsonUnwrapped; + /** * Appends a series of YAML events as strings serialized as bytes. * @@ -41,21 +49,15 @@ *

    Additional Fields

    *

    * This property allows addition of custom fields into generated JSON. - * {@code } inserts {@code foo: "bar"} directly - * into YAML output. Supports Lookup expressions. + * {@code } inserts {@code foo: "bar"} directly into YAML + * output. Supports Lookup expressions. *

    */ @Plugin(name = "YamlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) public final class YamlLayout extends AbstractJacksonLayout { - private static final String DEFAULT_FOOTER = Strings.EMPTY; - - private static final String DEFAULT_HEADER = Strings.EMPTY; - - static final String CONTENT_TYPE = "application/yaml"; - public static class Builder> extends AbstractJacksonLayout.Builder - implements org.apache.logging.log4j.core.util.Builder { + implements org.apache.logging.log4j.core.util.Builder { public Builder() { super(); @@ -66,98 +68,52 @@ public Builder() { public YamlLayout build() { final String headerPattern = toStringOrNull(getHeader()); final String footerPattern = toStringOrNull(getFooter()); - return new YamlLayout(getConfiguration(), isLocationInfo(), isProperties(), isComplete(), - isCompact(), getEventEol(), headerPattern, footerPattern, getCharset(), - isIncludeStacktrace(), isStacktraceAsString(), isIncludeNullDelimiter(), - getAdditionalFields()); + return new YamlLayout(getConfiguration(), isLocationInfo(), isProperties(), isComplete(), isCompact(), + getEventEol(), headerPattern, footerPattern, getCharset(), isIncludeStacktrace(), + isStacktraceAsString(), isIncludeNullDelimiter(), getAdditionalFields()); } } - /** - * @deprecated Use {@link #newBuilder()} instead - */ - @Deprecated - protected YamlLayout(final Configuration config, final boolean locationInfo, final boolean properties, - final boolean complete, final boolean compact, final boolean eventEol, final String headerPattern, - final String footerPattern, final Charset charset, final boolean includeStacktrace) { - super(config, new JacksonFactory.YAML(includeStacktrace, false).newWriter(locationInfo, properties, compact), - charset, compact, complete, eventEol, - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(), - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(), - false, null); - } - - private YamlLayout(final Configuration config, final boolean locationInfo, final boolean properties, - final boolean complete, final boolean compact, final boolean eventEol, - final String headerPattern, final String footerPattern, final Charset charset, - final boolean includeStacktrace, final boolean stacktraceAsString, - final boolean includeNullDelimiter, - final KeyValuePair[] additionalFields) { - super(config, new JacksonFactory.YAML(includeStacktrace, stacktraceAsString).newWriter(locationInfo, properties, compact), - charset, compact, complete, eventEol, - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern).setDefaultPattern(DEFAULT_HEADER).build(), - PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern).setDefaultPattern(DEFAULT_FOOTER).build(), - includeNullDelimiter, - additionalFields); - } + @JsonRootName(YamlConstants.EVENT) + public static class YamlLogEventWithAdditionalFields extends LogEventWithAdditionalFields { - /** - * Returns appropriate YAML header. - * - * @return a byte array containing the header, opening the YAML array. - */ - @Override - public byte[] getHeader() { - if (!this.complete) { - return null; + public YamlLogEventWithAdditionalFields(final Object logEvent, final Map additionalFields) { + super(logEvent, additionalFields); } - final StringBuilder buf = new StringBuilder(); - final String str = serializeToString(getHeaderSerializer()); - if (str != null) { - buf.append(str); - } - buf.append(this.eol); - return getBytes(buf.toString()); - } - /** - * Returns appropriate YAML footer. - * - * @return a byte array containing the footer, closing the YAML array. - */ - @Override - public byte[] getFooter() { - if (!this.complete) { - return null; + @Override + @JsonAnyGetter + public Map getAdditionalFields() { + return super.getAdditionalFields(); } - final StringBuilder buf = new StringBuilder(); - buf.append(this.eol); - final String str = serializeToString(getFooterSerializer()); - if (str != null) { - buf.append(str); + + @Override + @JsonUnwrapped + public Object getLogEvent() { + return super.getLogEvent(); } - buf.append(this.eol); - return getBytes(buf.toString()); - } - @Override - public Map getContentFormat() { - final Map result = new HashMap<>(); - result.put("version", "2.0"); - return result; } + private static final String DEFAULT_FOOTER = Strings.EMPTY; + + private static final String DEFAULT_HEADER = Strings.EMPTY; + + static final String CONTENT_TYPE = "application/yaml"; + /** - * @return The content type. + * Creates a YAML Layout using the default settings. Useful for testing. + * + * @return A YAML Layout. */ - @Override - public String getContentType() { - return CONTENT_TYPE + "; charset=" + this.getCharset(); + public static AbstractJacksonLayout createDefaultLayout() { + return new YamlLayout(new DefaultConfiguration(), false, false, false, false, false, DEFAULT_HEADER, + DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, null); } /** * Creates a YAML Layout. - * + * * @param config * The plugin configuration. * @param locationInfo @@ -177,13 +133,8 @@ public String getContentType() { * @deprecated Use {@link #newBuilder()} instead */ @Deprecated - public static AbstractJacksonLayout createLayout( - final Configuration config, - final boolean locationInfo, - final boolean properties, - final String headerPattern, - final String footerPattern, - final Charset charset, + public static AbstractJacksonLayout createLayout(final Configuration config, final boolean locationInfo, + final boolean properties, final String headerPattern, final String footerPattern, final Charset charset, final boolean includeStacktrace) { return new YamlLayout(config, locationInfo, properties, false, false, true, headerPattern, footerPattern, charset, includeStacktrace, false, false, null); @@ -195,12 +146,94 @@ public static > B newBuilder() { } /** - * Creates a YAML Layout using the default settings. Useful for testing. + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + protected YamlLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean complete, final boolean compact, final boolean eventEol, final String headerPattern, + final String footerPattern, final Charset charset, final boolean includeStacktrace) { + super(config, new YamlJacksonFactory(includeStacktrace, false).newWriter(locationInfo, properties, compact), + charset, compact, complete, eventEol, + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern) + .setDefaultPattern(DEFAULT_HEADER).build(), + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern) + .setDefaultPattern(DEFAULT_FOOTER).build(), + false, null); + } + + private YamlLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean complete, final boolean compact, final boolean eventEol, final String headerPattern, + final String footerPattern, final Charset charset, final boolean includeStacktrace, + final boolean stacktraceAsString, final boolean includeNullDelimiter, + final KeyValuePair[] additionalFields) { + super(config, + new YamlJacksonFactory(includeStacktrace, stacktraceAsString).newWriter(locationInfo, properties, + compact), + charset, compact, complete, eventEol, + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(headerPattern) + .setDefaultPattern(DEFAULT_HEADER).build(), + PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(footerPattern) + .setDefaultPattern(DEFAULT_FOOTER).build(), + includeNullDelimiter, additionalFields); + } + + @Override + protected LogEventWithAdditionalFields createLogEventWithAdditionalFields(final LogEvent event, + final Map additionalFieldsMap) { + return new YamlLogEventWithAdditionalFields(event, additionalFieldsMap); + } + + @Override + public Map getContentFormat() { + final Map result = new HashMap<>(); + result.put("version", "3.0"); + return result; + } + + /** + * @return The content type. + */ + @Override + public String getContentType() { + return CONTENT_TYPE + "; charset=" + this.getCharset(); + } + + /** + * Returns appropriate YAML footer. * - * @return A YAML Layout. + * @return a byte array containing the footer, closing the YAML array. */ - public static AbstractJacksonLayout createDefaultLayout() { - return new YamlLayout(new DefaultConfiguration(), false, false, false, false, false, DEFAULT_HEADER, - DEFAULT_FOOTER, StandardCharsets.UTF_8, true, false, false, null); + @Override + public byte[] getFooter() { + if (!this.complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + buf.append(this.eol); + final String str = serializeToString(getFooterSerializer()); + if (str != null) { + buf.append(str); + } + buf.append(this.eol); + return getBytes(buf.toString()); + } + + /** + * Returns appropriate YAML header. + * + * @return a byte array containing the header, opening the YAML array. + */ + @Override + public byte[] getHeader() { + if (!this.complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + final String str = serializeToString(getHeaderSerializer()); + if (str != null) { + buf.append(str); + } + buf.append(this.eol); + return getBytes(buf.toString()); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/YamlLogEventParser.java b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParser.java similarity index 85% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/parser/YamlLogEventParser.java rename to log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParser.java index 3efe662f406..0ef4049b210 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/parser/YamlLogEventParser.java +++ b/log4j-layout-jackson-yaml/src/main/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParser.java @@ -14,10 +14,11 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.parser; +package org.apache.logging.log4j.jackson.yaml.parser; import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.jackson.Log4jYamlObjectMapper; +import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser; +import org.apache.logging.log4j.jackson.yaml.Log4jYamlObjectMapper; /** * Parses the output from YamlLayout layout into instances of {@link LogEvent}. diff --git a/log4j-layout-jackson-yaml/src/site/manual/index.md b/log4j-layout-jackson-yaml/src/site/manual/index.md new file mode 100644 index 00000000000..83112afdc95 --- /dev/null +++ b/log4j-layout-jackson-yaml/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j Layout for Jackson YAML module + +As of Log4j 3.0.0, the layout based on Jackson YAML has moved from the existing module logj-core to the new modules log4j-layout-jackson-yaml. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires Jackson. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-layout-jackson-yaml/src/site/site.xml b/log4j-layout-jackson-yaml/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-layout-jackson-yaml/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInYamlTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/LevelMixInYamlTest.java similarity index 91% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInYamlTest.java rename to log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/LevelMixInYamlTest.java index 29b9e52795a..86b99845bdb 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInYamlTest.java +++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/LevelMixInYamlTest.java @@ -15,12 +15,14 @@ * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson.yaml; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.categories.Layouts; +import org.apache.logging.log4j.jackson.LevelMixInTest; import org.junit.experimental.categories.Category; +import com.fasterxml.jackson.databind.ObjectMapper; + @Category(Layouts.Yaml.class) public class LevelMixInYamlTest extends LevelMixInTest { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInYamlTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/MarkerMixInYamlTest.java similarity index 85% rename from log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInYamlTest.java rename to log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/MarkerMixInYamlTest.java index 2d14b6b308f..98132cd10a2 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInYamlTest.java +++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/MarkerMixInYamlTest.java @@ -15,16 +15,16 @@ * limitations under the license. */ -package org.apache.logging.log4j; +package org.apache.logging.log4j.jackson.yaml; import org.apache.logging.log4j.categories.Layouts; -import org.apache.logging.log4j.core.jackson.Log4jYamlObjectMapper; +import org.apache.logging.log4j.jackson.AbstractMarkerMixInTest; +import org.junit.experimental.categories.Category; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.experimental.categories.Category; @Category(Layouts.Yaml.class) -public class MarkerMixInYamlTest extends MarkerMixInTest { +public class MarkerMixInYamlTest extends AbstractMarkerMixInTest { @Override protected ObjectMapper newObjectMapper() { diff --git a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java new file mode 100644 index 00000000000..97466556618 --- /dev/null +++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/StackTraceElementYamlMixInTest.java @@ -0,0 +1,83 @@ +/* + * 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.jackson.yaml; + +import java.io.IOException; + +import org.apache.logging.log4j.categories.Layouts; +import org.apache.logging.log4j.jackson.Log4jStackTraceElementDeserializer; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; + +@Category(Layouts.Json.class) +public class StackTraceElementYamlMixInTest { + + protected String aposToQuotes(final String json) { + return json.replace("'", "\""); + } + + private void roundtrip(final ObjectMapper mapper) + throws JsonProcessingException, IOException, JsonParseException, JsonMappingException { + final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", + 123); + final String s = mapper.writeValueAsString(expected); + final StackTraceElement actual = mapper.readValue(s, StackTraceElement.class); + Assert.assertEquals(expected, actual); + } + + @Test + public void testFromYamlWithLog4jModule() throws Exception { + final ObjectMapper mapper = new YAMLMapper(); + final boolean encodeThreadContextAsList = false; + final SimpleModule module = new Log4jYamlModule(encodeThreadContextAsList, true, false); + module.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); + mapper.registerModule(module); + final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", + 123); + final StackTraceElement actual = mapper.readValue( + "---\nclass: package.SomeClass\nmethod: someMethod\nfile: SomeClass.java\nline: 123\n...", + StackTraceElement.class); + Assert.assertEquals(expected, actual); + } + + @Test + public void testFromYamlWithSimpleModule() throws Exception { + final ObjectMapper mapper = new YAMLMapper(); + final SimpleModule module = new SimpleModule(); + module.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); + mapper.registerModule(module); + final StackTraceElement expected = new StackTraceElement("package.SomeClass", "someMethod", "SomeClass.java", + 123); + final StackTraceElement actual = mapper.readValue( + "---\nclass: package.SomeClass\nmethod: someMethod\nfile: SomeClass.java\nline: 123\n...", + StackTraceElement.class); + Assert.assertEquals(expected, actual); + } + + @Test + public void testLog4jYamlObjectMapper() throws Exception { + this.roundtrip(new Log4jYamlObjectMapper()); + } +} diff --git a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java new file mode 100644 index 00000000000..a0e821c0f5d --- /dev/null +++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/ConcurrentLoggingWithYamlLayoutTest.java @@ -0,0 +1,113 @@ +/* + * 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.jackson.yaml.layout; + +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertThat; + +import java.io.File; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.AfterClass; +import org.junit.ClassRule; +import org.junit.Test; + +/** + * Like the test for LOG4J2-1769. + */ +public class ConcurrentLoggingWithYamlLayoutTest { + + private class LoggingThread extends Thread { + private final Set threads; + private final Logger log; + + LoggingThread(final Set threads, final Logger log) { + this.threads = threads; + this.log = log; + } + + @Override + public void run() { + log.info(threads.size()); + try { + for (int i = 0; i < 64; i++) { + log.info("First message."); + log.info("Second message."); + } + } finally { + threads.remove(this); + } + } + } + + @ClassRule + public static LoggerContextRule context = new LoggerContextRule("log4j2-yaml-layout.xml"); + + private static final String PATH = "target/test-yaml-layout.log"; + + @AfterClass + public static void after() { + new File(PATH).delete(); + } + + @Test + public void testConcurrentLogging() throws Throwable { + final Logger log = context.getLogger(ConcurrentLoggingWithYamlLayoutTest.class); + final Set threads = Collections.synchronizedSet(new HashSet()); + final List thrown = Collections.synchronizedList(new ArrayList()); + + for (int x = 0; x < Runtime.getRuntime().availableProcessors() * 2; x++) { + final Thread t = new LoggingThread(threads, log); + threads.add(t); + + // Appender is configured with ignoreExceptions="false"; + // any exceptions are propagated to the caller, so we can catch them here. + t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(final Thread t, final Throwable e) { + thrown.add(e); + } + }); + t.start(); + } + + while (!threads.isEmpty()) { + log.info("not done going to sleep..."); + Thread.sleep(10); + } + + // if any error occurred, fail this test + if (!thrown.isEmpty()) { + throw thrown.get(0); + } + + // simple test to ensure content is not corrupted + if (new File(PATH).exists()) { + final List lines = Files.readAllLines(new File(PATH).toPath(), Charset.defaultCharset()); + assertThat(lines.get(0), startsWith("---")); + // TODO more + } + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java rename to log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java index 2fef8de2acc..b8e3ee688f7 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/YamlLayoutTest.java +++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.jackson.yaml.layout; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -35,9 +35,11 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.jackson.Log4jYamlObjectMapper; +import org.apache.logging.log4j.core.layout.LogEventFixtures; import org.apache.logging.log4j.core.lookup.JavaLookup; import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.jackson.AbstractJacksonLayout; +import org.apache.logging.log4j.jackson.yaml.Log4jYamlObjectMapper; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.AbstractLogger; import org.apache.logging.log4j.test.appender.ListAppender; @@ -114,6 +116,34 @@ private void checkPropertyNameAbsent(final String name, final boolean compact, f assertFalse(str, str.contains(name + propSep)); } + private String prepareYAMLForStacktraceTests(final boolean stacktraceAsString) { + final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); + // @formatter:off + final AbstractJacksonLayout layout = YamlLayout.newBuilder() + .setIncludeStacktrace(true) + .setStacktraceAsString(stacktraceAsString) + .build(); + // @formatter:off + return layout.toSerializable(expected); + } + + @Test + public void testAdditionalFields() throws Exception { + final AbstractJacksonLayout layout = YamlLayout.newBuilder() + .setLocationInfo(false) + .setProperties(false) + .setIncludeStacktrace(false) + .setAdditionalFields(new KeyValuePair[] { + new KeyValuePair("KEY1", "VALUE1"), + new KeyValuePair("KEY2", "${java:runtime}"), }) + .setCharset(StandardCharsets.UTF_8) + .setConfiguration(ctx.getConfiguration()) + .build(); + final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); + assertTrue(str, str.contains("KEY1: \"VALUE1\"")); + assertTrue(str, str.contains("KEY2: \"" + new JavaLookup().getRuntime() + "\"")); + } + private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean eventEol, final boolean includeContext, final boolean contextMapAslist, final boolean includeStacktrace) throws Exception { final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); @@ -231,6 +261,29 @@ public void testEscapeLayout() throws Exception { } } + @Test + public void testExcludeStacktrace() throws Exception { + this.testAllFeatures(false, false, false, false, false, false); + } + + @Test + public void testIncludeNullDelimiterFalse() throws Exception { + final AbstractJacksonLayout layout = YamlLayout.newBuilder() + .setIncludeNullDelimiter(false) + .build(); + final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); + assertFalse(str.endsWith("\0")); + } + + @Test + public void testIncludeNullDelimiterTrue() throws Exception { + final AbstractJacksonLayout layout = YamlLayout.newBuilder() + .setIncludeNullDelimiter(true) + .build(); + final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); + assertTrue(str.endsWith("\0")); + } + /** * Test case for MDC conversion pattern. */ @@ -301,23 +354,6 @@ public void testLayoutLoggerName() throws Exception { assertEquals(expected, actual); } - @Test - public void testAdditionalFields() throws Exception { - final AbstractJacksonLayout layout = YamlLayout.newBuilder() - .setLocationInfo(false) - .setProperties(false) - .setIncludeStacktrace(false) - .setAdditionalFields(new KeyValuePair[] { - new KeyValuePair("KEY1", "VALUE1"), - new KeyValuePair("KEY2", "${java:runtime}"), }) - .setCharset(StandardCharsets.UTF_8) - .setConfiguration(ctx.getConfiguration()) - .build(); - final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); - assertTrue(str, str.contains("KEY1: \"VALUE1\"")); - assertTrue(str, str.contains("KEY2: \"" + new JavaLookup().getRuntime() + "\"")); - } - @Test public void testLocationOffCompactOffMdcOff() throws Exception { this.testAllFeatures(false, false, false, false, false, true); @@ -328,50 +364,16 @@ public void testLocationOnCompactOffEventEolOffMdcOn() throws Exception { this.testAllFeatures(true, false, false, true, false, true); } - @Test - public void testExcludeStacktrace() throws Exception { - this.testAllFeatures(false, false, false, false, false, false); - } - - @Test - public void testStacktraceAsString() throws Exception { - final String str = prepareYAMLForStacktraceTests(true); - assertTrue(str, str.contains("extendedStackTrace: \"java.lang.NullPointerException")); - } - @Test public void testStacktraceAsNonString() throws Exception { final String str = prepareYAMLForStacktraceTests(false); assertTrue(str, str.contains("extendedStackTrace:\n - ")); } - private String prepareYAMLForStacktraceTests(final boolean stacktraceAsString) { - final Log4jLogEvent expected = LogEventFixtures.createLogEvent(); - // @formatter:off - final AbstractJacksonLayout layout = YamlLayout.newBuilder() - .setIncludeStacktrace(true) - .setStacktraceAsString(stacktraceAsString) - .build(); - // @formatter:off - return layout.toSerializable(expected); - } - @Test - public void testIncludeNullDelimiterTrue() throws Exception { - final AbstractJacksonLayout layout = YamlLayout.newBuilder() - .setIncludeNullDelimiter(true) - .build(); - final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); - assertTrue(str.endsWith("\0")); - } - - @Test - public void testIncludeNullDelimiterFalse() throws Exception { - final AbstractJacksonLayout layout = YamlLayout.newBuilder() - .setIncludeNullDelimiter(false) - .build(); - final String str = layout.toSerializable(LogEventFixtures.createLogEvent()); - assertFalse(str.endsWith("\0")); + public void testStacktraceAsString() throws Exception { + final String str = prepareYAMLForStacktraceTests(true); + assertTrue(str, str.contains("extendedStackTrace: \"java.lang.NullPointerException")); } private String toPropertySeparator(final boolean compact, final boolean value) { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParserTest.java similarity index 94% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java rename to log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParserTest.java index 16c77e76ae5..7e689e6655b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/parser/YamlLogEventParserTest.java +++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/parser/YamlLogEventParserTest.java @@ -14,17 +14,17 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.parser; +package org.apache.logging.log4j.jackson.yaml.parser; + +import java.nio.charset.StandardCharsets; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.parser.AbstractLogEventParserTest; +import org.apache.logging.log4j.core.parser.ParseException; import org.junit.Before; import org.junit.Test; -import java.nio.charset.StandardCharsets; - -public class YamlLogEventParserTest extends LogEventParserTest { - - private YamlLogEventParser parser; +public class YamlLogEventParserTest extends AbstractLogEventParserTest { private static final String YAML = "---\n" + "timeMillis: 1493121664118\n" + @@ -69,25 +69,24 @@ public class YamlLogEventParserTest extends LogEventParserTest { " file: \"Main.java\"\n" + " line: 29"; + private YamlLogEventParser parser; + @Before public void setup() { parser = new YamlLogEventParser(); } @Test - public void testString() throws ParseException { - final LogEvent logEvent = parser.parseFrom(YAML); + public void testByteArray() throws ParseException { + final LogEvent logEvent = parser.parseFrom(YAML.getBytes(StandardCharsets.UTF_8)); assertLogEvent(logEvent); } - @Test(expected = ParseException.class) - public void testStringEmpty() throws ParseException { - parser.parseFrom(""); - } - - @Test(expected = ParseException.class) - public void testStringInvalidYaml() throws ParseException { - parser.parseFrom("foobar"); + @Test + public void testByteArrayOffsetLength() throws ParseException { + final byte[] bytes = ("abc" + YAML + "def").getBytes(StandardCharsets.UTF_8); + final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6); + assertLogEvent(logEvent); } @Test @@ -96,13 +95,14 @@ public void testEmptyObject() throws ParseException { } @Test - public void testTimeMillisIgnored() throws ParseException { - parser.parseFrom("---\ntimeMillis: \"foobar\"\n"); + public void testString() throws ParseException { + final LogEvent logEvent = parser.parseFrom(YAML); + assertLogEvent(logEvent); } @Test(expected = ParseException.class) - public void testStringWrongPropertyType() throws ParseException { - parser.parseFrom("---\nthreadId: \"foobar\"\n"); + public void testStringEmpty() throws ParseException { + parser.parseFrom(""); } @Test @@ -110,17 +110,19 @@ public void testStringIgnoreInvalidProperty() throws ParseException { parser.parseFrom("---\nfoo: \"bar\"\n"); } - @Test - public void testByteArray() throws ParseException { - final LogEvent logEvent = parser.parseFrom(YAML.getBytes(StandardCharsets.UTF_8)); - assertLogEvent(logEvent); + @Test(expected = ParseException.class) + public void testStringInvalidYaml() throws ParseException { + parser.parseFrom("foobar"); + } + + @Test(expected = ParseException.class) + public void testStringWrongPropertyType() throws ParseException { + parser.parseFrom("---\nthreadId: \"foobar\"\n"); } @Test - public void testByteArrayOffsetLength() throws ParseException { - final byte[] bytes = ("abc" + YAML + "def").getBytes(StandardCharsets.UTF_8); - final LogEvent logEvent = parser.parseFrom(bytes, 3, bytes.length - 6); - assertLogEvent(logEvent); + public void testTimeMillisIgnored() throws ParseException { + parser.parseFrom("---\ntimeMillis: \"foobar\"\n"); } } diff --git a/log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-layout.xml b/log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-layout.xml new file mode 100644 index 00000000000..f01d1e67aba --- /dev/null +++ b/log4j-layout-jackson-yaml/src/test/resources/log4j2-yaml-layout.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/log4j-layout-jackson/pom.xml b/log4j-layout-jackson/pom.xml new file mode 100644 index 00000000000..ad6183510d1 --- /dev/null +++ b/log4j-layout-jackson/pom.xml @@ -0,0 +1,214 @@ + + + + + + org.apache.logging.log4j + log4j + 3.0.0-SNAPSHOT + + 4.0.0 + + log4j-layout-jackson + Apache Log4j Layout for Jackson + + Apache Log4j Layout for Jackson. + + + ${basedir}/.. + Log4j Layout for Jackson Documentation + /log4j-layout-jackson + org.apache.logging.log4j.jackson + + + + + org.apache.logging.log4j + log4j-core + + + com.fasterxml.jackson.core + jackson-databind + + + + junit + junit + + + org.apache.logging.log4j + log4j-api + test-jar + + + org.apache.logging.log4j + log4j-core + test-jar + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + default-jar + + jar + + + + ${manifestfile} + + ${project.name} + ${project.version} + ${project.organization.name} + ${project.name} + ${project.version} + ${project.organization.name} + org.apache + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + default + + test-jar + + + + ${manifestfile} + + ${project.name} + ${project.version} + ${project.organization.name} + ${project.name} + ${project.version} + ${project.organization.name} + org.apache + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.jackson + * + + + + + + + + + org.apache.maven.plugins + maven-changes-plugin + ${changes.plugin.version} + + + + changes-report + + + + + %URL%/show_bug.cgi?id=%ISSUE% + true + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + + ${log4jParentDir}/checkstyle.xml + ${log4jParentDir}/checkstyle-suppressions.xml + false + basedir=${basedir} + licensedir=${log4jParentDir}/checkstyle-header.txt + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${javadoc.plugin.version} + + Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.
    + Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.

    ]]>
    + + false + true +
    + + + non-aggregate + + javadoc + + + +
    + + org.codehaus.mojo + findbugs-maven-plugin + ${findbugs.plugin.version} + + true + -Duser.language=en + Normal + Default + ${log4jParentDir}/findbugs-exclude-filter.xml + + + + org.apache.maven.plugins + maven-jxr-plugin + ${jxr.plugin.version} + + + non-aggregate + + jxr + + + + aggregate + + aggregate + + + + + + org.apache.maven.plugins + maven-pmd-plugin + ${pmd.plugin.version} + + ${maven.compiler.target} + + +
    +
    +
    diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java new file mode 100644 index 00000000000..ad4503c61db --- /dev/null +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonFactory.java @@ -0,0 +1,74 @@ +/* + * 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.jackson; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.logging.log4j.core.impl.Log4jLogEvent; + +import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; + +public abstract class AbstractJacksonFactory { + + protected final boolean includeStacktrace; + + protected final boolean stacktraceAsString; + public AbstractJacksonFactory(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(); + this.includeStacktrace = includeStacktrace; + this.stacktraceAsString = stacktraceAsString; + } + + abstract protected String getPropertyNameForContextMap(); + + abstract protected String getPropertyNameForNanoTime(); + + abstract protected String getPropertyNameForSource(); + + abstract protected String getPropertyNameForStackTrace(); + + abstract protected PrettyPrinter newCompactPrinter(); + + abstract protected ObjectMapper newObjectMapper(); + + abstract protected PrettyPrinter newPrettyPrinter(); + + public ObjectWriter newWriter(final boolean locationInfo, final boolean properties, final boolean compact) { + final SimpleFilterProvider filters = new SimpleFilterProvider(); + final Set except = new HashSet<>(4); + if (!locationInfo) { + except.add(this.getPropertyNameForSource()); + } + if (!properties) { + except.add(this.getPropertyNameForContextMap()); + } + if (!includeStacktrace) { + except.add(this.getPropertyNameForStackTrace()); + } + except.add(this.getPropertyNameForNanoTime()); + filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except)); + final ObjectWriter writer = this.newObjectMapper() + .writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter()); + return writer.with(filters); + } + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java similarity index 80% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java index 7a04100d69f..da66b9d3b0e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractJacksonLayout.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractJacksonLayout.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.layout; +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.io.Writer; @@ -27,24 +27,15 @@ import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.impl.MutableLogEvent; -import org.apache.logging.log4j.core.jackson.XmlConstants; +import org.apache.logging.log4j.core.layout.AbstractStringLayout; import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.util.KeyValuePair; import org.apache.logging.log4j.core.util.StringBuilderWriter; import org.apache.logging.log4j.util.Strings; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonRootName; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; -abstract class AbstractJacksonLayout extends AbstractStringLayout { - - protected static final String DEFAULT_EOL = "\r\n"; - protected static final String COMPACT_EOL = Strings.EMPTY; +public abstract class AbstractJacksonLayout extends AbstractStringLayout { public static abstract class Builder> extends AbstractStringLayout.Builder { @@ -75,8 +66,8 @@ public static abstract class Builder> extends AbstractStrin @PluginElement("AdditionalField") private KeyValuePair[] additionalFields; - protected String toStringOrNull(final byte[] header) { - return header == null ? null : new String(header, Charset.defaultCharset()); + public KeyValuePair[] getAdditionalFields() { + return additionalFields; } public boolean getEventEol() { @@ -91,34 +82,38 @@ public boolean isComplete() { return complete; } - public boolean isLocationInfo() { - return locationInfo; - } - - public boolean isProperties() { - return properties; + public boolean isIncludeNullDelimiter() { + return includeNullDelimiter; } /** - * If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true". - * @return If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true". + * If "true", includes the stack trace of any Throwable in the generated data, defaults to "true". + * + * @return If "true", includes the stack trace of any Throwable in the generated data, defaults to "true". */ public boolean isIncludeStacktrace() { return includeStacktrace; } - public boolean isStacktraceAsString() { - return stacktraceAsString; + public boolean isLocationInfo() { + return locationInfo; } - public boolean isIncludeNullDelimiter() { return includeNullDelimiter; } + public boolean isProperties() { + return properties; + } - public KeyValuePair[] getAdditionalFields() { - return additionalFields; + public boolean isStacktraceAsString() { + return stacktraceAsString; } - public B setEventEol(final boolean eventEol) { - this.eventEol = eventEol; + /** + * Additional fields to set on each log event. + * + * @return this builder + */ + public B setAdditionalFields(final KeyValuePair[] additionalFields) { + this.additionalFields = additionalFields; return asBuilder(); } @@ -132,19 +127,26 @@ public B setComplete(final boolean complete) { return asBuilder(); } - public B setLocationInfo(final boolean locationInfo) { - this.locationInfo = locationInfo; + public B setEventEol(final boolean eventEol) { + this.eventEol = eventEol; return asBuilder(); } - public B setProperties(final boolean properties) { - this.properties = properties; + /** + * Whether to include NULL byte as delimiter after each event (optional, default to false). + * + * @return this builder + */ + public B setIncludeNullDelimiter(final boolean includeNullDelimiter) { + this.includeNullDelimiter = includeNullDelimiter; return asBuilder(); } /** * If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true". - * @param includeStacktrace If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true". + * + * @param includeStacktrace + * If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true". * @return this builder */ public B setIncludeStacktrace(final boolean includeStacktrace) { @@ -152,6 +154,16 @@ public B setIncludeStacktrace(final boolean includeStacktrace) { return asBuilder(); } + public B setLocationInfo(final boolean locationInfo) { + this.locationInfo = locationInfo; + return asBuilder(); + } + + public B setProperties(final boolean properties) { + this.properties = properties; + return asBuilder(); + } + /** * Whether to format the stacktrace as a string, and not a nested object (optional, defaults to false). * @@ -162,32 +174,88 @@ public B setStacktraceAsString(final boolean stacktraceAsString) { return asBuilder(); } - /** - * Whether to include NULL byte as delimiter after each event (optional, default to false). - * - * @return this builder - */ - public B setIncludeNullDelimiter(final boolean includeNullDelimiter) { - this.includeNullDelimiter = includeNullDelimiter; - return asBuilder(); + protected String toStringOrNull(final byte[] header) { + return header == null ? null : new String(header, Charset.defaultCharset()); } + } + /** + * Subclasses can annotate with Jackson annotations for JSON example. + */ + public static class LogEventWithAdditionalFields { - /** - * Additional fields to set on each log event. - * - * @return this builder - */ - public B setAdditionalFields(KeyValuePair[] additionalFields) { + private final Object logEvent; + private final Map additionalFields; + + public LogEventWithAdditionalFields(final Object logEvent, final Map additionalFields) { + this.logEvent = logEvent; this.additionalFields = additionalFields; - return asBuilder(); + } + + public Map getAdditionalFields() { + return additionalFields; + } + + public Object getLogEvent() { + return logEvent; } } + protected static class ResolvableKeyValuePair { + + final String key; + final String value; + final boolean valueNeedsLookup; + + ResolvableKeyValuePair(final KeyValuePair pair) { + this.key = pair.getKey(); + this.value = pair.getValue(); + this.valueNeedsLookup = AbstractJacksonLayout.valueNeedsLookup(this.value); + } + } + + protected static final String DEFAULT_EOL = "\r\n"; + protected static final String COMPACT_EOL = Strings.EMPTY; + private static LogEvent convertMutableToLog4jEvent(final LogEvent event) { + // TODO Jackson-based layouts have certain filters set up for Log4jLogEvent. + // TODO Need to set up the same filters for MutableLogEvent but don't know how... + // This is a workaround. + return event instanceof MutableLogEvent ? ((MutableLogEvent) event).createMemento() : event; + } + private static ResolvableKeyValuePair[] prepareAdditionalFields(final Configuration config, + final KeyValuePair[] additionalFields) { + if (additionalFields == null || additionalFields.length == 0) { + // No fields set + return new ResolvableKeyValuePair[0]; + } + + // Convert to specific class which already determines whether values needs lookup during serialization + final ResolvableKeyValuePair[] resolvableFields = new ResolvableKeyValuePair[additionalFields.length]; + + for (int i = 0; i < additionalFields.length; i++) { + final ResolvableKeyValuePair resolvable = resolvableFields[i] = new ResolvableKeyValuePair(additionalFields[i]); + + // Validate + if (config == null && resolvable.valueNeedsLookup) { + throw new IllegalArgumentException( + "configuration needs to be set when there are additional fields with variables"); + } + } + + return resolvableFields; + } + protected static boolean valueNeedsLookup(final String value) { + return value != null && value.contains("${"); + } protected final String eol; + protected final ObjectWriter objectWriter; + protected final boolean compact; + protected final boolean complete; + protected final boolean includeNullDelimiter; + protected final ResolvableKeyValuePair[] additionalFields; @Deprecated @@ -201,7 +269,8 @@ protected AbstractJacksonLayout(final Configuration config, final ObjectWriter o protected AbstractJacksonLayout(final Configuration config, final ObjectWriter objectWriter, final Charset charset, final boolean compact, final boolean complete, final boolean eventEol, final Serializer headerSerializer, final Serializer footerSerializer, final boolean includeNullDelimiter) { - this(config, objectWriter, charset, compact, complete, eventEol, headerSerializer, footerSerializer, includeNullDelimiter, null); + this(config, objectWriter, charset, compact, complete, eventEol, headerSerializer, footerSerializer, + includeNullDelimiter, null); } protected AbstractJacksonLayout(final Configuration config, final ObjectWriter objectWriter, final Charset charset, @@ -217,41 +286,40 @@ protected AbstractJacksonLayout(final Configuration config, final ObjectWriter o this.additionalFields = prepareAdditionalFields(config, additionalFields); } - protected static boolean valueNeedsLookup(final String value) { - return value != null && value.contains("${"); + protected LogEventWithAdditionalFields createLogEventWithAdditionalFields(final LogEvent event, + final Map additionalFieldsMap) { + return new LogEventWithAdditionalFields(event, additionalFieldsMap); } - private static ResolvableKeyValuePair[] prepareAdditionalFields(final Configuration config, final KeyValuePair[] additionalFields) { - if (additionalFields == null || additionalFields.length == 0) { - // No fields set - return new ResolvableKeyValuePair[0]; - } - - // Convert to specific class which already determines whether values needs lookup during serialization - final ResolvableKeyValuePair[] resolvableFields = new ResolvableKeyValuePair[additionalFields.length]; - - for (int i = 0; i < additionalFields.length; i++) { - ResolvableKeyValuePair resolvable = resolvableFields[i] = new ResolvableKeyValuePair(additionalFields[i]); + private Map resolveAdditionalFields(final LogEvent logEvent) { + // Note: LinkedHashMap retains order + final Map additionalFieldsMap = new LinkedHashMap<>(additionalFields.length); + final StrSubstitutor strSubstitutor = configuration.getStrSubstitutor(); - // Validate - if (config == null && resolvable.valueNeedsLookup) { - throw new IllegalArgumentException("configuration needs to be set when there are additional fields with variables"); + // Go over each field + for (final ResolvableKeyValuePair pair : additionalFields) { + if (pair.valueNeedsLookup) { + // Resolve value + additionalFieldsMap.put(pair.key, strSubstitutor.replace(logEvent, pair.value)); + } else { + // Plain text value + additionalFieldsMap.put(pair.key, pair.value); } } - return resolvableFields; + return additionalFieldsMap; } /** * Formats a {@link org.apache.logging.log4j.core.LogEvent}. * - * @param event The LogEvent. + * @param event + * The LogEvent. * @return The XML representation of the LogEvent. */ @Override public String toSerializable(final LogEvent event) { - final StringBuilderWriter writer = new StringBuilderWriter(); - try { + try (final StringBuilderWriter writer = new StringBuilderWriter()) { toSerializable(event, writer); return writer.toString(); } catch (final IOException e) { @@ -261,48 +329,7 @@ public String toSerializable(final LogEvent event) { } } - private static LogEvent convertMutableToLog4jEvent(final LogEvent event) { - // TODO Jackson-based layouts have certain filters set up for Log4jLogEvent. - // TODO Need to set up the same filters for MutableLogEvent but don't know how... - // This is a workaround. - return event instanceof MutableLogEvent - ? ((MutableLogEvent) event).createMemento() - : event; - } - - protected Object wrapLogEvent(final LogEvent event) { - if (additionalFields.length > 0) { - // Construct map for serialization - note that we are intentionally using original LogEvent - Map additionalFieldsMap = resolveAdditionalFields(event); - // This class combines LogEvent with AdditionalFields during serialization - return new LogEventWithAdditionalFields(event, additionalFieldsMap); - } else { - // No additional fields, return original object - return event; - } - } - - private Map resolveAdditionalFields(LogEvent logEvent) { - // Note: LinkedHashMap retains order - final Map additionalFieldsMap = new LinkedHashMap<>(additionalFields.length); - final StrSubstitutor strSubstitutor = configuration.getStrSubstitutor(); - - // Go over each field - for (ResolvableKeyValuePair pair : additionalFields) { - if (pair.valueNeedsLookup) { - // Resolve value - additionalFieldsMap.put(pair.key, strSubstitutor.replace(logEvent, pair.value)); - } else { - // Plain text value - additionalFieldsMap.put(pair.key, pair.value); - } - } - - return additionalFieldsMap; - } - - public void toSerializable(final LogEvent event, final Writer writer) - throws JsonGenerationException, JsonMappingException, IOException { + public void toSerializable(final LogEvent event, final Writer writer) throws IOException { objectWriter.writeValue(writer, wrapLogEvent(convertMutableToLog4jEvent(event))); writer.write(eol); if (includeNullDelimiter) { @@ -311,40 +338,14 @@ public void toSerializable(final LogEvent event, final Writer writer) markEvent(); } - @JsonRootName(XmlConstants.ELT_EVENT) - @JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) - public static class LogEventWithAdditionalFields { - - private final Object logEvent; - private final Map additionalFields; - - public LogEventWithAdditionalFields(Object logEvent, Map additionalFields) { - this.logEvent = logEvent; - this.additionalFields = additionalFields; - } - - @JsonUnwrapped - public Object getLogEvent() { - return logEvent; - } - - @JsonAnyGetter - @SuppressWarnings("unused") - public Map getAdditionalFields() { - return additionalFields; - } - } - - protected static class ResolvableKeyValuePair { - - final String key; - final String value; - final boolean valueNeedsLookup; - - ResolvableKeyValuePair(KeyValuePair pair) { - this.key = pair.getKey(); - this.value = pair.getValue(); - this.valueNeedsLookup = AbstractJacksonLayout.valueNeedsLookup(this.value); + protected Object wrapLogEvent(final LogEvent event) { + if (additionalFields.length > 0) { + // Construct map for serialization - note that we are intentionally using original LogEvent + final Map additionalFieldsMap = resolveAdditionalFields(event); + // This class combines LogEvent with AdditionalFields during serialization + return createLogEventWithAdditionalFields(event, additionalFieldsMap); } + // No additional fields, return original object + return event; } } diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java new file mode 100644 index 00000000000..43784d6be9a --- /dev/null +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/AbstractLogEventMixIn.java @@ -0,0 +1,84 @@ +/* + * 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.jackson; + +import java.util.Map; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.message.Message; + +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +/** + *
    + * AbstractLogEventMixIn
    +*├─ AbstractLogEventXmlMixIn
    +*├──── LogEventWithContextListXmlMixIn
    +*├──── LogEventWithContextMapXmlMixIn
    +*├─ AbstractLogEventJsonMixIn
    +*├──── LogEventWithContextListJsonMixIn
    +*├──── LogEventWithContextMapJsonMixIn
    + * 
    + */ +@JsonFilter(AbstractLogEventMixIn.JSON_FILTER_ID) +public abstract class AbstractLogEventMixIn implements LogEvent { + + public static final String ATTR_END_OF_BATCH = "endOfBatch"; + public static final String ATTR_LEVEL = "level"; + public static final String ATTR_LOGGER_FQCN = "loggerFqcn"; + public static final String ATTR_LOGGER_NAME = "loggerName"; + public static final String ATTR_MARKER = "marker"; + public static final String ATTR_THREAD = "thread"; + public static final String ATTR_THREAD_ID = "threadId"; + public static final String ATTR_THREAD_PRIORITY = "threadPriority"; + public static final String ELT_MESSAGE = "message"; + public static final String JSON_FILTER_ID = "org.apache.logging.log4j.core.impl.Log4jLogEvent"; + + private static final long serialVersionUID = 1L; + + @Deprecated + @Override + @JsonIgnore + public abstract Map getContextMap(); + + @JsonSerialize(using = MessageSerializer.class) + @JsonDeserialize(using = SimpleMessageDeserializer.class) + @Override + public abstract Message getMessage(); + + @JsonIgnore + @Override + public abstract Throwable getThrown(); + + @JsonIgnore // ignore from 2.11.0 + @Override + public abstract long getTimeMillis(); + + @JsonIgnore + @Override + public abstract boolean isIncludeLocation(); + + @Override + public abstract void setEndOfBatch(boolean endOfBatch); + + @Override + public abstract void setIncludeLocation(boolean locationRequired); + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java similarity index 88% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListDeserializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java index 85dd21e19f6..6efee4f37aa 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListDeserializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListDeserializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.util.List; @@ -43,12 +43,12 @@ public class ContextDataAsEntryListDeserializer extends StdDeserializer list = jp.readValueAs(new TypeReference>() { - // empty + // do nothing }); - final StringMap contextData = new ContextDataFactory().createContextData(); + final StringMap contextData = ContextDataFactory.createContextData(); for (final MapEntry mapEntry : list) { contextData.putValue(mapEntry.getKey(), mapEntry.getValue()); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListSerializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListSerializer.java similarity index 77% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListSerializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListSerializer.java index ccf17ff287a..d3c7551e57f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataAsEntryListSerializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataAsEntryListSerializer.java @@ -14,13 +14,14 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; + +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.util.Map; -import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.BiConsumer; +import org.apache.logging.log4j.util.ReadOnlyStringMap; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; @@ -40,17 +41,25 @@ protected ContextDataAsEntryListSerializer() { super(Map.class, false); } + protected MapEntry createMapEntry(final String key, final String value) { + return new MapEntry(key, value); + } + + protected MapEntry[] createMapEntryArray(final int size) { + return new MapEntry[size]; + } + @Override - public void serialize(final ReadOnlyStringMap contextData, final JsonGenerator jgen, final SerializerProvider provider) - throws IOException, JsonGenerationException { + public void serialize(final ReadOnlyStringMap contextData, final JsonGenerator jgen, + final SerializerProvider provider) throws IOException, JsonGenerationException { - final MapEntry[] pairs = new MapEntry[contextData.size()]; + final MapEntry[] pairs = createMapEntryArray(contextData.size()); contextData.forEach(new BiConsumer() { int i = 0; @Override public void accept(final String key, final Object value) { - pairs[i++] = new MapEntry(key, String.valueOf(value)); + pairs[i++] = createMapEntry(key, String.valueOf(value)); } }); jgen.writeObject(pairs); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataDeserializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java index 3a9a13e248b..9d6843ad791 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataDeserializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataDeserializer.java @@ -15,7 +15,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.util.Map; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataSerializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataSerializer.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataSerializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataSerializer.java index 8808d3d699f..245e436a547 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ContextDataSerializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ContextDataSerializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.util.Map; @@ -36,19 +36,6 @@ public class ContextDataSerializer extends StdSerializer { private static final long serialVersionUID = 1L; - protected ContextDataSerializer() { - super(Map.class, false); - } - - @Override - public void serialize(final ReadOnlyStringMap contextData, final JsonGenerator jgen, - final SerializerProvider provider) throws IOException, JsonGenerationException { - - jgen.writeStartObject(); - contextData.forEach(WRITE_STRING_FIELD_INTO, jgen); - jgen.writeEndObject(); - } - private static final TriConsumer WRITE_STRING_FIELD_INTO = new TriConsumer() { @@ -61,4 +48,17 @@ public void accept(final String key, final Object value, final JsonGenerator jso } } }; + + protected ContextDataSerializer() { + super(Map.class, false); + } + + @Override + public void serialize(final ReadOnlyStringMap contextData, final JsonGenerator jgen, + final SerializerProvider provider) throws IOException, JsonGenerationException { + + jgen.writeStartObject(); + contextData.forEach(WRITE_STRING_FIELD_INTO, jgen); + jgen.writeEndObject(); + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java similarity index 52% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java index 84df3d60750..2642e420a17 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ExtendedStackTraceElementMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ExtendedStackTraceElementMixIn.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.Serializable; @@ -25,63 +25,73 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; /** * Mix-in for {@link ExtendedStackTraceElement}. */ -@JsonPropertyOrder({ "class", "method", "file", "line", "exact", "location", "version" }) -abstract class ExtendedStackTraceElementMixIn implements Serializable { +@JsonPropertyOrder({ + //@formatter:off + ExtendedStackTraceElementMixIn.ATTR_CLASS, + ExtendedStackTraceElementMixIn.ATTR_METHOD, + ExtendedStackTraceElementMixIn.ATTR_FILE, + ExtendedStackTraceElementMixIn.ATTR_LINE, + ExtendedStackTraceElementMixIn.ATTR_EXACT, + ExtendedStackTraceElementMixIn.ATTR_LOCATION, + ExtendedStackTraceElementMixIn.ATTR_VERSION + //@formatter:on +}) +public abstract class ExtendedStackTraceElementMixIn implements Serializable { + + protected static final String ATTR_CLASS = StackTraceElementConstants.ATTR_CLASS; + protected static final String ATTR_METHOD = StackTraceElementConstants.ATTR_METHOD; + protected static final String ATTR_FILE = StackTraceElementConstants.ATTR_FILE; + protected static final String ATTR_LINE = StackTraceElementConstants.ATTR_LINE; + protected static final String ATTR_EXACT = "exact"; + protected static final String ATTR_LOCATION = "location"; + protected static final String ATTR_VERSION = "version"; private static final long serialVersionUID = 1L; @JsonCreator public ExtendedStackTraceElementMixIn( - // @formatter:off - @JsonProperty("class") final String declaringClass, - @JsonProperty("method") final String methodName, - @JsonProperty("file") final String fileName, - @JsonProperty("line") final int lineNumber, - @JsonProperty("exact") final boolean exact, - @JsonProperty("location") final String location, - @JsonProperty("version") final String version - // @formatter:on + // @formatter:off + @JsonProperty(ATTR_CLASS) final String declaringClass, + @JsonProperty(ATTR_METHOD) final String methodName, + @JsonProperty(ATTR_FILE) final String fileName, + @JsonProperty(ATTR_LINE) final int lineNumber, + @JsonProperty(ATTR_EXACT) final boolean exact, + @JsonProperty(ATTR_LOCATION) final String location, + @JsonProperty(ATTR_VERSION) final String version + // @formatter:on ) { // empty } - @JsonProperty("class") - @JacksonXmlProperty(localName = "class", isAttribute = true) + @JsonProperty(ATTR_CLASS) public abstract String getClassName(); - @JsonProperty - @JacksonXmlProperty(isAttribute = true) + @JsonProperty(ATTR_EXACT) public abstract boolean getExact(); @JsonIgnore public abstract ExtendedClassInfo getExtraClassInfo(); - @JsonProperty("file") - @JacksonXmlProperty(localName = "file", isAttribute = true) + @JsonProperty(ATTR_FILE) public abstract String getFileName(); - @JsonProperty("line") - @JacksonXmlProperty(localName = "line", isAttribute = true) + @JsonProperty(ATTR_LINE) public abstract int getLineNumber(); - @JsonProperty - @JacksonXmlProperty(isAttribute = true) + @JsonProperty(ATTR_LOCATION) public abstract String getLocation(); - @JsonProperty("method") - @JacksonXmlProperty(localName = "method", isAttribute = true) + @JsonProperty(ATTR_METHOD) public abstract String getMethodName(); - + @JsonIgnore abstract StackTraceElement getStackTraceElement(); - @JsonProperty - @JacksonXmlProperty(isAttribute = true) + @JsonProperty(ATTR_VERSION) public abstract String getVersion(); @JsonIgnore diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/InstantMixIn.java similarity index 68% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/InstantMixIn.java index 216534b0f4d..16a3bb5b4d3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/InstantMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/InstantMixIn.java @@ -14,40 +14,42 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.time.Instant; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.core.time.Instant; /** * Jackson mix-in for {@link Instant}. *

    * Consider this class private. *

    + * * @see Marker */ @JsonIgnoreProperties({ "epochMillisecond", "nanoOfMillisecond" }) -abstract class InstantMixIn { +public abstract class InstantMixIn { + + protected static final String ATTR_NANO_OF_SECOND = "nanoOfSecond"; + protected static final String ATTR_EPOCH_SECOND = "epochSecond"; @JsonCreator - InstantMixIn( - // @formatter:off - @JsonProperty("epochSecond") final long epochSecond, - @JsonProperty("nanoOfSecond") final int nanoOfSecond) + protected InstantMixIn( + // @formatter:off + @JsonProperty(ATTR_EPOCH_SECOND) final long epochSecond, + @JsonProperty(ATTR_NANO_OF_SECOND) final int nanoOfSecond) // @formatter:on { // empty } - @JsonProperty("epochSecond") - @JacksonXmlProperty(localName = "epochSecond", isAttribute = true) - abstract long getEpochSecond(); + @JsonProperty(ATTR_EPOCH_SECOND) + public abstract long getEpochSecond(); - @JsonProperty("nanoOfSecond") - @JacksonXmlProperty(localName = "nanoOfSecond", isAttribute = true) - abstract int getNanoOfSecond(); + @JsonProperty(ATTR_NANO_OF_SECOND) + public abstract int getNanoOfSecond(); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/JsonConstants.java similarity index 94% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/JsonConstants.java index bb9898d95c0..1db6f5287d5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/JsonConstants.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/JsonConstants.java @@ -14,13 +14,14 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; /** * Keeps constants separate from any class that may depend on third party jars. */ public final class JsonConstants { public static final String ELT_CAUSE = "cause"; + public static final String ELT_EVENT = "event"; public static final String ELT_CONTEXT_MAP = "contextMap"; public static final String ELT_CONTEXT_STACK = "contextStack"; public static final String ELT_MARKER = "marker"; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LevelMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LevelMixIn.java similarity index 94% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LevelMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LevelMixIn.java index bb252c87f53..c11d22ea424 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LevelMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LevelMixIn.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; @@ -31,7 +31,7 @@ * @see Marker */ @JsonIgnoreProperties({ "name", "declaringClass", "standardLevel" }) -abstract class LevelMixIn { +public abstract class LevelMixIn { @JsonCreator(mode = JsonCreator.Mode.DELEGATING) public static Level getLevel(final String name) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ListOfMapEntryDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ListOfMapEntryDeserializer.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ListOfMapEntryDeserializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ListOfMapEntryDeserializer.java index 0a7281ed327..4a1199d8c9c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ListOfMapEntryDeserializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ListOfMapEntryDeserializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.util.HashMap; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ListOfMapEntrySerializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ListOfMapEntrySerializer.java similarity index 88% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ListOfMapEntrySerializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ListOfMapEntrySerializer.java index 02f47a2f67e..48a99110047 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ListOfMapEntrySerializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ListOfMapEntrySerializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.util.Map; @@ -39,11 +39,15 @@ protected ListOfMapEntrySerializer() { super(Map.class, false); } + protected MapEntry[] createMapEntryArray(final Set> entrySet) { + return new MapEntry[entrySet.size()]; + } + @Override public void serialize(final Map map, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, JsonGenerationException { final Set> entrySet = map.entrySet(); - final MapEntry[] pairs = new MapEntry[entrySet.size()]; + final MapEntry[] pairs = createMapEntryArray(entrySet); int i = 0; for (final Entry entry : entrySet) { pairs[i++] = new MapEntry(entry.getKey(), entry.getValue()); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jStackTraceElementDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/Log4jStackTraceElementDeserializer.java similarity index 98% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jStackTraceElementDeserializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/Log4jStackTraceElementDeserializer.java index 936ace19d2d..7d03805915b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jStackTraceElementDeserializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/Log4jStackTraceElementDeserializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventJsonMixIn.java similarity index 61% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventJsonMixIn.java index bbb024de965..e9607bd4c54 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventJsonMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventJsonMixIn.java @@ -14,18 +14,18 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.util.Map; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -34,88 +34,87 @@ import com.fasterxml.jackson.annotation.JsonRootName; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; -@JsonRootName(XmlConstants.ELT_EVENT) -@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) +@JsonRootName(JsonConstants.ELT_EVENT) @JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent") -@JsonPropertyOrder({ "timeMillis", XmlConstants.ELT_INSTANT, "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP, - JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" }) -abstract class LogEventJsonMixIn implements LogEvent { +@JsonPropertyOrder({ + // @formatter:off + "timeMillis", + JsonConstants.ELT_INSTANT, + "threadName", + "level", + "loggerName", + "marker", + "message", + "thrown", + JsonConstants.ELT_CONTEXT_MAP, + JsonConstants.ELT_CONTEXT_STACK, + "loggerFQCN", + "Source", + "endOfBatch" }) + // @formatter:on +/** + * As of Jackson 2.9.4, if we extend AbstractLogEventMixIn, then the {@link ObjectMessage} serializer + * {@code ObjectMessageSerializer} does not get invoked. Either a bug in Jackson or in our set up code. + */ +public abstract class LogEventJsonMixIn /* extends AbstractLogEventMixIn */ implements LogEvent { private static final long serialVersionUID = 1L; -// @JsonProperty(JsonConstants.ELT_CONTEXT_MAP) -// @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) -// @JsonSerialize(using = MapSerializer.class) -// @JsonDeserialize(using = MapDeserializer.class) - @Override - @JsonIgnore -// @JsonProperty(JsonConstants.ELT_CONTEXT_MAP) -// @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) - public abstract Map getContextMap(); - @JsonProperty(JsonConstants.ELT_CONTEXT_MAP) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) @JsonSerialize(using = ContextDataSerializer.class) @JsonDeserialize(using = ContextDataDeserializer.class) - //@JsonIgnore @Override public abstract ReadOnlyStringMap getContextData(); + @Override + @JsonIgnore + public abstract Map getContextMap(); + @JsonProperty(JsonConstants.ELT_CONTEXT_STACK) - @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK_ITEM) @Override public abstract ContextStack getContextStack(); + @JsonProperty(JsonConstants.ELT_INSTANT) + @Override + public abstract Instant getInstant(); + @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract Level getLevel(); @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract String getLoggerFqcn(); @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract String getLoggerName(); @JsonProperty(JsonConstants.ELT_MARKER) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) @Override public abstract Marker getMarker(); @JsonProperty(JsonConstants.ELT_MESSAGE) @JsonDeserialize(using = SimpleMessageDeserializer.class) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MESSAGE) @Override public abstract Message getMessage(); @JsonProperty(JsonConstants.ELT_SOURCE) @JsonDeserialize(using = Log4jStackTraceElementDeserializer.class) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SOURCE) @Override public abstract StackTraceElement getSource(); @Override @JsonProperty("threadId") - @JacksonXmlProperty(isAttribute = true, localName = "threadId") public abstract long getThreadId(); @Override @JsonProperty("thread") - @JacksonXmlProperty(isAttribute = true, localName = "thread") public abstract String getThreadName(); @Override @JsonProperty("threadPriority") - @JacksonXmlProperty(isAttribute = true, localName = "threadPriority") public abstract int getThreadPriority(); @JsonIgnore @@ -123,23 +122,14 @@ abstract class LogEventJsonMixIn implements LogEvent { public abstract Throwable getThrown(); @JsonProperty(JsonConstants.ELT_THROWN) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_THROWN) @Override public abstract ThrowableProxy getThrownProxy(); @JsonIgnore // ignore from 2.11 -// @JsonProperty() -// @JacksonXmlProperty(isAttribute = true) @Override public abstract long getTimeMillis(); - @JsonProperty(JsonConstants.ELT_INSTANT) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_INSTANT) - @Override - public abstract Instant getInstant(); - @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract boolean isEndOfBatch(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventWithContextListMixIn.java similarity index 68% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventWithContextListMixIn.java index 12b61fa7962..cd0639bcf41 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/LogEventWithContextListMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/LogEventWithContextListMixIn.java @@ -14,18 +14,18 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.util.Map; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext.ContextStack; -import org.apache.logging.log4j.core.time.Instant; -import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -34,12 +34,8 @@ import com.fasterxml.jackson.annotation.JsonRootName; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; @JsonRootName(XmlConstants.ELT_EVENT) -@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) @JsonFilter("org.apache.logging.log4j.core.impl.Log4jLogEvent") @JsonPropertyOrder({ "timeMillis", XmlConstants.ELT_INSTANT, "threadName", "level", "loggerName", "marker", "message", "thrown", XmlConstants.ELT_CONTEXT_MAP, JsonConstants.ELT_CONTEXT_STACK, "loggerFQCN", "Source", "endOfBatch" }) @@ -47,74 +43,62 @@ abstract class LogEventWithContextListMixIn implements LogEvent { private static final long serialVersionUID = 1L; -// @JsonProperty(JsonConstants.ELT_CONTEXT_MAP) -// @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) -// @JsonSerialize(using = ListOfMapEntrySerializer.class) -// @JsonDeserialize(using = ListOfMapEntryDeserializer.class) - @Override - @JsonIgnore - public abstract Map getContextMap(); - @JsonProperty(JsonConstants.ELT_CONTEXT_MAP) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) @JsonSerialize(using = ContextDataAsEntryListSerializer.class) @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class) // @JsonIgnore @Override public abstract ReadOnlyStringMap getContextData(); + @Override + @JsonIgnore + public abstract Map getContextMap(); + @JsonProperty(JsonConstants.ELT_CONTEXT_STACK) - @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK_ITEM) @Override public abstract ContextStack getContextStack(); + @JsonProperty(JsonConstants.ELT_INSTANT) + @Override + public abstract Instant getInstant(); + @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract Level getLevel(); @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract String getLoggerFqcn(); @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract String getLoggerName(); @JsonProperty(JsonConstants.ELT_MARKER) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) @Override public abstract Marker getMarker(); @JsonProperty(JsonConstants.ELT_MESSAGE) @JsonSerialize(using = MessageSerializer.class) @JsonDeserialize(using = SimpleMessageDeserializer.class) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MESSAGE) @Override public abstract Message getMessage(); @JsonProperty(JsonConstants.ELT_SOURCE) @JsonDeserialize(using = Log4jStackTraceElementDeserializer.class) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SOURCE) @Override public abstract StackTraceElement getSource(); @Override @JsonProperty("threadId") - @JacksonXmlProperty(isAttribute = true, localName = "threadId") public abstract long getThreadId(); @Override @JsonProperty("thread") - @JacksonXmlProperty(isAttribute = true, localName = "thread") public abstract String getThreadName(); @Override @JsonProperty("threadPriority") - @JacksonXmlProperty(isAttribute = true, localName = "threadPriority") public abstract int getThreadPriority(); @JsonIgnore @@ -122,23 +106,14 @@ abstract class LogEventWithContextListMixIn implements LogEvent { public abstract Throwable getThrown(); @JsonProperty(JsonConstants.ELT_THROWN) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_THROWN) @Override public abstract ThrowableProxy getThrownProxy(); @JsonIgnore // ignore from 2.11 -// @JsonProperty() -// @JacksonXmlProperty(isAttribute = true) @Override public abstract long getTimeMillis(); - @JsonProperty(JsonConstants.ELT_INSTANT) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_INSTANT) - @Override - public abstract Instant getInstant(); - @JsonProperty() - @JacksonXmlProperty(isAttribute = true) @Override public abstract boolean isEndOfBatch(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MapEntry.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MapEntry.java similarity index 87% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MapEntry.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MapEntry.java index 239b084982a..fc021809b75 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MapEntry.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MapEntry.java @@ -14,33 +14,32 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; + +package org.apache.logging.log4j.jackson; import org.apache.logging.log4j.util.Strings; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; /** *

    * Consider this class private. *

    *

    - * Used to represent map entries in a generic fashion because the default Jackson behavior uses the key as the element tag. Using the key as - * an element/property name would mean that you cannot have a generic JSON/XML schema for all log event. + * Used to represent map entries in a generic fashion because the default Jackson behavior uses the key as the element + * tag. Using the key as an element/property name would mean that you cannot have a generic JSON/XML schema for all log + * event. *

    */ @JsonPropertyOrder({ "key", "value" }) -final class MapEntry { +public class MapEntry { @JsonProperty - @JacksonXmlProperty(isAttribute = true) private String key; @JsonProperty - @JacksonXmlProperty(isAttribute = true) private String value; @JsonCreator diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MarkerMixIn.java similarity index 79% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MarkerMixIn.java index 950c2c8e412..45bbcc38f91 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MarkerMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MarkerMixIn.java @@ -14,15 +14,13 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import org.apache.logging.log4j.Marker; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; /** * Jackson mix-in for {@link Marker}. @@ -48,29 +46,26 @@ </Parents> </Marker> * - * + * * @see Marker */ // Alternate for multiple Marker implementation. // @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") @JsonDeserialize(as = org.apache.logging.log4j.MarkerManager.Log4jMarker.class) -abstract class MarkerMixIn implements Marker { +public abstract class MarkerMixIn implements Marker { private static final long serialVersionUID = 1L; @JsonCreator - MarkerMixIn(@JsonProperty("name") final String name) { + public MarkerMixIn(@JsonProperty("name") final String name) { // empty } @Override @JsonProperty("name") - @JacksonXmlProperty(isAttribute = true) public abstract String getName(); @Override @JsonProperty(JsonConstants.ELT_PARENTS) - @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_PARENTS) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) public abstract Marker[] getParents(); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MessageSerializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MessageSerializer.java similarity index 90% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MessageSerializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MessageSerializer.java index 3c19672faf8..faff2daf883 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MessageSerializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MessageSerializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; @@ -30,11 +30,11 @@ * Consider this class private. *

    */ -final class MessageSerializer extends StdScalarSerializer { +public final class MessageSerializer extends StdScalarSerializer { private static final long serialVersionUID = 1L; - MessageSerializer() { + public MessageSerializer() { super(Message.class); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MutableThreadContextStackDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MutableThreadContextStackDeserializer.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MutableThreadContextStackDeserializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MutableThreadContextStackDeserializer.java index 4d4a530dd9e..b98edb530b6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/MutableThreadContextStackDeserializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/MutableThreadContextStackDeserializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; import java.util.List; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ObjectMessageSerializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ObjectMessageSerializer.java similarity index 86% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ObjectMessageSerializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ObjectMessageSerializer.java index 8bbfe0b1518..3cb9af25789 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ObjectMessageSerializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ObjectMessageSerializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; @@ -39,9 +39,9 @@ final class ObjectMessageSerializer extends StdScalarSerializer { } @Override - public void serialize(final ObjectMessage value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException, - JsonGenerationException { - jgen.writeObject(value.getParameter()); + public void serialize(final ObjectMessage value, final JsonGenerator jsonGenerator, + final SerializerProvider serializerProvider) throws IOException, JsonGenerationException { + jsonGenerator.writeObject(value.getParameter()); } } diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java new file mode 100644 index 00000000000..3d73d932906 --- /dev/null +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SetupContextInitializer.java @@ -0,0 +1,38 @@ +package org.apache.logging.log4j.jackson; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; + +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Used to set up {@link SetupContext} from different {@link SimpleModule}s. + *

    + * Consider this class private. + *

    + */ +public class SetupContextInitializer { + + public void setupModule(final SetupContext context, final boolean includeStacktrace, + final boolean stacktraceAsString) { + // JRE classes: we cannot edit those with Jackson annotations + context.setMixInAnnotations(StackTraceElement.class, StackTraceElementMixIn.class); + // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not + // depend on Jackson. + context.setMixInAnnotations(Marker.class, MarkerMixIn.class); + context.setMixInAnnotations(Level.class, LevelMixIn.class); + context.setMixInAnnotations(Instant.class, InstantMixIn.class); + context.setMixInAnnotations(LogEvent.class, LogEventWithContextListMixIn.class); + // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. + context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class); + context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace + ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class) + : ThrowableProxyWithoutStacktraceMixIn.class); + } + +} \ No newline at end of file diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/SimpleMessageDeserializer.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SimpleMessageDeserializer.java similarity index 83% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/SimpleMessageDeserializer.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SimpleMessageDeserializer.java index f269590306f..2ab948cf791 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/SimpleMessageDeserializer.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/SimpleMessageDeserializer.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; @@ -39,9 +39,9 @@ public final class SimpleMessageDeserializer extends StdScalarDeserializer + * Consider this class private. + *

    + */ +public class SimpleModuleInitializer { + public void initialize(final SimpleModule simpleModule, final boolean objectMessageAsJsonObject) { + // Workaround because mix-ins do not work for classes that already have a built-in deserializer. + // See Jackson issue 429. + simpleModule.addDeserializer(StackTraceElement.class, new Log4jStackTraceElementDeserializer()); + simpleModule.addDeserializer(ContextStack.class, new MutableThreadContextStackDeserializer()); + if (objectMessageAsJsonObject) { + simpleModule.addSerializer(ObjectMessage.class, new ObjectMessageSerializer()); + } + simpleModule.addSerializer(Message.class, new MessageSerializer()); + } +} \ No newline at end of file diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/StackTraceElementConstants.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/StackTraceElementConstants.java new file mode 100644 index 00000000000..0f0f0250486 --- /dev/null +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/StackTraceElementConstants.java @@ -0,0 +1,30 @@ +/* + * 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.jackson; + +/** + * Defines constants use for naming stack trace elements. + */ +public class StackTraceElementConstants { + + public static final String ATTR_CLASS = "class"; + public static final String ATTR_FILE = "file"; + public static final String ATTR_LINE = "line"; + public static final String ATTR_METHOD = "method"; + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/StackTraceElementMixIn.java similarity index 54% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/StackTraceElementMixIn.java index 9a3b0223f80..b3bff92aed9 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/StackTraceElementMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/StackTraceElementMixIn.java @@ -14,49 +14,46 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; + +package org.apache.logging.log4j.jackson; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; /** * Jackson mix-in for {@link StackTraceElement}. *

    * Consider this class private. *

    - * + * * @see StackTraceElement */ @JsonIgnoreProperties("nativeMethod") -abstract class StackTraceElementMixIn { +public abstract class StackTraceElementMixIn { + @JsonCreator - StackTraceElementMixIn( - // @formatter:off - @JsonProperty("class") final String declaringClass, - @JsonProperty("method") final String methodName, - @JsonProperty("file") final String fileName, - @JsonProperty("line") final int lineNumber) - // @formatter:on + protected StackTraceElementMixIn( + // @formatter:off + @JsonProperty(StackTraceElementConstants.ATTR_CLASS) final String declaringClass, + @JsonProperty(StackTraceElementConstants.ATTR_METHOD) final String methodName, + @JsonProperty(StackTraceElementConstants.ATTR_FILE) final String fileName, + @JsonProperty(StackTraceElementConstants.ATTR_LINE) final int lineNumber) + // @formatter:on { // empty } - @JsonProperty("class") - @JacksonXmlProperty(localName = "class", isAttribute = true) - abstract String getClassName(); + @JsonProperty(StackTraceElementConstants.ATTR_CLASS) + protected abstract String getClassName(); - @JsonProperty("file") - @JacksonXmlProperty(localName = "file", isAttribute = true) - abstract String getFileName(); + @JsonProperty(StackTraceElementConstants.ATTR_FILE) + protected abstract String getFileName(); - @JsonProperty("line") - @JacksonXmlProperty(localName = "line", isAttribute = true) - abstract int getLineNumber(); + @JsonProperty(StackTraceElementConstants.ATTR_LINE) + protected abstract int getLineNumber(); - @JsonProperty("method") - @JacksonXmlProperty(localName = "method", isAttribute = true) - abstract String getMethodName(); + @JsonProperty(StackTraceElementConstants.ATTR_METHOD) + protected abstract String getMethodName(); } diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java new file mode 100644 index 00000000000..7116c8099c1 --- /dev/null +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyMixIn.java @@ -0,0 +1,70 @@ +/* + * 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.jackson; + +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Mix-in for {@link ThrowableProxy}. + */ +public abstract class ThrowableProxyMixIn { + + @JsonProperty(JsonConstants.ELT_CAUSE) + private ThrowableProxyMixIn causeProxy; + + @JsonProperty + private int commonElementCount; + + @JsonProperty(JsonConstants.ELT_EXTENDED_STACK_TRACE) + private ExtendedStackTraceElement[] extendedStackTrace; + + @JsonProperty + private String localizedMessage; + + @JsonProperty + private String message; + + @JsonProperty + private String name; + + @JsonIgnore + private transient Throwable throwable; + + @JsonIgnore + public abstract String getCauseStackTraceAsString(); + + @JsonIgnore + public abstract String getExtendedStackTraceAsString(); + + @JsonIgnore + public abstract StackTraceElement[] getStackTrace(); + + @JsonProperty(JsonConstants.ELT_SUPPRESSED) + public abstract ThrowableProxy[] getSuppressedProxies(); + + @JsonIgnore + public abstract String getSuppressedStackTrace(); + + @JsonIgnore + public abstract Throwable getThrowable(); + +} diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java new file mode 100644 index 00000000000..e73a108433c --- /dev/null +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithStacktraceAsStringMixIn.java @@ -0,0 +1,70 @@ +/* + * 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.jackson; + +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Mix-in for {@link org.apache.logging.log4j.core.impl.ThrowableProxy}. + */ +public abstract class ThrowableProxyWithStacktraceAsStringMixIn { + + @JsonProperty(JsonConstants.ELT_CAUSE) + private ThrowableProxyWithStacktraceAsStringMixIn causeProxy; + + @JsonProperty + private int commonElementCount; + + @JsonIgnore + private ExtendedStackTraceElement[] extendedStackTrace; + + @JsonProperty + private String localizedMessage; + + @JsonProperty + private String message; + + @JsonProperty + private String name; + + @JsonIgnore + private transient Throwable throwable; + + @JsonIgnore + public abstract String getCauseStackTraceAsString(); + + @JsonProperty(JsonConstants.ELT_EXTENDED_STACK_TRACE) + public abstract String getExtendedStackTraceAsString(); + + @JsonIgnore + public abstract StackTraceElement[] getStackTrace(); + + @JsonProperty(JsonConstants.ELT_SUPPRESSED) + public abstract ThrowableProxy[] getSuppressedProxies(); + + @JsonIgnore + public abstract String getSuppressedStackTrace(); + + @JsonIgnore + public abstract Throwable getThrowable(); + +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithoutStacktraceMixIn.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithoutStacktraceMixIn.java similarity index 72% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithoutStacktraceMixIn.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithoutStacktraceMixIn.java index 264bef8bbd2..b80c89ce952 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/ThrowableProxyWithoutStacktraceMixIn.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/ThrowableProxyWithoutStacktraceMixIn.java @@ -14,41 +14,35 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; import org.apache.logging.log4j.core.impl.ThrowableProxy; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * Mix-in for {@link ThrowableProxy}. */ -abstract class ThrowableProxyWithoutStacktraceMixIn { +public abstract class ThrowableProxyWithoutStacktraceMixIn { @JsonProperty(JsonConstants.ELT_CAUSE) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE) private ThrowableProxyWithoutStacktraceMixIn causeProxy; @JsonProperty - @JacksonXmlProperty(isAttribute = true) private int commonElementCount; @JsonIgnore private ExtendedStackTraceElement[] extendedStackTrace; @JsonProperty - @JacksonXmlProperty(isAttribute = true) private String localizedMessage; @JsonProperty - @JacksonXmlProperty(isAttribute = true) private String message; @JsonProperty - @JacksonXmlProperty(isAttribute = true) private String name; @JsonIgnore @@ -64,8 +58,6 @@ abstract class ThrowableProxyWithoutStacktraceMixIn { public abstract StackTraceElement[] getStackTrace(); @JsonProperty(JsonConstants.ELT_SUPPRESSED) - @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED) - @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM) public abstract ThrowableProxy[] getSuppressedProxies(); @JsonIgnore diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/XmlConstants.java similarity index 97% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/XmlConstants.java index 08714402a6e..10dc37d46c7 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/XmlConstants.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/XmlConstants.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; /** * Keeps constants separate from any class that may depend on third party jars. diff --git a/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java new file mode 100644 index 00000000000..a468c1e2990 --- /dev/null +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/layout/AbstractJacksonLayout.java @@ -0,0 +1,378 @@ +/* + * 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. + */ + +/* + * 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.jackson.layout; + +import java.io.IOException; +import java.io.Writer; +import java.nio.charset.Charset; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; +import org.apache.logging.log4j.core.config.plugins.PluginElement; +import org.apache.logging.log4j.core.impl.MutableLogEvent; +import org.apache.logging.log4j.core.layout.AbstractStringLayout; +import org.apache.logging.log4j.core.lookup.StrSubstitutor; +import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.core.util.StringBuilderWriter; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.util.Strings; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonRootName; +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectWriter; + +abstract class AbstractJacksonLayout extends AbstractStringLayout { + + public static abstract class Builder> extends AbstractStringLayout.Builder { + + @PluginBuilderAttribute + private boolean eventEol; + + @PluginBuilderAttribute + private boolean compact; + + @PluginBuilderAttribute + private boolean complete; + + @PluginBuilderAttribute + private boolean locationInfo; + + @PluginBuilderAttribute + private boolean properties; + + @PluginBuilderAttribute + private boolean includeStacktrace = true; + + @PluginBuilderAttribute + private boolean stacktraceAsString = false; + + @PluginBuilderAttribute + private boolean includeNullDelimiter = false; + + @PluginElement("AdditionalField") + private KeyValuePair[] additionalFields; + + public KeyValuePair[] getAdditionalFields() { + return additionalFields; + } + + public boolean getEventEol() { + return eventEol; + } + + public boolean isCompact() { + return compact; + } + + public boolean isComplete() { + return complete; + } + + public boolean isIncludeNullDelimiter() { + return includeNullDelimiter; + } + + /** + * If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true". + * + * @return If "true", includes the stacktrace of any Throwable in the generated data, defaults to "true". + */ + public boolean isIncludeStacktrace() { + return includeStacktrace; + } + + public boolean isLocationInfo() { + return locationInfo; + } + + public boolean isProperties() { + return properties; + } + + public boolean isStacktraceAsString() { + return stacktraceAsString; + } + + /** + * Additional fields to set on each log event. + * + * @return this builder + */ + public B setAdditionalFields(final KeyValuePair[] additionalFields) { + this.additionalFields = additionalFields; + return asBuilder(); + } + + public B setCompact(final boolean compact) { + this.compact = compact; + return asBuilder(); + } + + public B setComplete(final boolean complete) { + this.complete = complete; + return asBuilder(); + } + + public B setEventEol(final boolean eventEol) { + this.eventEol = eventEol; + return asBuilder(); + } + + /** + * Whether to include NULL byte as delimiter after each event (optional, default to false). + * + * @return this builder + */ + public B setIncludeNullDelimiter(final boolean includeNullDelimiter) { + this.includeNullDelimiter = includeNullDelimiter; + return asBuilder(); + } + + /** + * If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true". + * + * @param includeStacktrace + * If "true", includes the stacktrace of any Throwable in the generated JSON, defaults to "true". + * @return this builder + */ + public B setIncludeStacktrace(final boolean includeStacktrace) { + this.includeStacktrace = includeStacktrace; + return asBuilder(); + } + + public B setLocationInfo(final boolean locationInfo) { + this.locationInfo = locationInfo; + return asBuilder(); + } + + public B setProperties(final boolean properties) { + this.properties = properties; + return asBuilder(); + } + + /** + * Whether to format the stacktrace as a string, and not a nested object (optional, defaults to false). + * + * @return this builder + */ + public B setStacktraceAsString(final boolean stacktraceAsString) { + this.stacktraceAsString = stacktraceAsString; + return asBuilder(); + } + + protected String toStringOrNull(final byte[] header) { + return header == null ? null : new String(header, Charset.defaultCharset()); + } + } + @JsonRootName(XmlConstants.ELT_EVENT) + public static class LogEventWrapperWithAdditionalFields { + + private final Object logEvent; + private final Map additionalFields; + + public LogEventWrapperWithAdditionalFields(final Object logEvent, final Map additionalFields) { + this.logEvent = logEvent; + this.additionalFields = additionalFields; + } + + @JsonAnyGetter + @SuppressWarnings("unused") + public Map getAdditionalFields() { + return additionalFields; + } + + @JsonUnwrapped + public Object getLogEvent() { + return logEvent; + } + } + + protected static class ResolvableKeyValuePair { + + final String key; + final String value; + final boolean valueNeedsLookup; + + ResolvableKeyValuePair(final KeyValuePair pair) { + this.key = pair.getKey(); + this.value = pair.getValue(); + this.valueNeedsLookup = AbstractJacksonLayout.valueNeedsLookup(this.value); + } + } + + protected static final String DEFAULT_EOL = "\r\n"; + + protected static final String COMPACT_EOL = Strings.EMPTY; + private static LogEvent convertMutableToLog4jEvent(final LogEvent event) { + // TODO Jackson-based layouts have certain filters set up for Log4jLogEvent. + // TODO Need to set up the same filters for MutableLogEvent but don't know how... + // This is a workaround. + return event instanceof MutableLogEvent ? ((MutableLogEvent) event).createMemento() : event; + } + private static ResolvableKeyValuePair[] prepareAdditionalFields(final Configuration config, + final KeyValuePair[] additionalFields) { + if (additionalFields == null || additionalFields.length == 0) { + // No fields set + return new ResolvableKeyValuePair[0]; + } + + // Convert to specific class which already determines whether values needs lookup during serialization + final ResolvableKeyValuePair[] resolvableFields = new ResolvableKeyValuePair[additionalFields.length]; + + for (int i = 0; i < additionalFields.length; i++) { + final ResolvableKeyValuePair resolvable = resolvableFields[i] = new ResolvableKeyValuePair(additionalFields[i]); + + // Validate + if (config == null && resolvable.valueNeedsLookup) { + throw new IllegalArgumentException( + "configuration needs to be set when there are additional fields with variables"); + } + } + + return resolvableFields; + } + protected static boolean valueNeedsLookup(final String value) { + return value != null && value.contains("${"); + } + protected final String eol; + protected final ObjectWriter objectWriter; + + protected final boolean compact; + + protected final boolean complete; + + protected final boolean includeNullDelimiter; + + protected final ResolvableKeyValuePair[] additionalFields; + + @Deprecated + protected AbstractJacksonLayout(final Configuration config, final ObjectWriter objectWriter, final Charset charset, + final boolean compact, final boolean complete, final boolean eventEol, final Serializer headerSerializer, + final Serializer footerSerializer) { + this(config, objectWriter, charset, compact, complete, eventEol, headerSerializer, footerSerializer, false); + } + + @Deprecated + protected AbstractJacksonLayout(final Configuration config, final ObjectWriter objectWriter, final Charset charset, + final boolean compact, final boolean complete, final boolean eventEol, final Serializer headerSerializer, + final Serializer footerSerializer, final boolean includeNullDelimiter) { + this(config, objectWriter, charset, compact, complete, eventEol, headerSerializer, footerSerializer, + includeNullDelimiter, null); + } + + protected AbstractJacksonLayout(final Configuration config, final ObjectWriter objectWriter, final Charset charset, + final boolean compact, final boolean complete, final boolean eventEol, final Serializer headerSerializer, + final Serializer footerSerializer, final boolean includeNullDelimiter, + final KeyValuePair[] additionalFields) { + super(config, charset, headerSerializer, footerSerializer); + this.objectWriter = objectWriter; + this.compact = compact; + this.complete = complete; + this.eol = compact && !eventEol ? COMPACT_EOL : DEFAULT_EOL; + this.includeNullDelimiter = includeNullDelimiter; + this.additionalFields = prepareAdditionalFields(config, additionalFields); + } + + protected LogEventWrapperWithAdditionalFields createLogEventWrapperWithAdditionalFields(final LogEvent event, + final Map additionalFieldsMap) { + return new LogEventWrapperWithAdditionalFields(event, additionalFieldsMap); + } + + private Map resolveAdditionalFields(final LogEvent logEvent) { + // Note: LinkedHashMap retains order + final Map additionalFieldsMap = new LinkedHashMap<>(additionalFields.length); + final StrSubstitutor strSubstitutor = configuration.getStrSubstitutor(); + + // Go over each field + for (final ResolvableKeyValuePair pair : additionalFields) { + if (pair.valueNeedsLookup) { + // Resolve value + additionalFieldsMap.put(pair.key, strSubstitutor.replace(logEvent, pair.value)); + } else { + // Plain text value + additionalFieldsMap.put(pair.key, pair.value); + } + } + + return additionalFieldsMap; + } + + /** + * Formats a {@link org.apache.logging.log4j.core.LogEvent}. + * + * @param event + * The LogEvent. + * @return The XML representation of the LogEvent. + */ + @Override + public String toSerializable(final LogEvent event) { + final StringBuilderWriter writer = new StringBuilderWriter(); + try { + toSerializable(event, writer); + return writer.toString(); + } catch (final IOException e) { + // Should this be an ISE or IAE? + LOGGER.error(e); + return Strings.EMPTY; + } + } + + public void toSerializable(final LogEvent event, final Writer writer) + throws JsonGenerationException, JsonMappingException, IOException { + objectWriter.writeValue(writer, wrapLogEvent(convertMutableToLog4jEvent(event))); + writer.write(eol); + if (includeNullDelimiter) { + writer.write('\0'); + } + markEvent(); + } + + protected Object wrapLogEvent(final LogEvent event) { + if (additionalFields.length > 0) { + // Construct map for serialization - note that we are intentionally using original LogEvent + final Map additionalFieldsMap = resolveAdditionalFields(event); + // This class combines LogEvent with AdditionalFields during serialization + return createLogEventWrapperWithAdditionalFields(event, additionalFieldsMap); + } + // No additional fields, return original object + return event; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/package-info.java b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/package-info.java similarity index 95% rename from log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/package-info.java rename to log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/package-info.java index 585da42b8a1..3b5c435fe9a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/package-info.java +++ b/log4j-layout-jackson/src/main/java/org/apache/logging/log4j/jackson/package-info.java @@ -18,4 +18,4 @@ * Classes and interfaces for serializing and deserializing Log4j 2 log events to XML and JSON using the Jackson * library. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; diff --git a/log4j-layout-jackson/src/site/manual/index.md b/log4j-layout-jackson/src/site/manual/index.md new file mode 100644 index 00000000000..b1d22b6bbfa --- /dev/null +++ b/log4j-layout-jackson/src/site/manual/index.md @@ -0,0 +1,33 @@ + + + +# Apache Log4j Layout for Jackson module + +As of Log4j 3.0.0, common code for layouts based on Jackson have moved from the existing module logj-core to the new modules log4j-layout-jackson. + +## Requirements + +This module was introduced in Log4j 2.11.0 and requires Jackson. + +Some features may require optional +[dependencies](../runtime-dependencies.html). These dependencies are specified in the +documentation for those features. + +Some Log4j features require external dependencies. +See the [Dependency Tree](dependencies.html#Dependency_Tree) +for the exact list of JAR files needed for these features. diff --git a/log4j-layout-jackson/src/site/site.xml b/log4j-layout-jackson/src/site/site.xml new file mode 100644 index 00000000000..6d4cddc0b14 --- /dev/null +++ b/log4j-layout-jackson/src/site/site.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInTest.java b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/AbstractMarkerMixInTest.java similarity index 95% rename from log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInTest.java rename to log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/AbstractMarkerMixInTest.java index d8bbae8088f..acfae965489 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/MarkerMixInTest.java +++ b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/AbstractMarkerMixInTest.java @@ -14,29 +14,34 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j; +package org.apache.logging.log4j.jackson; import java.io.IOException; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.ObjectWriter; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.MarkerManager.Log4jMarker; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.ObjectWriter; + /** * Tests {@link MarkerMixIn}. * * This class is in this package to let {@link Log4jMarker} have the least visibility. */ -public abstract class MarkerMixInTest { +public abstract class AbstractMarkerMixInTest { private ObjectReader reader; private ObjectWriter writer; + protected abstract ObjectMapper newObjectMapper(); + @Before public void setUp() { final ObjectMapper log4jObjectMapper = newObjectMapper(); @@ -45,8 +50,6 @@ public void setUp() { MarkerManager.clear(); } - protected abstract ObjectMapper newObjectMapper(); - @Test public void testNameOnly() throws IOException { final Marker expected = MarkerManager.getMarker("A"); @@ -67,17 +70,6 @@ public void testOneParent() throws IOException { Assert.assertEquals(expected, actual); } - /** - * @param expected - * @return - * @throws JsonProcessingException - */ - private String writeValueAsString(final Marker expected) throws JsonProcessingException { - final String str = writer.writeValueAsString(expected); - // System.out.println(str); - return str; - } - @Test public void testTwoParents() throws IOException { final Marker expected = MarkerManager.getMarker("A"); @@ -91,4 +83,15 @@ public void testTwoParents() throws IOException { final Marker actual = reader.readValue(str); Assert.assertEquals(expected, actual); } + + /** + * @param expected + * @return + * @throws JsonProcessingException + */ + private String writeValueAsString(final Marker expected) throws JsonProcessingException { + final String str = writer.writeValueAsString(expected); + // System.out.println(str); + return str; + } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInTest.java b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/LevelMixInTest.java similarity index 98% rename from log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInTest.java rename to log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/LevelMixInTest.java index acff4b422a1..0cdcb365cea 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/jackson/LevelMixInTest.java +++ b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/LevelMixInTest.java @@ -14,7 +14,7 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.core.jackson; +package org.apache.logging.log4j.jackson; import java.io.IOException; @@ -23,12 +23,12 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.experimental.categories.Category; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectWriter; -import org.junit.experimental.categories.Category; /** * Tests {@link LevelMixIn}. @@ -76,6 +76,8 @@ public int hashCode() { private ObjectWriter writer; + protected abstract ObjectMapper newObjectMapper(); + @Before public void setUp() { log4jObjectMapper = newObjectMapper(); @@ -83,8 +85,6 @@ public void setUp() { reader = log4jObjectMapper.readerFor(Level.class); } - protected abstract ObjectMapper newObjectMapper(); - @Test public void testContainer() throws IOException { final Fixture expected = new Fixture(); diff --git a/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java new file mode 100644 index 00000000000..ee077118071 --- /dev/null +++ b/log4j-layout-jackson/src/test/java/org/apache/logging/log4j/jackson/ThrowableProxyJacksonTest.java @@ -0,0 +1,51 @@ +/* + * 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.jackson; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.apache.logging.log4j.core.impl.ThrowableProxy; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * + */ +public class ThrowableProxyJacksonTest { + + static class Fixture { + @JsonProperty + ThrowableProxy proxy = new ThrowableProxy(new IOException("test")); + } + + protected void testIoContainer(final ObjectMapper objectMapper) throws IOException { + final Fixture expected = new Fixture(); + final String s = objectMapper.writeValueAsString(expected); + final Fixture actual = objectMapper.readValue(s, Fixture.class); + assertEquals(expected.proxy.getName(), actual.proxy.getName()); + assertEquals(expected.proxy.getMessage(), actual.proxy.getMessage()); + assertEquals(expected.proxy.getLocalizedMessage(), actual.proxy.getLocalizedMessage()); + assertEquals(expected.proxy.getCommonElementCount(), actual.proxy.getCommonElementCount()); + assertArrayEquals(expected.proxy.getExtendedStackTrace(), actual.proxy.getExtendedStackTrace()); + assertEquals(expected.proxy, actual.proxy); + } + +} diff --git a/pom.xml b/pom.xml index 2c8f327be80..ff8c1b9ed7d 100644 --- a/pom.xml +++ b/pom.xml @@ -1341,6 +1341,10 @@ log4j-api log4j-core-java9 log4j-core + log4j-layout-jackson + log4j-layout-jackson-json + log4j-layout-jackson-xml + log4j-layout-jackson-yaml log4j-core-its log4j-1.2-api log4j-slf4j-impl diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d3f9420d1d8..edb22bc0e71 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -61,6 +61,9 @@ org.apache.logging.log4j.core.lookup.EnvironmentLookup may throw NPE. + + Move Jackson-based layouts to their own modules: JSON, XML, and YAML. + From dbfedf7dbd89e189ac264beb9a0400fe6c3680d3 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 19 Feb 2018 19:14:44 -0700 Subject: [PATCH 0059/2347] [LOG4J2-2082] Update Apache Flume from 1.7.0 to 1.8.0. --- pom.xml | 2 +- src/changes/changes.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ff8c1b9ed7d..b5f0a4765dd 100644 --- a/pom.xml +++ b/pom.xml @@ -183,7 +183,7 @@ 1.9.13 2.9.4 3.2.18.RELEASE - 1.7.0 + 1.8.0 3.3.7 1.2.10 2.14.3 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index edb22bc0e71..c279e0188ca 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -64,6 +64,9 @@ Move Jackson-based layouts to their own modules: JSON, XML, and YAML. + + Update Apache Flume from 1.7.0 to 1.8.0. + From 233d9e230338f884c93b86ce88ebb580df335b2b Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 19 Feb 2018 22:53:32 -0700 Subject: [PATCH 0060/2347] [LOG4J2-2079] Update Conversant Disruptor from 1.12.10 to 1.12.11. --- log4j-core-its/pom.xml | 1 - log4j-core/pom.xml | 1 - log4j-perf/pom.xml | 1 - pom.xml | 6 ++---- src/changes/changes.xml | 3 +++ 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/log4j-core-its/pom.xml b/log4j-core-its/pom.xml index 513fce383aa..fc258183d29 100644 --- a/log4j-core-its/pom.xml +++ b/log4j-core-its/pom.xml @@ -83,7 +83,6 @@ com.conversantmedia disruptor - jdk7 true diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 196e4e55e49..b0813d4309c 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -61,7 +61,6 @@ com.conversantmedia disruptor - jdk7 true diff --git a/log4j-perf/pom.xml b/log4j-perf/pom.xml index 02e3162780d..3fb9af972b9 100644 --- a/log4j-perf/pom.xml +++ b/log4j-perf/pom.xml @@ -103,7 +103,6 @@ com.conversantmedia disruptor - jdk7 org.jctools diff --git a/pom.xml b/pom.xml index b5f0a4765dd..82218cfe779 100644 --- a/pom.xml +++ b/pom.xml @@ -183,9 +183,9 @@ 1.9.13 2.9.4 3.2.18.RELEASE - 1.8.0 + 1.8.0 3.3.7 - 1.2.10 + 1.2.11 2.14.3 3.6.1 3.7.0 @@ -627,8 +627,6 @@ com.conversantmedia disruptor ${conversantDisruptorVersion} - - jdk7 org.jctools diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c279e0188ca..50e621e97ee 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -67,6 +67,9 @@ Update Apache Flume from 1.7.0 to 1.8.0. + + Update Conversant Disruptor from 1.12.10 to 1.12.11. + From 46129b61bb07b6f4c57689d13ea197a919726aad Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 19 Feb 2018 22:58:55 -0700 Subject: [PATCH 0061/2347] Update HttpAppenderTest from Wiremock 2.14.0 to 2.15.0. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 82218cfe779..b3abcddc042 100644 --- a/pom.xml +++ b/pom.xml @@ -783,7 +783,7 @@ com.github.tomakehurst wiremock test - 2.14.0 + 2.15.0 From 7be2a2849e563cea241916449a8dae4e1d35e42d Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 19 Feb 2018 23:31:58 -0700 Subject: [PATCH 0062/2347] [LOG4J2-2258] Update LMAX Disruptor from 3.3.7 to 3.3.8. --- pom.xml | 2 +- src/changes/changes.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b3abcddc042..efccb368025 100644 --- a/pom.xml +++ b/pom.xml @@ -184,7 +184,7 @@ 2.9.4 3.2.18.RELEASE 1.8.0 - 3.3.7 + 3.3.8 1.2.11 2.14.3 3.6.1 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 50e621e97ee..2e7ed2dc43a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -70,6 +70,9 @@ Update Conversant Disruptor from 1.12.10 to 1.12.11. + + Update LMAX Disruptor from 3.3.7 to 3.3.8. + From 53889cbf0f6b8b8c784323887628773019742208 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 19 Feb 2018 23:36:49 -0700 Subject: [PATCH 0063/2347] [LOG4J2-2083] Update Eclipse javax.persistence from 2.1.1 to 2.2.0. --- pom.xml | 2 +- src/changes/changes.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index efccb368025..d93c578c380 100644 --- a/pom.xml +++ b/pom.xml @@ -221,7 +221,7 @@ Site Documentation 1.2 - 2.1.1 + 2.2.0 6.0.0 5.14.5 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 2e7ed2dc43a..00521890f83 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -73,6 +73,9 @@ Update LMAX Disruptor from 3.3.7 to 3.3.8. + + Update Eclipse javax.persistence from 2.1.1 to 2.2.0. + From d6099e19d3e9d35d8cb5c43fa2afe266ec8104f9 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Mon, 19 Feb 2018 23:38:17 -0700 Subject: [PATCH 0064/2347] [LOG4J2-2083] Update build to expect Java 8 sources and generate Java 8 byte codes. --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 00521890f83..349f0cd94c0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -76,6 +76,9 @@ Update Eclipse javax.persistence from 2.1.1 to 2.2.0. + + Update build to expect Java 8 sources and generate Java 8 byte codes. + From 038c8586134dd4450485aa22dcfa797bbd703fe6 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 07:24:08 -0700 Subject: [PATCH 0065/2347] Update MongoDB tests from Maven plugin de.flapdoodle.embed.mongo 2.0.1 to 2.0.3. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d93c578c380..9d52bf29c25 100644 --- a/pom.xml +++ b/pom.xml @@ -828,7 +828,7 @@ de.flapdoodle.embed de.flapdoodle.embed.mongo - 2.0.1 + 2.0.3 test From b738b99eecafff9fc5efb9d90181e6d4ab9fd6a2 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 07:59:58 -0700 Subject: [PATCH 0066/2347] [LOG4J2-2259] Update MongoDB 3 module from driver 3.6.1 to 3.6.3. --- pom.xml | 2 +- src/changes/changes.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9d52bf29c25..aba849b28e0 100644 --- a/pom.xml +++ b/pom.xml @@ -187,7 +187,7 @@ 3.3.8 1.2.11 2.14.3 - 3.6.1 + 3.6.3 3.7.0 3.8 3.1.0-RC7 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 349f0cd94c0..c3c80b1440e 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -79,6 +79,9 @@ Update build to expect Java 8 sources and generate Java 8 byte codes. + + Update MongoDB 3 module from driver 3.6.1 to 3.6.3. + From 49031a563812916334a4fa0078151b97a94be298 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 08:53:28 -0700 Subject: [PATCH 0067/2347] [LOG4J2-2260] [SMTP] Update javax.mail from 1.6.0 to 1.6.1. --- pom.xml | 2 +- src/changes/changes.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aba849b28e0..e8f05b6062a 100644 --- a/pom.xml +++ b/pom.xml @@ -589,7 +589,7 @@ com.sun.mail javax.mail - 1.6.0 + 1.6.1 org.jboss.spec.javax.jms diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c3c80b1440e..27e4d1b8509 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -82,6 +82,9 @@ Update MongoDB 3 module from driver 3.6.1 to 3.6.3. + + [SMTP] Update javax.mail from 1.6.0 to 1.6.1. + From f87466976326a2ff930673fb297f07448fa45f2b Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 08:58:13 -0700 Subject: [PATCH 0068/2347] Update release notes from 2.11.0. --- src/changes/changes.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 27e4d1b8509..9ccb40208f0 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -239,6 +239,12 @@ Update Apache Commons Compress from 1.15 to 1.16.1. + + Update MongoDB 3 module from driver 3.6.1 to 3.6.3. + + + [SMTP] Update javax.mail from 1.6.0 to 1.6.1. + From 2e8ac7a8bfe51b4c0363c2bc254e10e3462700aa Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 09:01:55 -0700 Subject: [PATCH 0069/2347] [LOG4J2-2261] Update JMS tests from Apache ActiveMQ 5.14.5 (Java 7) to 5.15.3 (Java 8.) --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e8f05b6062a..b91193dd30b 100644 --- a/pom.xml +++ b/pom.xml @@ -223,8 +223,7 @@ 1.2 2.2.0 6.0.0 - - 5.14.5 + 5.15.3 info 1.2.1 From 28128128fc12084546d7e6e230617ca8e586a6da Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 09:05:44 -0700 Subject: [PATCH 0070/2347] Update GelfLayout from Json-Unit 1.28.1 to 1.28.2. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b91193dd30b..1dd44dbbf95 100644 --- a/pom.xml +++ b/pom.xml @@ -756,7 +756,7 @@ net.javacrumbs.json-unit json-unit - 1.28.1 + 1.28.2 test From 190136c61126cabad23cb6c453bd372f920d14e0 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 09:13:09 -0700 Subject: [PATCH 0071/2347] [LOG4J2-2262] Update JDBC and JPA tests from hsqldb 2.3.5 (Java 7) to 2.4.0 (Javav 8.) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1dd44dbbf95..07cccf6dfe8 100644 --- a/pom.xml +++ b/pom.xml @@ -715,7 +715,7 @@ org.eclipse.persistence org.eclipse.persistence.jpa - 2.6.5 + 2.7.1 org.eclipse.persistence From 60e96d7c1e3720cc1b21057a2d03e82a61055eef Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 09:22:36 -0700 Subject: [PATCH 0072/2347] [LOG4J2-2262] Update JDBC and JPA tests from hsqldb 2.3.5 (Java 7) to 2.4.0 (Java 8.) --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 07cccf6dfe8..e1ee3d2ce99 100644 --- a/pom.xml +++ b/pom.xml @@ -704,8 +704,7 @@ org.hsqldb hsqldb - 2.3.5 - + 2.4.0 com.h2database From ae7f1256ca5bfcf923f790a5ef78bad9298e5a18 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Feb 2018 09:31:56 -0700 Subject: [PATCH 0073/2347] [LOG4J2-2264] Update JAnsi from 1.16 to 1.17. --- pom.xml | 2 +- src/changes/changes.xml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e1ee3d2ce99..d8b8675ada7 100644 --- a/pom.xml +++ b/pom.xml @@ -404,7 +404,7 @@ org.fusesource.jansi jansi - 1.16 + 1.17 true diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 9ccb40208f0..3b5d1d560e6 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -245,6 +245,9 @@ [SMTP] Update javax.mail from 1.6.0 to 1.6.1. + + Update JAnsi from 1.16 to 1.17. + @@ -377,6 +380,9 @@ Jackson dependencies for 2.9.2 incorrectly bring in jackson-annotations 2.9.0 instead of 2.9.2. + + Update JAnsi from 1.16 to 1.17. + From b562b07177efb0f4b7f3bf5b55c2b123414f6743 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 25 Feb 2018 11:05:08 -0700 Subject: [PATCH 0074/2347] [LOG4J2-2270] Strings::join, when called with [null] returns "null" instead of EMPTY. I implemented a different fix than the one proposed in the PR. --- .../apache/logging/log4j/util/Strings.java | 2 +- .../logging/log4j/util/StringsTest.java | 19 +++++++++++++++++++ src/changes/changes.xml | 5 ++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java index f6608d61f65..c369a4ee51e 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java @@ -216,7 +216,7 @@ public static String join(final Iterator iterator, final char separator) { } final Object first = iterator.next(); if (!iterator.hasNext()) { - return Objects.toString(first); + return Objects.toString(first, EMPTY); } // two or more elements diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java index d5167391d21..162d1621fa4 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java @@ -20,6 +20,9 @@ import org.junit.Assert; import org.junit.Test; +import java.util.Arrays; +import java.util.Iterator; + public class StringsTest { /** @@ -31,6 +34,22 @@ public void testEMPTY() { Assert.assertEquals(0, Strings.EMPTY.length()); } + @Test + public void testJoin() { + Assert.assertEquals(null, Strings.join((Iterable) null, '.')); + Assert.assertEquals(null, Strings.join((Iterator) null, '.')); + Assert.assertEquals("", Strings.join((Arrays.asList()), '.')); + + Assert.assertEquals("a", Strings.join(Arrays.asList("a"), '.')); + Assert.assertEquals("a.b", Strings.join(Arrays.asList("a", "b"), '.')); + Assert.assertEquals("a.b.c", Strings.join(Arrays.asList("a", "b", "c"), '.')); + + Assert.assertEquals("", Strings.join(Arrays.asList((String) null), ':')); + Assert.assertEquals(":", Strings.join(Arrays.asList(null, null), ':')); + Assert.assertEquals("a:", Strings.join(Arrays.asList("a", null), ':')); + Assert.assertEquals(":b", Strings.join(Arrays.asList(null, "b"), ':')); + } + @Test public void testQuote() { Assert.assertEquals("'Q'", Strings.quote("Q")); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 3b5d1d560e6..f0a538aaa1c 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -58,7 +58,7 @@ Move JDBC code to a new module log4j-jdbc. - + org.apache.logging.log4j.core.lookup.EnvironmentLookup may throw NPE. @@ -85,6 +85,9 @@ [SMTP] Update javax.mail from 1.6.0 to 1.6.1. + + Strings::join, when called with [null] returns "null" instead of EMPTY. + From 0b222b7f2366b7d38e303d1a36f424e814bfcbf5 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sun, 25 Feb 2018 11:05:39 -0700 Subject: [PATCH 0075/2347] [LOG4J2-2270] Strings::join, when called with [null] returns "null" instead of EMPTY. I implemented a different fix than the one proposed in the PR. --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f0a538aaa1c..ae9015cb337 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -251,6 +251,9 @@ Update JAnsi from 1.16 to 1.17. + + Strings::join, when called with [null] returns "null" instead of EMPTY. + From 33fe01a2ada89fccd3165e33b172163eb0c58b58 Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sun, 25 Feb 2018 21:17:08 -0700 Subject: [PATCH 0076/2347] LOG4J2-2271 - Move module-info.class to META-INF/versions/9 directory. --- log4j-api-java9/src/assembly/java9.xml | 8 -------- src/changes/changes.xml | 3 +++ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/log4j-api-java9/src/assembly/java9.xml b/log4j-api-java9/src/assembly/java9.xml index 3e595612db4..41a0da0699d 100644 --- a/log4j-api-java9/src/assembly/java9.xml +++ b/log4j-api-java9/src/assembly/java9.xml @@ -32,7 +32,6 @@ **/*.class - module-info.class **/Dummy.class **/spi/Provider.class **/util/PropertySource.class @@ -40,12 +39,5 @@ **/message/ThreadDumpMessage$ThreadInfoFactory.class - - ${project.build.outputDirectory} - /classes - - module-info.class - - diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ae9015cb337..3f964969573 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -90,6 +90,9 @@ + + Move module-info.class to META-INF/versions/9 directory. + Incorrect automatics module name header was being included in manifests. From 967bb0f71155aa00acadbd95362a90832bed69f6 Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Tue, 13 Feb 2018 11:28:17 -0500 Subject: [PATCH 0077/2347] LOG4J2-2252 Reusable LogEvents should pass along the original format string This allows custom layouts to group logged messages parameterized values without creating new single-use messages for each event. This slightly modifies the getFormat implementation of some message types to avoid doing unnecessary work to load the format string. --- .../log4j/message/ReusableObjectMessage.java | 2 +- .../log4j/message/ReusableSimpleMessage.java | 2 +- .../logging/log4j/message/SimpleMessage.java | 5 ++-- .../message/ReusableObjectMessageTest.java | 4 +-- .../message/ReusableSimpleMessageTest.java | 2 +- .../log4j/core/async/RingBufferLogEvent.java | 5 +++- .../log4j/core/impl/MutableLogEvent.java | 5 +++- .../log4j/core/impl/MutableLogEventTest.java | 28 +++++++++++++++++++ 8 files changed, 44 insertions(+), 9 deletions(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java index c4ffa22c105..ff2d58f02f8 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java @@ -55,7 +55,7 @@ public void formatTo(final StringBuilder buffer) { */ @Override public String getFormat() { - return getFormattedMessage(); + return obj instanceof String ? (String) obj : null; } /** diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java index 905b694d30e..90c8bc0bd98 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java @@ -43,7 +43,7 @@ public String getFormattedMessage() { @Override public String getFormat() { - return getFormattedMessage(); + return charSequence instanceof String ? (String) charSequence : null; } @Override diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java index 8a2fc7219ea..d33f3b9bfdc 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/SimpleMessage.java @@ -16,10 +16,11 @@ */ package org.apache.logging.log4j.message; +import org.apache.logging.log4j.util.StringBuilderFormattable; + import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import org.apache.logging.log4j.util.StringBuilderFormattable; /** * The simplest possible implementation of Message. It just returns the String given as the constructor argument. @@ -75,7 +76,7 @@ public void formatTo(final StringBuilder buffer) { */ @Override public String getFormat() { - return getFormattedMessage(); + return message; } /** diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableObjectMessageTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableObjectMessageTest.java index d4f87a7dd8e..614d54c08cc 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableObjectMessageTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableObjectMessageTest.java @@ -49,8 +49,8 @@ public void testGetFormattedMessage_ReturnsLatestSetString() throws Exception { } @Test - public void testGetFormat_InitiallyNullString() throws Exception { - assertEquals("null", new ReusableObjectMessage().getFormat()); + public void testGetFormat_InitiallyNull() throws Exception { + assertNull(new ReusableObjectMessage().getFormat()); } @Test diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableSimpleMessageTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableSimpleMessageTest.java index 3a56b643175..1070a532cb4 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableSimpleMessageTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableSimpleMessageTest.java @@ -50,7 +50,7 @@ public void testGetFormattedMessage_ReturnsLatestSetString() throws Exception { @Test public void testGetFormat_InitiallyStringNull() throws Exception { - assertEquals("null", new ReusableSimpleMessage().getFormat()); + assertNull(new ReusableSimpleMessage().getFormat()); } @Test diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java index 0a2964df412..b18a3753e17 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java @@ -83,6 +83,7 @@ public RingBufferLogEvent newInstance() { private String threadName; private String loggerName; private Message message; + private String messageFormat; private StringBuilder messageText; private Object[] parameters; private transient Throwable thrown; @@ -135,6 +136,7 @@ private void setMessage(final Message msg) { if (msg instanceof ReusableMessage) { final ReusableMessage reusable = (ReusableMessage) msg; reusable.formatTo(getMessageTextForWriting()); + messageFormat = reusable.getFormat(); if (parameters != null) { parameters = reusable.swapParameters(parameters); parameterCount = reusable.getParameterCount(); @@ -235,7 +237,7 @@ public String getFormattedMessage() { */ @Override public String getFormat() { - return null; + return messageFormat; } /** @@ -402,6 +404,7 @@ public void clear() { this.fqcn = null; this.level = null; this.message = null; + this.messageFormat = null; this.thrown = null; this.thrownProxy = null; this.contextStack = null; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java index b427c4a272d..52688bc303a 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java @@ -56,6 +56,7 @@ public class MutableLogEvent implements LogEvent, ReusableMessage { private String threadName; private String loggerName; private Message message; + private String messageFormat; private StringBuilder messageText; private Object[] parameters; private Throwable thrown; @@ -126,6 +127,7 @@ public void clear() { level = null; loggerName = null; message = null; + messageFormat = null; thrown = null; thrownProxy = null; source = null; @@ -211,6 +213,7 @@ public void setMessage(final Message msg) { if (msg instanceof ReusableMessage) { final ReusableMessage reusable = (ReusableMessage) msg; reusable.formatTo(getMessageTextForWriting()); + this.messageFormat = msg.getFormat(); if (parameters != null) { parameters = reusable.swapParameters(parameters); parameterCount = reusable.getParameterCount(); @@ -243,7 +246,7 @@ public String getFormattedMessage() { */ @Override public String getFormat() { - return null; + return messageFormat; } /** diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java index 1e4c8ccdf41..2bee6fb573e 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java @@ -28,7 +28,9 @@ import org.apache.logging.log4j.MarkerManager; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ParameterizedMessage; +import org.apache.logging.log4j.message.ReusableMessageFactory; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.SortedArrayStringMap; @@ -112,6 +114,32 @@ public void testInitFromCopiesAllFields() { assertEquals("millis", source.getTimeMillis(), mutable.getTimeMillis()); } + @Test + public void testInitFromReusableCopiesFormatString() { + Message message = ReusableMessageFactory.INSTANCE.newMessage("msg in a {}", "bottle"); + final Log4jLogEvent source = Log4jLogEvent.newBuilder() // + .setContextData(CONTEXT_DATA) // + .setContextStack(STACK) // + .setEndOfBatch(true) // + .setIncludeLocation(true) // + .setLevel(Level.FATAL) // + .setLoggerFqcn("a.b.c.d.e") // + .setLoggerName("my name is Logger") // + .setMarker(MarkerManager.getMarker("on your marks")) // + .setMessage(message) // + .setNanoTime(1234567) // + .setSource(new StackTraceElement("myclass", "mymethod", "myfile", 123)) // + .setThreadId(100).setThreadName("threadname").setThreadPriority(10) // + .setThrown(new RuntimeException("run")) // + .setTimeMillis(987654321) + .build(); + final MutableLogEvent mutable = new MutableLogEvent(); + mutable.initFrom(source); + assertEquals("format", "msg in a {}", mutable.getFormat()); + assertEquals("formatted", "msg in a bottle", mutable.getFormattedMessage()); + assertEquals("parameters", new String[] {"bottle"}, mutable.getParameters()); + } + @Test public void testClear() { final MutableLogEvent mutable = new MutableLogEvent(); From 41648dfa16a7176860e3af30b483e85775c48b9d Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Wed, 14 Feb 2018 14:48:00 -0500 Subject: [PATCH 0078/2347] LOG4J2-2253 Added ParameterVisitableMessage.forEachParameter This method allows us to iterate over parameters in a ParameterVisitableMessage without array creation. --- .../log4j/message/ParameterConsumer.java | 26 ++++++++++++++++ .../message/ParameterVisitableMessage.java | 30 +++++++++++++++++++ .../log4j/message/ReusableObjectMessage.java | 7 ++++- .../message/ReusableParameterizedMessage.java | 10 ++++++- .../log4j/message/ReusableSimpleMessage.java | 6 +++- .../ReusableParameterizedMessageTest.java | 22 ++++++++++++++ .../log4j/core/async/RingBufferLogEvent.java | 17 +++++++---- .../log4j/core/impl/MutableLogEvent.java | 11 ++++++- .../core/async/RingBufferLogEventTest.java | 12 ++++++++ 9 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java create mode 100644 log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java new file mode 100644 index 00000000000..ff8c148e112 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java @@ -0,0 +1,26 @@ +package org.apache.logging.log4j.message; + +/** + * An operation that accepts two input arguments and returns no result. + * + *

    + * The third parameter lets callers pass in a stateful object to be modified with the key-value pairs, + * so the ParameterConsumer implementation itself can be stateless and potentially reusable. + *

    + * + * @param state data + * @see ReusableMessage + * @since 2.11 + */ +public interface ParameterConsumer { + + /** + * Performs an operation given the specified arguments. + * + * @param parameter the parameter + * @param parameterIndex Index of the parameter + * @param state + */ + void accept(Object parameter, short parameterIndex, S state); + +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java new file mode 100644 index 00000000000..5cb62283992 --- /dev/null +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java @@ -0,0 +1,30 @@ +package org.apache.logging.log4j.message; + +import org.apache.logging.log4j.util.PerformanceSensitive; + +/** + * Allows message parameters to be iterated over without any allocation + * or memory copies. + * + * @since 2.11 + */ +@PerformanceSensitive("allocation") +public interface ParameterVisitableMessage extends Message { + + /** + * Performs the given action for each parameter until all values + * have been processed or the action throws an exception. + *

    + * The second parameter lets callers pass in a stateful object to be modified with the key-value pairs, + * so the TriConsumer implementation itself can be stateless and potentially reusable. + *

    + * + * @param action The action to be performed for each key-value pair in this collection + * @param state the object to be passed as the third parameter to each invocation on the + * specified ParameterConsumer. + * @param type of the third parameter + * @since 2.11 + */ + void forEachParameter(ParameterConsumer action, S state); + +} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java index c4ffa22c105..603381f31d5 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java @@ -24,7 +24,7 @@ * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableObjectMessage implements ReusableMessage { +public class ReusableObjectMessage implements ReusableMessage, ParameterVisitableMessage { private static final long serialVersionUID = 6922476812535519960L; private transient Object obj; @@ -112,6 +112,11 @@ public short getParameterCount() { return 0; } + @Override + public void forEachParameter(ParameterConsumer action, S state) { + action.accept(obj, (short) 0, state); + } + @Override public Message memento() { return new ObjectMessage(obj); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java index daf299482c8..55a079cc8f4 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java @@ -30,7 +30,7 @@ * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableParameterizedMessage implements ReusableMessage { +public class ReusableParameterizedMessage implements ReusableMessage, ParameterVisitableMessage { private static final int MIN_BUILDER_SIZE = 512; private static final int MAX_PARMS = 10; @@ -104,6 +104,14 @@ public short getParameterCount() { return (short) argCount; } + @Override + public void forEachParameter(ParameterConsumer action, S state) { + Object[] parameters = getParams(); + for (short i = 0; i < argCount; i++) { + action.accept(parameters[i], i, state); + } + } + @Override public Message memento() { return new ParameterizedMessage(messagePattern, getTrimmedParams()); diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java index 905b694d30e..03c290ab579 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java @@ -23,7 +23,7 @@ * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableSimpleMessage implements ReusableMessage, CharSequence { +public class ReusableSimpleMessage implements ReusableMessage, CharSequence, ParameterVisitableMessage { private static final long serialVersionUID = -9199974506498249809L; private static Object[] EMPTY_PARAMS = new Object[0]; private CharSequence charSequence; @@ -80,6 +80,10 @@ public short getParameterCount() { return 0; } + @Override + public void forEachParameter(ParameterConsumer action, S state) { + } + @Override public Message memento() { return new SimpleMessage(charSequence); diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java index b25735c17af..38f157dce33 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java @@ -19,6 +19,9 @@ import org.apache.logging.log4j.junit.Mutable; import org.junit.Test; +import java.util.LinkedList; +import java.util.List; + import static org.junit.Assert.*; /** @@ -144,4 +147,23 @@ public void testThrowable() { msg.set(testMsg, "msgs", EXCEPTION2); assertSame(EXCEPTION2, msg.getThrowable()); } + + @Test + public void testParameterConsumer() { + final String testMsg = "Test message {}"; + final ReusableParameterizedMessage msg = new ReusableParameterizedMessage(); + final Throwable EXCEPTION1 = new IllegalAccessError("#1"); + msg.set(testMsg, "msg", EXCEPTION1); + List expected = new LinkedList<>(); + expected.add("msg"); + expected.add(EXCEPTION1); + final List actual = new LinkedList<>(); + msg.forEachParameter(new ParameterConsumer() { + @Override + public void accept(Object parameter, short parameterIndex, Void state) { + actual.add(parameter); + } + }, null); + assertEquals(expected, actual); + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java index 0a2964df412..4fee2efa776 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java @@ -32,11 +32,7 @@ import org.apache.logging.log4j.core.util.*; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.core.time.MutableInstant; -import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.message.ParameterizedMessage; -import org.apache.logging.log4j.message.ReusableMessage; -import org.apache.logging.log4j.message.SimpleMessage; -import org.apache.logging.log4j.message.TimestampMessage; +import org.apache.logging.log4j.message.*; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.apache.logging.log4j.util.StringBuilders; import org.apache.logging.log4j.util.StringMap; @@ -48,7 +44,7 @@ * When the Disruptor is started, the RingBuffer is populated with event objects. These objects are then re-used during * the life of the RingBuffer. */ -public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence { +public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence, ParameterVisitableMessage { /** The {@code EventFactory} for {@code RingBufferLogEvent}s. */ public static final Factory FACTORY = new Factory(); @@ -283,6 +279,15 @@ public short getParameterCount() { return parameterCount; } + @Override + public void forEachParameter(ParameterConsumer action, S state) { + if (parameters != null) { + for (short i = 0; i < parameterCount; i++) { + action.accept(parameters[i], i, state); + } + } + } + @Override public Message memento() { if (message != null) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java index b427c4a272d..b5993fe90b0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java @@ -42,7 +42,7 @@ * Mutable implementation of the {@code LogEvent} interface. * @since 2.6 */ -public class MutableLogEvent implements LogEvent, ReusableMessage { +public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisitableMessage { private static final Message EMPTY = new SimpleMessage(Strings.EMPTY); private int threadPriority; @@ -254,6 +254,15 @@ public Object[] getParameters() { return parameters == null ? null : Arrays.copyOf(parameters, parameterCount); } + @Override + public void forEachParameter(ParameterConsumer action, S state) { + if (parameters != null) { + for (short i = 0; i < parameterCount; i++) { + action.accept(parameters[i], i, state); + } + } + } + /** * @see ReusableMessage#getThrowable() */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java index cc50b425ca2..fdc03d45d4e 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java @@ -32,6 +32,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.time.internal.FixedPreciseClock; +import org.apache.logging.log4j.message.ParameterConsumer; import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.core.impl.ThrowableProxy; @@ -189,4 +190,15 @@ public void testMessageTextNeverThrowsNpe() { fail("the messageText field was not set"); } } + + @Test + public void testForEachParameterNothingSet() { + final RingBufferLogEvent evt = new RingBufferLogEvent(); + evt.forEachParameter(new ParameterConsumer() { + @Override + public void accept(Object parameter, short parameterIndex, Void state) { + fail("Should not have been called"); + } + }, null); + } } From 7060cc30761120e0adfae07bfe528c5b6cb0d697 Mon Sep 17 00:00:00 2001 From: rpopma Date: Mon, 26 Feb 2018 19:31:42 +0900 Subject: [PATCH 0079/2347] LOG4J2-2253 renamed ParameterVisitableMessage to ParameterVisitable --- .../{ParameterVisitableMessage.java => ParameterVisitable.java} | 2 +- .../org/apache/logging/log4j/message/ReusableObjectMessage.java | 2 +- .../logging/log4j/message/ReusableParameterizedMessage.java | 2 +- .../org/apache/logging/log4j/message/ReusableSimpleMessage.java | 2 +- .../org/apache/logging/log4j/core/async/RingBufferLogEvent.java | 2 +- .../org/apache/logging/log4j/core/impl/MutableLogEvent.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename log4j-api/src/main/java/org/apache/logging/log4j/message/{ParameterVisitableMessage.java => ParameterVisitable.java} (94%) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitable.java similarity index 94% rename from log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java rename to log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitable.java index 5cb62283992..31d8c5f8297 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitableMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterVisitable.java @@ -9,7 +9,7 @@ * @since 2.11 */ @PerformanceSensitive("allocation") -public interface ParameterVisitableMessage extends Message { +public interface ParameterVisitable { /** * Performs the given action for each parameter until all values diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java index b54224077c9..b973e5a34af 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java @@ -24,7 +24,7 @@ * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableObjectMessage implements ReusableMessage, ParameterVisitableMessage { +public class ReusableObjectMessage implements ReusableMessage, ParameterVisitable { private static final long serialVersionUID = 6922476812535519960L; private transient Object obj; diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java index 55a079cc8f4..a1431f85c42 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java @@ -30,7 +30,7 @@ * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableParameterizedMessage implements ReusableMessage, ParameterVisitableMessage { +public class ReusableParameterizedMessage implements ReusableMessage, ParameterVisitable { private static final int MIN_BUILDER_SIZE = 512; private static final int MAX_PARMS = 10; diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java index e5d8622fe45..49b0d7fde78 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableSimpleMessage.java @@ -23,7 +23,7 @@ * @since 2.6 */ @PerformanceSensitive("allocation") -public class ReusableSimpleMessage implements ReusableMessage, CharSequence, ParameterVisitableMessage { +public class ReusableSimpleMessage implements ReusableMessage, CharSequence, ParameterVisitable { private static final long serialVersionUID = -9199974506498249809L; private static Object[] EMPTY_PARAMS = new Object[0]; private CharSequence charSequence; diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java index 651186af9f2..27e719730f4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java @@ -44,7 +44,7 @@ * When the Disruptor is started, the RingBuffer is populated with event objects. These objects are then re-used during * the life of the RingBuffer. */ -public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence, ParameterVisitableMessage { +public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence, ParameterVisitable { /** The {@code EventFactory} for {@code RingBufferLogEvent}s. */ public static final Factory FACTORY = new Factory(); diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java index c5b4d4c93dd..ecabcbc32d4 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java @@ -42,7 +42,7 @@ * Mutable implementation of the {@code LogEvent} interface. * @since 2.6 */ -public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisitableMessage { +public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisitable { private static final Message EMPTY = new SimpleMessage(Strings.EMPTY); private int threadPriority; From 0bc29cc36ba66c13e8a97b27b187a13c2efdb9e8 Mon Sep 17 00:00:00 2001 From: rpopma Date: Mon, 26 Feb 2018 19:38:25 +0900 Subject: [PATCH 0080/2347] fix typo (cherry picked from commit d19496f) --- src/changes/changes.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 3f964969573..db9db2f6623 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -90,7 +90,7 @@ - + Move module-info.class to META-INF/versions/9 directory. From b712cb7b419e5d665ee4935101a947f933ab749d Mon Sep 17 00:00:00 2001 From: rpopma Date: Mon, 26 Feb 2018 19:42:22 +0900 Subject: [PATCH 0081/2347] LOG4J2-2253 (change log) Add API to enable iterating over message parameters without creating temporary objects Closes #150 (cherry picked from commit 73306cd) --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index db9db2f6623..10081d52fd4 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -90,6 +90,9 @@ + + Add API to enable iterating over message parameters without creating temporary objects. + Move module-info.class to META-INF/versions/9 directory. From c8261a5b1997c121f9416d693e60dac050c2719f Mon Sep 17 00:00:00 2001 From: "Bruno P. Kinoshita" Date: Tue, 27 Feb 2018 16:11:43 +1300 Subject: [PATCH 0082/2347] Fix typo in documentation Hello, found while updating a legacy project from log4j1 to log4j2, and reading the docs (which are great, by the way, a life saver. Thanks!) --- src/site/xdoc/manual/customconfig.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/xdoc/manual/customconfig.xml b/src/site/xdoc/manual/customconfig.xml index 8b1b8bdd6fe..e57af39415b 100644 --- a/src/site/xdoc/manual/customconfig.xml +++ b/src/site/xdoc/manual/customconfig.xml @@ -210,7 +210,7 @@ builder.add( builder.newLogger( "TestLogger", Level.DEBUG ) builder.add( builder.newRootLogger( Level.DEBUG ) .add( builder.newAppenderRef( "rolling" ) ) ); -LoggerContext ctx = Configurator.intitialize(builder.build()); +LoggerContext ctx = Configurator.initialize(builder.build()); ]]> From 5b5bd912043222b1b0c94683bcba98eede54c97c Mon Sep 17 00:00:00 2001 From: rpopma Date: Tue, 27 Feb 2018 12:17:43 +0900 Subject: [PATCH 0083/2347] LOG4J2-2252 (change log) Reusable LogEvents now pass the original format string to downstream components like layouts and filters. Closes #148 (cherry picked from commit e4d9b0d) --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 10081d52fd4..4e3cc99a3e5 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -90,6 +90,9 @@ + + Reusable LogEvents now pass the original format string to downstream components like layouts and filters. + Add API to enable iterating over message parameters without creating temporary objects. From 73191e1ccfd35e444634d3150fdaad029f1e10e9 Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Mon, 26 Feb 2018 21:39:12 -0800 Subject: [PATCH 0084/2347] LOG4J2-2253 Update ParameterConsumer index type from short to int Originally ParameterVisitable was built for ReusableMessage which provides a "short getParameterCount()" method. Now that the interface isn't bound to ReusableMessage it might as well use integer. --- .../org/apache/logging/log4j/message/ParameterConsumer.java | 2 +- .../org/apache/logging/log4j/message/ReusableObjectMessage.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java index ff8c148e112..8b81e1a4358 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ParameterConsumer.java @@ -21,6 +21,6 @@ public interface ParameterConsumer { * @param parameterIndex Index of the parameter * @param state */ - void accept(Object parameter, short parameterIndex, S state); + void accept(Object parameter, int parameterIndex, S state); } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java index b973e5a34af..c272ab78db7 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableObjectMessage.java @@ -114,7 +114,7 @@ public short getParameterCount() { @Override public void forEachParameter(ParameterConsumer action, S state) { - action.accept(obj, (short) 0, state); + action.accept(obj, 0, state); } @Override From 31c41c0c6d270402185f92289972a78ecdf62e17 Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Mon, 26 Feb 2018 21:46:10 -0800 Subject: [PATCH 0085/2347] LOG4J2-2253 Update tests Closes #156 Closes #157 --- .../logging/log4j/message/ReusableParameterizedMessageTest.java | 2 +- .../apache/logging/log4j/core/async/RingBufferLogEventTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java index 38f157dce33..d16beb327c9 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/message/ReusableParameterizedMessageTest.java @@ -160,7 +160,7 @@ public void testParameterConsumer() { final List actual = new LinkedList<>(); msg.forEachParameter(new ParameterConsumer() { @Override - public void accept(Object parameter, short parameterIndex, Void state) { + public void accept(Object parameter, int parameterIndex, Void state) { actual.add(parameter); } }, null); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java index fdc03d45d4e..1d349216488 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java @@ -196,7 +196,7 @@ public void testForEachParameterNothingSet() { final RingBufferLogEvent evt = new RingBufferLogEvent(); evt.forEachParameter(new ParameterConsumer() { @Override - public void accept(Object parameter, short parameterIndex, Void state) { + public void accept(Object parameter, int parameterIndex, Void state) { fail("Should not have been called"); } }, null); From 5b9957b926314a08af6944da15fc7ef73de3ed06 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 28 Feb 2018 17:22:53 -0700 Subject: [PATCH 0086/2347] [LOG4J2-2276] ConcurrentModificationException from org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:71). --- .../util/SystemPropertiesPropertySource.java | 19 ++++- .../SystemPropertiesPropertySourceTest.java | 74 +++++++++++++++++++ src/changes/changes.xml | 8 +- 3 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java index af10fb00c44..627b968b59a 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java @@ -16,7 +16,8 @@ */ package org.apache.logging.log4j.util; -import java.util.Map; +import java.util.Objects; +import java.util.Properties; /** * PropertySource backed by the current system properties. Other than having a higher priority over normal properties, @@ -26,17 +27,27 @@ */ public class SystemPropertiesPropertySource implements PropertySource { + private static final int DEFAULT_PRIORITY = 100; private static final String PREFIX = "log4j2."; @Override public int getPriority() { - return 100; + return DEFAULT_PRIORITY; } @Override public void forEach(final BiConsumer action) { - for (final Map.Entry entry : System.getProperties().entrySet()) { - action.accept(((String) entry.getKey()), ((String) entry.getValue())); + final Properties properties = System.getProperties(); + // Lock properties only long enough to get a thread-safe SAFE snapshot of its current keys, an array. + final Object[] keySet; + synchronized (properties) { + keySet = properties.keySet().toArray(); + } + // Then traverse for an unknown amount of time. + // Some keys may now be absent, in which case, the value is null. + for (final Object key : keySet) { + final String keyStr = Objects.toString(key, null); + action.accept(keyStr, properties.getProperty(keyStr)); } } diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java new file mode 100644 index 00000000000..8fa41c7619e --- /dev/null +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java @@ -0,0 +1,74 @@ +package org.apache.logging.log4j.util; + +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.junit.Test; + +/* + * 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. + */ + +/** + * Tests https://issues.apache.org/jira/browse/LOG4J2-2276. + */ +public class SystemPropertiesPropertySourceTest { + + private static final int ITERATIONS = 10000; + + /** + * Tests avoiding a ConcurrentModificationException. For example: + * + *
    +     * java.util.ConcurrentModificationException
    +     *  at java.util.Hashtable$Enumerator.next(Hashtable.java:1167)
    +     *  at org.apache.logging.log4j.util.SystemPropertiesPropertySource.forEach(SystemPropertiesPropertySource.java:38)
    +     *  at org.apache.logging.log4j.util.SystemPropertiesPropertySourceTest.testMultiThreadedAccess(SystemPropertiesPropertySourceTest.java:47)
    +     * 
    + * @throws InterruptedException + * @throws ExecutionException + */ + @Test + public void testMultiThreadedAccess() throws InterruptedException, ExecutionException { + ExecutorService threadPool = Executors.newSingleThreadExecutor(); + try { + Future future = threadPool.submit(new Runnable() { + + @Override + public void run() { + final Properties properties = System.getProperties(); + for (int i = 0; i < ITERATIONS; i++) { + properties.setProperty("FOO_" + i, "BAR"); + } + } + }); + for (int i = 0; i < ITERATIONS; i++) + new SystemPropertiesPropertySource().forEach(new BiConsumer() { + @Override + public void accept(final String key, final String value) { + // nothing + } + }); + future.get(); + } finally { + threadPool.shutdown(); + } + } + +} diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 63183b67d0d..4a9ec5b64e6 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -87,6 +87,9 @@ Strings::join, when called with [null] returns "null" instead of EMPTY. + + + ConcurrentModificationException from org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:71). @@ -265,7 +268,10 @@ Strings::join, when called with [null] returns "null" instead of EMPTY. - + + + ConcurrentModificationException from org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:71). + From 3795f16769b4ebe33b37c6543fe5f6a2e8d53243 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Wed, 28 Feb 2018 17:33:27 -0700 Subject: [PATCH 0087/2347] Update @since tags for 2.11.0 since there will not be a 2.10.1. --- .../logging/log4j/core/appender/db/AbstractDatabaseManager.java | 2 +- .../apache/logging/log4j/core/appender/nosql/NoSqlAppender.java | 2 +- .../logging/log4j/core/pattern/EndOfBatchPatternConverter.java | 2 +- .../logging/log4j/core/pattern/LoggerFqcnPatternConverter.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java index 7624c5e82c8..0350543ffc6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java @@ -185,7 +185,7 @@ public final synchronized void flush() { * This method manages buffering and writing of events. * * @param event The event to write to the database. - * @deprecated since 2.10.1 Use {@link #write(LogEvent, Serializable)}. + * @deprecated since 2.11.0 Use {@link #write(LogEvent, Serializable)}. */ @Deprecated public final synchronized void write(final LogEvent event) { diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java index aae28ffaaf4..0d23a2ac22c 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/nosql/NoSqlAppender.java @@ -123,7 +123,7 @@ public B setProvider(NoSqlProvider provider) { * @param provider * The NoSQL provider that provides connections to the chosen NoSQL database. * @return a new NoSQL appender. - * @deprecated since 2.10.1; use {@link Builder}. + * @deprecated since 2.11.0; use {@link Builder}. */ @SuppressWarnings("resource") @Deprecated diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverter.java index a2f95fde1a0..bf627680fb5 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/EndOfBatchPatternConverter.java @@ -23,7 +23,7 @@ /** * Formats the EndOfBatch. * - * @since 2.10.1 + * @since 2.11.0 */ @Plugin(name = "EndOfBatchPatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "endOfBatch" }) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverter.java index 9eb429606b7..cba32c96180 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverter.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/LoggerFqcnPatternConverter.java @@ -23,7 +23,7 @@ /** * Formats the Logger FQCN. * - * @since 2.10.1 + * @since 2.11.0 */ @Plugin(name = "LoggerFqcnPatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "fqcn" }) From f2789da8f5a441718bfb56be8d90870cad628dbe Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 08:32:05 -0700 Subject: [PATCH 0088/2347] [LOG4J2-2274] Allow EnvironmentPropertySource to run with a SecurityManager that rejects environment variable access. --- .../log4j/util/EnvironmentPropertySource.java | 25 ++++-- ...mentPropertySourceSecurityManagerTest.java | 76 +++++++++++++++++++ src/changes/changes.xml | 6 ++ 3 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java index af8c23e20fa..40aa76bb16f 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java @@ -19,24 +19,35 @@ import java.util.Map; /** - * PropertySource implementation that uses environment variables as a source. All environment variables must begin - * with {@code LOG4J_} so as not to conflict with other variables. Normalized environment variables follow a scheme - * like this: {@code log4j2.fooBarProperty} would normalize to {@code LOG4J_FOO_BAR_PROPERTY}. + * PropertySource implementation that uses environment variables as a source. All environment variables must begin with + * {@code LOG4J_} so as not to conflict with other variables. Normalized environment variables follow a scheme like + * this: {@code log4j2.fooBarProperty} would normalize to {@code LOG4J_FOO_BAR_PROPERTY}. * * @since 2.10.0 */ public class EnvironmentPropertySource implements PropertySource { + + private static final String PREFIX = "LOG4J_"; + private static final int DEFAULT_PRIORITY = -100; + @Override public int getPriority() { - return -100; + return DEFAULT_PRIORITY; } @Override public void forEach(final BiConsumer action) { - for (final Map.Entry entry : System.getenv().entrySet()) { + final Map getenv; + try { + getenv = System.getenv(); + } catch (SecurityException e) { + // There is no status logger yet. + return; + } + for (final Map.Entry entry : getenv.entrySet()) { final String key = entry.getKey(); - if (key.startsWith("LOG4J_")) { - action.accept(key.substring(6), entry.getValue()); + if (key.startsWith(PREFIX)) { + action.accept(key.substring(PREFIX.length()), entry.getValue()); } } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java new file mode 100644 index 00000000000..f85d640a2f1 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java @@ -0,0 +1,76 @@ +/* + * 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.util; + +import java.security.Permission; + +import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests https://issues.apache.org/jira/browse/LOG4J2-2274. + * + * @see EnvironmentPropertySource + * @see SecurityManager + * @see System#setSecurityManager(SecurityManager) + */ +public class EnvironmentPropertySourceSecurityManagerTest { + + /** + * Always throws a SecurityException for any environment variables permission check. + */ + private class TestSecurityManager extends SecurityManager { + @Override + public void checkPermission(Permission permission) { + if ("getenv.*".equals(permission.getName())) { + throw new SecurityException(); + } + } + } + + /** + * Makes sure we do not blow up with exception below due to a security manager rejecting environment variable access + * in {@link EnvironmentPropertySource}. + * + *
    +     * java.lang.NoClassDefFoundError: Could not initialize class org.apache.logging.log4j.util.PropertiesUtil
    +     *     at org.apache.logging.log4j.status.StatusLogger.(StatusLogger.java:78)
    +     *     at org.apache.logging.log4j.core.AbstractLifeCycle.(AbstractLifeCycle.java:38)
    +     *     at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    +     *     at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    +     *     at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    +     *     at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    +     *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:172)
    +     *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:161)
    +     *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:1)
    +     *     at org.apache.logging.log4j.util.EnvironmentPropertySourceSecurityManagerTest.test(EnvironmentPropertySourceSecurityManagerTest.java:55)
    +     * 
    + */ + @Test + public void test() { + try { + SecurityManager securityManager = new TestSecurityManager(); + System.setSecurityManager(securityManager); + } catch (SecurityException se) { + // The SecurityManager is already set + } + + Assert.assertNotNull(ConfigurationBuilderFactory.newConfigurationBuilder().build()); + } +} diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 4a9ec5b64e6..b8c739ee2bf 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -91,6 +91,9 @@ ConcurrentModificationException from org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:71). + + Allow EnvironmentPropertySource to run with a SecurityManager that rejects environment variable access. +
    @@ -272,6 +275,9 @@ ConcurrentModificationException from org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:71). + + Allow EnvironmentPropertySource to run with a SecurityManager that rejects environment variable access. + From beadd21ddc3b1e903193ee9b45a12e583c53dad2 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 11:04:52 -0700 Subject: [PATCH 0089/2347] [LOG4J2-2279] Allow SystemPropertiesPropertySource to run with a SecurityManager that rejects system property access. --- .../log4j/util/EnvironmentPropertySource.java | 77 +++++++++-------- .../util/SystemPropertiesPropertySource.java | 66 ++++++++------ .../log4j/junit/SecurityManagerTestRule.java | 70 +++++++++++++++ ...onmentPropertySourceSecurityManagerIT.java | 78 +++++++++++++++++ ...tyFilePropertySourceSecurityManagerIT.java | 79 +++++++++++++++++ ...ertiesPropertySourceSecurityManagerIT.java | 86 +++++++++++++++++++ ...mentPropertySourceSecurityManagerTest.java | 76 ---------------- 7 files changed, 393 insertions(+), 139 deletions(-) create mode 100644 log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java create mode 100644 log4j-api/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerIT.java create mode 100644 log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java create mode 100644 log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceSecurityManagerIT.java delete mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java index 40aa76bb16f..f2ef0df9986 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/EnvironmentPropertySource.java @@ -19,48 +19,53 @@ import java.util.Map; /** - * PropertySource implementation that uses environment variables as a source. All environment variables must begin with - * {@code LOG4J_} so as not to conflict with other variables. Normalized environment variables follow a scheme like - * this: {@code log4j2.fooBarProperty} would normalize to {@code LOG4J_FOO_BAR_PROPERTY}. + * PropertySource implementation that uses environment variables as a source. + * All environment variables must begin with {@code LOG4J_} so as not to + * conflict with other variables. Normalized environment variables follow a + * scheme like this: {@code log4j2.fooBarProperty} would normalize to + * {@code LOG4J_FOO_BAR_PROPERTY}. * * @since 2.10.0 */ public class EnvironmentPropertySource implements PropertySource { - private static final String PREFIX = "LOG4J_"; - private static final int DEFAULT_PRIORITY = -100; + private static final String PREFIX = "LOG4J_"; + private static final int DEFAULT_PRIORITY = -100; - @Override - public int getPriority() { - return DEFAULT_PRIORITY; - } + @Override + public int getPriority() { + return DEFAULT_PRIORITY; + } - @Override - public void forEach(final BiConsumer action) { - final Map getenv; - try { - getenv = System.getenv(); - } catch (SecurityException e) { - // There is no status logger yet. - return; - } - for (final Map.Entry entry : getenv.entrySet()) { - final String key = entry.getKey(); - if (key.startsWith(PREFIX)) { - action.accept(key.substring(PREFIX.length()), entry.getValue()); - } - } - } + @Override + public void forEach(final BiConsumer action) { + final Map getenv; + try { + getenv = System.getenv(); + } catch (final SecurityException e) { + // There is no status logger yet. + LowLevelLogUtil.logException( + "The system environment variables are not available to Log4j due to security restrictions: " + e, + e); + return; + } + for (final Map.Entry entry : getenv.entrySet()) { + final String key = entry.getKey(); + if (key.startsWith(PREFIX)) { + action.accept(key.substring(PREFIX.length()), entry.getValue()); + } + } + } - @Override - public CharSequence getNormalForm(final Iterable tokens) { - final StringBuilder sb = new StringBuilder("LOG4J"); - for (final CharSequence token : tokens) { - sb.append('_'); - for (int i = 0; i < token.length(); i++) { - sb.append(Character.toUpperCase(token.charAt(i))); - } - } - return sb.toString(); - } + @Override + public CharSequence getNormalForm(final Iterable tokens) { + final StringBuilder sb = new StringBuilder("LOG4J"); + for (final CharSequence token : tokens) { + sb.append('_'); + for (int i = 0; i < token.length(); i++) { + sb.append(Character.toUpperCase(token.charAt(i))); + } + } + return sb.toString(); + } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java index 627b968b59a..2509cd1e195 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java @@ -20,40 +20,52 @@ import java.util.Properties; /** - * PropertySource backed by the current system properties. Other than having a higher priority over normal properties, - * this follows the same rules as {@link PropertiesPropertySource}. + * PropertySource backed by the current system properties. Other than having a + * higher priority over normal properties, this follows the same rules as + * {@link PropertiesPropertySource}. * * @since 2.10.0 */ public class SystemPropertiesPropertySource implements PropertySource { - private static final int DEFAULT_PRIORITY = 100; - private static final String PREFIX = "log4j2."; + private static final int DEFAULT_PRIORITY = 100; + private static final String PREFIX = "log4j2."; - @Override - public int getPriority() { - return DEFAULT_PRIORITY; - } + @Override + public int getPriority() { + return DEFAULT_PRIORITY; + } - @Override - public void forEach(final BiConsumer action) { - final Properties properties = System.getProperties(); - // Lock properties only long enough to get a thread-safe SAFE snapshot of its current keys, an array. - final Object[] keySet; - synchronized (properties) { - keySet = properties.keySet().toArray(); - } - // Then traverse for an unknown amount of time. - // Some keys may now be absent, in which case, the value is null. - for (final Object key : keySet) { - final String keyStr = Objects.toString(key, null); - action.accept(keyStr, properties.getProperty(keyStr)); - } - } + @Override + public void forEach(final BiConsumer action) { + Properties properties; + try { + properties = System.getProperties(); + } catch (final SecurityException e) { + // (1) There is no status logger. + // (2) LowLevelLogUtil also consults system properties ("line.separator") to + // open a BufferedWriter, so this may fail as well. Just having a hard reference + // in this code to LowLevelLogUtil would cause a problem. + // (3) We could log to System.err (nah) or just be quiet as we do now. + return; + } + // Lock properties only long enough to get a thread-safe SAFE snapshot of its + // current keys, an array. + final Object[] keySet; + synchronized (properties) { + keySet = properties.keySet().toArray(); + } + // Then traverse for an unknown amount of time. + // Some keys may now be absent, in which case, the value is null. + for (final Object key : keySet) { + final String keyStr = Objects.toString(key, null); + action.accept(keyStr, properties.getProperty(keyStr)); + } + } - @Override - public CharSequence getNormalForm(final Iterable tokens) { - return PREFIX + Util.joinAsCamelCase(tokens); - } + @Override + public CharSequence getNormalForm(final Iterable tokens) { + return PREFIX + Util.joinAsCamelCase(tokens); + } } diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java b/log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java new file mode 100644 index 00000000000..311b817bc99 --- /dev/null +++ b/log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java @@ -0,0 +1,70 @@ +/* + * 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.junit; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * Sets a security manager for a test run. The current security manager is first + * saved then restored after the test is run. + *

    + * Using a security manager can mess up other tests so this is best used from + * integration tests (classes that end in "IT" instead of "Test" and + * "TestCase".) + *

    + * + * @since 2.11.0 + */ +public class SecurityManagerTestRule implements TestRule { + + public SecurityManagerTestRule(final SecurityManager securityManager) { + super(); + this.securityManager = securityManager; + } + + private SecurityManager securityManagerBefore; + private final SecurityManager securityManager; + + @Override + public Statement apply(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + before(); + try { + base.evaluate(); + } finally { + after(); + } + } + + private void after() { + System.setSecurityManager(securityManagerBefore); + } + + private void before() { + securityManagerBefore = System.getSecurityManager(); + System.setSecurityManager(securityManager); + + } + }; + } + +} diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerIT.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerIT.java new file mode 100644 index 00000000000..0020c057e3b --- /dev/null +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerIT.java @@ -0,0 +1,78 @@ +/* + * 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.util; + +import java.security.Permission; + +import org.apache.logging.log4j.junit.SecurityManagerTestRule; +import org.junit.Rule; +import org.junit.Test; + +/** + * Tests https://issues.apache.org/jira/browse/LOG4J2-2274. + *

    + * Using a security manager can mess up other tests so this is best used from + * integration tests (classes that end in "IT" instead of "Test" and + * "TestCase".) + *

    + * + * @see EnvironmentPropertySource + * @see SecurityManager + * @see System#setSecurityManager(SecurityManager) + */ +public class EnvironmentPropertySourceSecurityManagerIT { + + @Rule + public final SecurityManagerTestRule rule = new SecurityManagerTestRule(new TestSecurityManager()); + + /** + * Always throws a SecurityException for any environment variables permission + * check. + */ + private class TestSecurityManager extends SecurityManager { + @Override + public void checkPermission(final Permission permission) { + if ("getenv.*".equals(permission.getName())) { + throw new SecurityException(); + } + } + } + + /** + * Makes sure we do not blow up with exception below due to a security manager + * rejecting environment variable access in {@link EnvironmentPropertySource}. + * + *
    +	 * java.lang.NoClassDefFoundError: Could not initialize class org.apache.logging.log4j.util.PropertiesUtil
    +	 *     at org.apache.logging.log4j.status.StatusLogger.(StatusLogger.java:78)
    +	 *     at org.apache.logging.log4j.core.AbstractLifeCycle.(AbstractLifeCycle.java:38)
    +	 *     at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    +	 *     at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    +	 *     at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    +	 *     at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    +	 *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:172)
    +	 *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:161)
    +	 *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:1)
    +	 *     at org.apache.logging.log4j.util.EnvironmentPropertySourceSecurityManagerTest.test(EnvironmentPropertySourceSecurityManagerTest.java:55)
    +	 * 
    + */ + @Test + public void test() { + PropertiesUtil.getProperties(); + } +} diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java new file mode 100644 index 00000000000..a6679d66823 --- /dev/null +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java @@ -0,0 +1,79 @@ +/* + * 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.util; + +import java.io.FilePermission; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.Permission; +import java.util.PropertyPermission; + +import org.apache.logging.log4j.junit.SecurityManagerTestRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +/** + * Test related to https://issues.apache.org/jira/browse/LOG4J2-2274. + *

    + * Using a security manager can mess up other tests so this is best used from + * integration tests (classes that end in "IT" instead of "Test" and + * "TestCase".) + *

    + * + * @see PropertyFilePropertySource + * @see SecurityManager + * @see System#setSecurityManager(SecurityManager) + * @see PropertyPermission + */ +public class PropertyFilePropertySourceSecurityManagerIT { + + @Rule + public final SecurityManagerTestRule rule = new SecurityManagerTestRule(new TestSecurityManager()); + + private static final String TEST_FIXTURE_PATH = "src/test/resources/PropertiesUtilTest.properties"; + + /** + * Always throws a SecurityException for any environment variables permission + * check. + */ + private class TestSecurityManager extends SecurityManager { + + @Override + public void checkPermission(Permission permission) { + if (permission instanceof FilePermission && permission.getName().endsWith(TEST_FIXTURE_PATH)) { + throw new SecurityException(); + } + } + } + + /** + * Makes sure we do not blow up with exception below due to a security manager + * rejecting environment variable access in + * {@link SystemPropertiesPropertySource}. + * + *
    +	 * 
    + */ + @Test + public void test() { + Assert.assertTrue(TEST_FIXTURE_PATH, Files.exists(Paths.get(TEST_FIXTURE_PATH))); + PropertiesUtil propertiesUtil = new PropertiesUtil(TEST_FIXTURE_PATH); + Assert.assertEquals(null, propertiesUtil.getStringProperty("a.1")); + } +} diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceSecurityManagerIT.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceSecurityManagerIT.java new file mode 100644 index 00000000000..ebab7100d5a --- /dev/null +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceSecurityManagerIT.java @@ -0,0 +1,86 @@ +/* + * 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.util; + +import java.security.Permission; +import java.util.PropertyPermission; + +import org.apache.logging.log4j.junit.SecurityManagerTestRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +/** + * Test related to https://issues.apache.org/jira/browse/LOG4J2-2274. + *

    + * Using a security manager can mess up other tests so this is best used from + * integration tests (classes that end in "IT" instead of "Test" and + * "TestCase".) + *

    + * + * @see SystemPropertiesPropertySource + * @see SecurityManager + * @see System#setSecurityManager(SecurityManager) + * @see PropertyPermission + */ +public class SystemPropertiesPropertySourceSecurityManagerIT { + + @Rule + public final SecurityManagerTestRule rule = new SecurityManagerTestRule(new TestSecurityManager()); + + /** + * Always throws a SecurityException for any environment variables permission + * check. + */ + private class TestSecurityManager extends SecurityManager { + @Override + public void checkPermission(final Permission permission) { + if (permission instanceof PropertyPermission) { + throw new SecurityException(); + } + } + } + + /** + * Makes sure we do not blow up with exception below due to a security manager + * rejecting environment variable access in + * {@link SystemPropertiesPropertySource}. + * + *
    +	 * java.lang.ExceptionInInitializerError
    +	 * 	at org.apache.logging.log4j.util.SystemPropertiesPropertySourceSecurityManagerTest.test(SystemPropertiesPropertySourceSecurityManagerTest.java:64)
    +	 * 	...
    +	 * Caused by: java.lang.SecurityException
    +	 * 	at org.apache.logging.log4j.util.SystemPropertiesPropertySourceSecurityManagerTest$TestSecurityManager.checkPermission(SystemPropertiesPropertySourceSecurityManagerTest.java:49)
    +	 * 	at java.lang.SecurityManager.checkPropertiesAccess(SecurityManager.java:1265)
    +	 * 	at java.lang.System.getProperties(System.java:624)
    +	 * 	at org.apache.logging.log4j.util.SystemPropertiesPropertySource.forEach(SystemPropertiesPropertySource.java:40)
    +	 * 	at org.apache.logging.log4j.util.PropertiesUtil$Environment.reload(PropertiesUtil.java:330)
    +	 * 	at org.apache.logging.log4j.util.PropertiesUtil$Environment.(PropertiesUtil.java:322)
    +	 * 	at org.apache.logging.log4j.util.PropertiesUtil$Environment.(PropertiesUtil.java:310)
    +	 * 	at org.apache.logging.log4j.util.PropertiesUtil.(PropertiesUtil.java:69)
    +	 * 	at org.apache.logging.log4j.util.PropertiesUtil.(PropertiesUtil.java:49)
    +	 * 	... 26 more
    +	 * 
    + */ + @Test + public void test() { + final PropertiesUtil propertiesUtil = new PropertiesUtil("src/test/resources/PropertiesUtilTest.properties"); + Assert.assertEquals(null, propertiesUtil.getStringProperty("a.1")); + } +} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java deleted file mode 100644 index f85d640a2f1..00000000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/util/EnvironmentPropertySourceSecurityManagerTest.java +++ /dev/null @@ -1,76 +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.util; - -import java.security.Permission; - -import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory; -import org.junit.Assert; -import org.junit.Test; - -/** - * Tests https://issues.apache.org/jira/browse/LOG4J2-2274. - * - * @see EnvironmentPropertySource - * @see SecurityManager - * @see System#setSecurityManager(SecurityManager) - */ -public class EnvironmentPropertySourceSecurityManagerTest { - - /** - * Always throws a SecurityException for any environment variables permission check. - */ - private class TestSecurityManager extends SecurityManager { - @Override - public void checkPermission(Permission permission) { - if ("getenv.*".equals(permission.getName())) { - throw new SecurityException(); - } - } - } - - /** - * Makes sure we do not blow up with exception below due to a security manager rejecting environment variable access - * in {@link EnvironmentPropertySource}. - * - *
    -     * java.lang.NoClassDefFoundError: Could not initialize class org.apache.logging.log4j.util.PropertiesUtil
    -     *     at org.apache.logging.log4j.status.StatusLogger.(StatusLogger.java:78)
    -     *     at org.apache.logging.log4j.core.AbstractLifeCycle.(AbstractLifeCycle.java:38)
    -     *     at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    -     *     at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    -     *     at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    -     *     at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    -     *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:172)
    -     *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:161)
    -     *     at org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder.build(DefaultConfigurationBuilder.java:1)
    -     *     at org.apache.logging.log4j.util.EnvironmentPropertySourceSecurityManagerTest.test(EnvironmentPropertySourceSecurityManagerTest.java:55)
    -     * 
    - */ - @Test - public void test() { - try { - SecurityManager securityManager = new TestSecurityManager(); - System.setSecurityManager(securityManager); - } catch (SecurityException se) { - // The SecurityManager is already set - } - - Assert.assertNotNull(ConfigurationBuilderFactory.newConfigurationBuilder().build()); - } -} From d0049ceb2b3778e377fe13ecda0ba406fb475877 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 11:05:35 -0700 Subject: [PATCH 0090/2347] [LOG4J2-2279] Allow SystemPropertiesPropertySource to run with a SecurityManager that rejects system property access. --- src/changes/changes.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index b8c739ee2bf..512291dabce 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -94,6 +94,9 @@ Allow EnvironmentPropertySource to run with a SecurityManager that rejects environment variable access. + + Allow SystemPropertiesPropertySource to run with a SecurityManager that rejects system property access. +
    @@ -278,6 +281,9 @@ Allow EnvironmentPropertySource to run with a SecurityManager that rejects environment variable access. + + Allow SystemPropertiesPropertySource to run with a SecurityManager that rejects system property access. + From 33af8889ce67a54bde32241d87f2f0e54a7c32c8 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 12:18:27 -0700 Subject: [PATCH 0091/2347] [LOG4J2-2279] Allow SystemPropertiesPropertySource to run with a SecurityManager that rejects system property access. This test passes for me on Windows 10 but fails on Jenkins. Reorder a sanity check so that it takes place before the SecurityManager test rule is evaluated. --- ...tyFilePropertySourceSecurityManagerIT.java | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java index a6679d66823..c0c51349399 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/PropertyFilePropertySourceSecurityManagerIT.java @@ -25,6 +25,7 @@ import org.apache.logging.log4j.junit.SecurityManagerTestRule; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -43,37 +44,41 @@ */ public class PropertyFilePropertySourceSecurityManagerIT { - @Rule - public final SecurityManagerTestRule rule = new SecurityManagerTestRule(new TestSecurityManager()); + @BeforeClass + public static void beforeClass() { + Assert.assertTrue(TEST_FIXTURE_PATH, Files.exists(Paths.get(TEST_FIXTURE_PATH))); + } + + @Rule + public final SecurityManagerTestRule rule = new SecurityManagerTestRule(new TestSecurityManager()); - private static final String TEST_FIXTURE_PATH = "src/test/resources/PropertiesUtilTest.properties"; + private static final String TEST_FIXTURE_PATH = "src/test/resources/PropertiesUtilTest.properties"; - /** - * Always throws a SecurityException for any environment variables permission - * check. - */ - private class TestSecurityManager extends SecurityManager { + /** + * Always throws a SecurityException for any environment variables permission + * check. + */ + private class TestSecurityManager extends SecurityManager { - @Override - public void checkPermission(Permission permission) { - if (permission instanceof FilePermission && permission.getName().endsWith(TEST_FIXTURE_PATH)) { - throw new SecurityException(); - } - } - } + @Override + public void checkPermission(final Permission permission) { + if (permission instanceof FilePermission && permission.getName().endsWith(TEST_FIXTURE_PATH)) { + throw new SecurityException(); + } + } + } - /** - * Makes sure we do not blow up with exception below due to a security manager - * rejecting environment variable access in - * {@link SystemPropertiesPropertySource}. - * - *
    -	 * 
    - */ - @Test - public void test() { - Assert.assertTrue(TEST_FIXTURE_PATH, Files.exists(Paths.get(TEST_FIXTURE_PATH))); - PropertiesUtil propertiesUtil = new PropertiesUtil(TEST_FIXTURE_PATH); - Assert.assertEquals(null, propertiesUtil.getStringProperty("a.1")); - } + /** + * Makes sure we do not blow up with exception below due to a security manager + * rejecting environment variable access in + * {@link SystemPropertiesPropertySource}. + * + *
    +     * 
    + */ + @Test + public void test() { + final PropertiesUtil propertiesUtil = new PropertiesUtil(TEST_FIXTURE_PATH); + Assert.assertEquals(null, propertiesUtil.getStringProperty("a.1")); + } } From 5749450151cc0f3fc4179540e658a2b9faf0b467 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 12:47:30 -0700 Subject: [PATCH 0092/2347] Now that we are on Java 8, we do not need to keep the test set up that allowed for MongoDB tests to be disabled if not running on Java 8. This was due to the dependency on Java 8 of the MongoDB test framework we use. --- .../logging/log4j/mongodb2/Java8Test.java | 48 ------------------- ...Java8.java => MongoDbAuthFailureTest.java} | 2 +- ...dTestJava8.java => MongoDbCappedTest.java} | 2 +- ...tJava8.java => MongoDbMapMessageTest.java} | 2 +- ...MongoDbTestJava8.java => MongoDbTest.java} | 2 +- ...ava8.java => MongoDbTestTestRuleTest.java} | 2 +- .../logging/log4j/mongodb3/Java8Test.java | 48 ------------------- ...Java8.java => MongoDbAuthFailureTest.java} | 4 +- ...dTestJava8.java => MongoDbCappedTest.java} | 4 +- ...tJava8.java => MongoDbMapMessageTest.java} | 4 +- ...MongoDbTestJava8.java => MongoDbTest.java} | 4 +- ...ava8.java => MongoDbTestTestRuleTest.java} | 4 +- 12 files changed, 15 insertions(+), 111 deletions(-) delete mode 100644 log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/Java8Test.java rename log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/{MongoDbAuthFailureTestJava8.java => MongoDbAuthFailureTest.java} (98%) rename log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/{MongoDbCappedTestJava8.java => MongoDbCappedTest.java} (98%) rename log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/{MongoDbMapMessageTestJava8.java => MongoDbMapMessageTest.java} (98%) rename log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/{MongoDbTestJava8.java => MongoDbTest.java} (98%) rename log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/{MongoDbTestTestRuleTestJava8.java => MongoDbTestTestRuleTest.java} (98%) delete mode 100644 log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/Java8Test.java rename log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/{MongoDbAuthFailureTestJava8.java => MongoDbAuthFailureTest.java} (96%) rename log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/{MongoDbCappedTestJava8.java => MongoDbCappedTest.java} (96%) rename log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/{MongoDbMapMessageTestJava8.java => MongoDbMapMessageTest.java} (96%) rename log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/{MongoDbTestJava8.java => MongoDbTest.java} (97%) rename log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/{MongoDbTestTestRuleTestJava8.java => MongoDbTestTestRuleTest.java} (96%) diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/Java8Test.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/Java8Test.java deleted file mode 100644 index 569cf4a0284..00000000000 --- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/Java8Test.java +++ /dev/null @@ -1,48 +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.mongodb2; - -import org.apache.commons.lang3.JavaVersion; -import org.apache.commons.lang3.SystemUtils; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -/** - * Runs all MongoDB only on Java 8. - *

    - * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8. - *

    - */ -@RunWith(Suite.class) -@Suite.SuiteClasses({ MongoDbTestTestRuleTestJava8.class, MongoDbAuthFailureTestJava8.class, MongoDbCappedTestJava8.class, - MongoDbMapMessageTestJava8.class, MongoDbTestJava8.class }) -public class Java8Test { - - @BeforeClass - public static void beforeClass() { - Assume.assumeTrue(SystemUtils.JAVA_VERSION, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_8)); - } - - @Test - public void test() { - // noop - } -} diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTestJava8.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTest.java similarity index 98% rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTestJava8.java rename to log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTest.java index 0d970f79f4a..0fb61c62af6 100644 --- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTestJava8.java +++ b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbAuthFailureTest.java @@ -41,7 +41,7 @@ */ @Ignore("TODO Set up the log4j user in MongoDB") @Category(Appenders.MongoDb.class) -public class MongoDbAuthFailureTestJava8 { +public class MongoDbAuthFailureTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-auth-failure.xml"); diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTestJava8.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTest.java similarity index 98% rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTestJava8.java rename to log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTest.java index 03e463a2eb1..ffd368a02e2 100644 --- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTestJava8.java +++ b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbCappedTest.java @@ -38,7 +38,7 @@ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}. */ @Category(Appenders.MongoDb.class) -public class MongoDbCappedTestJava8 { +public class MongoDbCappedTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-capped.xml"); diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTestJava8.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTest.java similarity index 98% rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTestJava8.java rename to log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTest.java index f18e7ba9a1f..99350aa1bb7 100644 --- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTestJava8.java +++ b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbMapMessageTest.java @@ -39,7 +39,7 @@ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}. */ @Category(Appenders.MongoDb.class) -public class MongoDbMapMessageTestJava8 { +public class MongoDbMapMessageTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-map-message.xml"); diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestJava8.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTest.java similarity index 98% rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestJava8.java rename to log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTest.java index 0e2661086a0..2a73f8c4eb5 100644 --- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestJava8.java +++ b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTest.java @@ -38,7 +38,7 @@ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}. */ @Category(Appenders.MongoDb.class) -public class MongoDbTestJava8 { +public class MongoDbTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb.xml"); diff --git a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTestJava8.java b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTest.java similarity index 98% rename from log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTestJava8.java rename to log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTest.java index 3d8b35503d6..68e9782f51e 100644 --- a/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTestJava8.java +++ b/log4j-mongodb2/src/test/java/org/apache/logging/log4j/mongodb2/MongoDbTestTestRuleTest.java @@ -37,7 +37,7 @@ * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8. *

    */ -public class MongoDbTestTestRuleTestJava8 { +public class MongoDbTestTestRuleTest { private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule .create(TestConstants.SYS_PROP_NAME_PORT); diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/Java8Test.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/Java8Test.java deleted file mode 100644 index 71acc293fdf..00000000000 --- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/Java8Test.java +++ /dev/null @@ -1,48 +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.mongodb3; - -import org.apache.commons.lang3.JavaVersion; -import org.apache.commons.lang3.SystemUtils; -import org.junit.Assume; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -/** - * Runs all MongoDB only on Java 8. - *

    - * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8. - *

    - */ -@RunWith(Suite.class) -@Suite.SuiteClasses({ MongoDbTestTestRuleTestJava8.class, MongoDbAuthFailureTestJava8.class, MongoDbCappedTestJava8.class, - MongoDbMapMessageTestJava8.class, MongoDbTestJava8.class }) -public class Java8Test { - - @BeforeClass - public static void beforeClass() { - Assume.assumeTrue(SystemUtils.JAVA_VERSION, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_8)); - } - - @Test - public void test() { - // noop - } -} diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTestJava8.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTest.java similarity index 96% rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTestJava8.java rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTest.java index 6361a442edf..19a45c86763 100644 --- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTestJava8.java +++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbAuthFailureTest.java @@ -42,7 +42,7 @@ */ @Ignore("TODO Set up the log4j user in MongoDB") @Category(Appenders.MongoDb.class) -public class MongoDbAuthFailureTestJava8 { +public class MongoDbAuthFailureTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-auth-failure.xml"); @@ -50,7 +50,7 @@ public class MongoDbAuthFailureTestJava8 { .create(TestConstants.SYS_PROP_NAME_PORT); private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), - MongoDbAuthFailureTestJava8.class, LoggingTarget.NULL); + MongoDbAuthFailureTest.class, LoggingTarget.NULL); @ClassRule public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule, diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTestJava8.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java similarity index 96% rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTestJava8.java rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java index 06fb4f5cae5..7611284f436 100644 --- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTestJava8.java +++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbCappedTest.java @@ -38,7 +38,7 @@ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}. */ @Category(Appenders.MongoDb.class) -public class MongoDbCappedTestJava8 { +public class MongoDbCappedTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-capped.xml"); @@ -46,7 +46,7 @@ public class MongoDbCappedTestJava8 { .create(TestConstants.SYS_PROP_NAME_PORT); private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), - MongoDbCappedTestJava8.class, LoggingTarget.NULL); + MongoDbCappedTest.class, LoggingTarget.NULL); @ClassRule public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule, diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTestJava8.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java similarity index 96% rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTestJava8.java rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java index 1c36e080e0a..70f910e849d 100644 --- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTestJava8.java +++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbMapMessageTest.java @@ -39,7 +39,7 @@ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}. */ @Category(Appenders.MongoDb.class) -public class MongoDbMapMessageTestJava8 { +public class MongoDbMapMessageTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb-map-message.xml"); @@ -47,7 +47,7 @@ public class MongoDbMapMessageTestJava8 { .create(TestConstants.SYS_PROP_NAME_PORT); private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), - MongoDbMapMessageTestJava8.class, LoggingTarget.NULL); + MongoDbMapMessageTest.class, LoggingTarget.NULL); @ClassRule public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule, diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestJava8.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java similarity index 97% rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestJava8.java rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java index e1f283cadc7..eab64b3f5c2 100644 --- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestJava8.java +++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTest.java @@ -38,7 +38,7 @@ * This class name does NOT end in "Test" in order to only be picked up by {@link Java8Test}. */ @Category(Appenders.MongoDb.class) -public class MongoDbTestJava8 { +public class MongoDbTest { private static LoggerContextRule loggerContextTestRule = new LoggerContextRule("log4j2-mongodb.xml"); @@ -46,7 +46,7 @@ public class MongoDbTestJava8 { .create(TestConstants.SYS_PROP_NAME_PORT); private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), - MongoDbTestJava8.class, LoggingTarget.NULL); + MongoDbTest.class, LoggingTarget.NULL); @ClassRule public static RuleChain ruleChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule, diff --git a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTestJava8.java b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTest.java similarity index 96% rename from log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTestJava8.java rename to log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTest.java index 21d62f9c1de..e19980bfff9 100644 --- a/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTestJava8.java +++ b/log4j-mongodb3/src/test/java/org/apache/logging/log4j/mongodb3/MongoDbTestTestRuleTest.java @@ -37,13 +37,13 @@ * The test framework {@code de.flapdoodle.embed.mongo} requires Java 8. *

    */ -public class MongoDbTestTestRuleTestJava8 { +public class MongoDbTestTestRuleTest { private static final AvailablePortSystemPropertyTestRule mongoDbPortTestRule = AvailablePortSystemPropertyTestRule .create(TestConstants.SYS_PROP_NAME_PORT); private static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName(), - MongoDbTestTestRuleTestJava8.class, LoggingTarget.NULL); + MongoDbTestTestRuleTest.class, LoggingTarget.NULL); @ClassRule public static RuleChain mongoDbChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule); From c647ca61eec5a4d7fc4aba6530e3ecd704a54a0d Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 15:03:48 -0700 Subject: [PATCH 0093/2347] Better Javadoc. --- .../log4j/junit/SecurityManagerTestRule.java | 88 ++++++++++++------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java b/log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java index 311b817bc99..57ac55da281 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/junit/SecurityManagerTestRule.java @@ -22,49 +22,73 @@ import org.junit.runners.model.Statement; /** - * Sets a security manager for a test run. The current security manager is first - * saved then restored after the test is run. + * Sets a security manager for a test run. The current security manager is first saved then restored after the test is + * run. *

    - * Using a security manager can mess up other tests so this is best used from - * integration tests (classes that end in "IT" instead of "Test" and - * "TestCase".) + * Using a security manager can mess up other tests so this is best used from integration tests (classes that end in + * "IT" instead of "Test" and "TestCase".) *

    * + *

    + * When this test rule is evaluated, it will: + *

    + *
      + *
    1. Save the current SecurityManager.
    2. + *
    3. Set the SecurityManager to the instance supplied to this rule.
    4. + *
    5. Evaluate the test statement.
    6. + *
    7. Reset the current SecurityManager to the one from step (1).
    8. + *
    + * * @since 2.11.0 */ public class SecurityManagerTestRule implements TestRule { - public SecurityManagerTestRule(final SecurityManager securityManager) { - super(); - this.securityManager = securityManager; - } + /** + * Constructs a new instance with the given {@link SecurityManager}. + *

    + * When this test rule is evaluated, it will: + *

    + *
      + *
    1. Save the current SecurityManager.
    2. + *
    3. Set the SecurityManager to the instance supplied to this rule.
    4. + *
    5. Evaluate the test statement.
    6. + *
    7. Reset the current SecurityManager to the one from step (1).
    8. + *
    + * + * @param securityManager + * the {@link SecurityManager} to use while running a test. + */ + public SecurityManagerTestRule(final SecurityManager securityManager) { + super(); + this.securityManager = securityManager; + } - private SecurityManager securityManagerBefore; - private final SecurityManager securityManager; + private SecurityManager securityManagerBefore; + private final SecurityManager securityManager; - @Override - public Statement apply(final Statement base, final Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - before(); - try { - base.evaluate(); - } finally { - after(); - } - } + @Override + public Statement apply(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + before(); + try { + base.evaluate(); + } finally { + after(); + } + } - private void after() { - System.setSecurityManager(securityManagerBefore); - } + private void after() { + System.setSecurityManager(securityManagerBefore); + } - private void before() { - securityManagerBefore = System.getSecurityManager(); - System.setSecurityManager(securityManager); + private void before() { + securityManagerBefore = System.getSecurityManager(); + System.setSecurityManager(securityManager); - } - }; - } + } + }; + } } From 2c3713d9befbaae488c210ea2257b2f1721d4558 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 16:37:05 -0700 Subject: [PATCH 0094/2347] [LOG4J2-2279] Move ProcessIdUtil from log4j-api to log4j-core. --- .../main/java/org/apache/logging/log4j/util/ProcessIdUtil.java | 0 .../java/org/apache/logging/log4j/util/ProcessIdUtilTest.java | 0 src/changes/changes.xml | 3 +++ 3 files changed, 3 insertions(+) rename {log4j-api => log4j-core}/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java (100%) rename {log4j-api => log4j-core}/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java (100%) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java similarity index 100% rename from log4j-api/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java rename to log4j-core/src/main/java/org/apache/logging/log4j/util/ProcessIdUtil.java diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java similarity index 100% rename from log4j-api/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java rename to log4j-core/src/test/java/org/apache/logging/log4j/util/ProcessIdUtilTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 512291dabce..49c8d9009cd 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -97,6 +97,9 @@ Allow SystemPropertiesPropertySource to run with a SecurityManager that rejects system property access. + + Move ProcessIdUtil from log4j-api to log4j-core. +
    From 4f51c8078ba21a0fcb84f5a7936be611c19a4a1a Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Thu, 1 Mar 2018 18:01:39 -0700 Subject: [PATCH 0095/2347] Fix Oracle compiler warnings. No warnings in Eclipse though. --- .../log4j/CloseableThreadContextTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/CloseableThreadContextTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/CloseableThreadContextTest.java index c5e84e09ddf..11539fef712 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/CloseableThreadContextTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/CloseableThreadContextTest.java @@ -26,6 +26,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertNotNull; /** * Tests {@link CloseableThreadContext}. @@ -43,6 +44,7 @@ public class CloseableThreadContextTest { @Test public void shouldAddAnEntryToTheMap() throws Exception { try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.put(key, value)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(value)); } } @@ -52,6 +54,7 @@ public void shouldAddTwoEntriesToTheMap() throws Exception { final String key2 = "key2"; final String value2 = "value2"; try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.put(key, value).put(key2, value2)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(value)); assertThat(ThreadContext.get(key2), is(value2)); } @@ -63,8 +66,10 @@ public void shouldNestEntries() throws Exception { final String innerValue = "innerValue"; ThreadContext.put(key, oldValue); try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.put(key, value)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(value)); try (final CloseableThreadContext.Instance ignored2 = CloseableThreadContext.put(key, innerValue)) { + assertNotNull(ignored2); assertThat(ThreadContext.get(key), is(innerValue)); } assertThat(ThreadContext.get(key), is(value)); @@ -77,6 +82,7 @@ public void shouldPreserveOldEntriesFromTheMapWhenAutoClosed() throws Exception final String oldValue = "oldValue"; ThreadContext.put(key, oldValue); try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.put(key, value)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(value)); } assertThat(ThreadContext.get(key), is(oldValue)); @@ -88,6 +94,7 @@ public void ifTheSameKeyIsAddedTwiceTheOriginalShouldBeUsed() throws Exception { final String secondValue = "innerValue"; ThreadContext.put(key, oldValue); try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.put(key, value).put(key, secondValue)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(secondValue)); } assertThat(ThreadContext.get(key), is(oldValue)); @@ -97,6 +104,7 @@ public void ifTheSameKeyIsAddedTwiceTheOriginalShouldBeUsed() throws Exception { public void shouldPushAndPopAnEntryToTheStack() throws Exception { final String message = "message"; try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.push(message)) { + assertNotNull(ignored); assertThat(ThreadContext.peek(), is(message)); } assertThat(ThreadContext.peek(), is("")); @@ -107,6 +115,7 @@ public void shouldPushAndPopTwoEntriesToTheStack() throws Exception { final String message1 = "message1"; final String message2 = "message2"; try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.push(message1).push(message2)) { + assertNotNull(ignored); assertThat(ThreadContext.peek(), is(message2)); } assertThat(ThreadContext.peek(), is("")); @@ -119,6 +128,7 @@ public void shouldPushAndPopAParameterizedEntryToTheStack() throws Exception { final String formattedMessage = parameterizedMessage.replace("{}", parameterizedMessageParameter); try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.push(parameterizedMessage, parameterizedMessageParameter)) { + assertNotNull(ignored); assertThat(ThreadContext.peek(), is(formattedMessage)); } assertThat(ThreadContext.peek(), is("")); @@ -127,6 +137,7 @@ public void shouldPushAndPopAParameterizedEntryToTheStack() throws Exception { @Test public void shouldRemoveAnEntryFromTheMapWhenAutoClosed() throws Exception { try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.put(key, value)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(value)); } assertThat(ThreadContext.containsKey(key), is(false)); @@ -136,6 +147,7 @@ public void shouldRemoveAnEntryFromTheMapWhenAutoClosed() throws Exception { public void shouldAddEntriesToBothStackAndMap() throws Exception { final String stackValue = "something"; try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.put(key, value).push(stackValue)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(value)); assertThat(ThreadContext.peek(), is(stackValue)); } @@ -148,6 +160,7 @@ public void canReuseCloseableThreadContext() throws Exception { final String stackValue = "something"; // Create a ctc and close it final CloseableThreadContext.Instance ctc = CloseableThreadContext.push(stackValue).put(key, value); + assertNotNull(ctc); assertThat(ThreadContext.get(key), is(value)); assertThat(ThreadContext.peek(), is(stackValue)); ctc.close(); @@ -179,6 +192,7 @@ public void closeIsIdempotent() throws Exception { final String newMapValue = "temp map value"; final String newStackValue = "temp stack to keep"; final CloseableThreadContext.Instance ctc = CloseableThreadContext.push(newStackValue).put(key, newMapValue); + assertNotNull(ctc); ctc.close(); assertThat(ThreadContext.get(key), is(originalMapValue)); @@ -199,6 +213,7 @@ public void putAllWillPutAllValues() throws Exception { valuesToPut.put(key, value); try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.putAll(valuesToPut)) { + assertNotNull(ignored); assertThat(ThreadContext.get(key), is(value)); } assertThat(ThreadContext.get(key), is(oldValue)); @@ -213,6 +228,7 @@ public void pushAllWillPushAllValues() throws Exception { ThreadContext.pop(); try (final CloseableThreadContext.Instance ignored = CloseableThreadContext.pushAll(messages)) { + assertNotNull(ignored); assertThat(ThreadContext.peek(), is(key)); } assertThat(ThreadContext.peek(), is("")); From c64c2b6cff2ba2658c7e0522cc0e1e1be6793667 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Fri, 9 Mar 2018 12:20:28 -0700 Subject: [PATCH 0096/2347] Better module description. --- log4j-jpa/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log4j-jpa/pom.xml b/log4j-jpa/pom.xml index e434c1d08ca..25210327833 100644 --- a/log4j-jpa/pom.xml +++ b/log4j-jpa/pom.xml @@ -19,7 +19,7 @@ log4j-jpa Apache Log4j JPA - Apache Log4j Java Persistence API. + Apache Log4j Java Persistence API Appender. ${basedir}/.. From 2b460747fe5a321c5a436225abf06e1856e13f9a Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Fri, 9 Mar 2018 12:22:41 -0700 Subject: [PATCH 0097/2347] Port from 2.x-release branch. --- src/site/markdown/javadoc.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/site/markdown/javadoc.md b/src/site/markdown/javadoc.md index 00cd556e214..a8c1ebad802 100644 --- a/src/site/markdown/javadoc.md +++ b/src/site/markdown/javadoc.md @@ -43,7 +43,11 @@ Component | Description [Log4j 2 to SLF4J Adapter](log4j-to-slf4j/apidocs/index.html) | An adapter that permits applications written against the Log4j 2 API to log using SLF4J. [Apache Flume Appender](log4j-flume-ng/apidocs/index.html) | An Appender that allows applications to send logging events to Apache Flume Agents. [Log4j JMX GUI](log4j-jmx-gui/apidocs/index.html) | A Java Swing-based client for remotely viewing the status logger and editing the Log4j configuration. +[Log4j JPA](log4j-jpa/apidocs/index.html) | Apache Log4j Java Persistence API Appender. [Log4j Web Application Support](log4j-web/apidocs/index.html) | Additional classes that enable multiple configurations within a Servlet Container. [Log4j CouchDB Support](log4j-couchdb/apidocs/index.html) | Additional Appender for CouchDB. -[Log4j MongoDB Support](log4j-mongodb/apidocs/index.html) | Additional Appender for MongoDB. +[Log4j JDBC DBCP 2](log4j-jdbc-dbcp2/apidocs/index.html) | Connection source for the JDBC Appender using Apache Commons DBCP2. +[Log4j Liquibase Binding](log4j-liquibase/apidocs/index.html) | The Apache Log4j Liquibase binding to Log4j 2 Core. +[Log4j MongoDB 2 Support](log4j-mongodb2/apidocs/index.html) | Additional Appender for MongoDB using the version 2 driver. +[Log4j MongoDB 3 Support](log4j-mongodb3/apidocs/index.html) | Additional Appender for MongoDB using the version 3 driver. [Log4j Cassandra Support](log4j-cassandra/apidocs/index.html) | Additional Appender for Cassandra. From fd3a82bff93e159250451c104cfd228de11689a8 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 10 Mar 2018 12:31:48 -0700 Subject: [PATCH 0098/2347] Fix OSGi tests. --- log4j-core/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index b0813d4309c..7497d20bdb4 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -452,6 +452,7 @@ org.apache.logging.log4j.core.* sun.reflect;resolution:=optional, + org.apache.logging.log4j.util, * org.apache.logging.log4j.core.osgi.Activator From 9ed183774830b53927e871e303272276cb835603 Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sun, 11 Mar 2018 12:36:03 -0700 Subject: [PATCH 0099/2347] LOG4J2-2104 - LoaderUtil was improperly looping over classloaders --- .../main/java/org/apache/logging/log4j/util/LoaderUtil.java | 3 ++- src/changes/changes.xml | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java index 762670475c9..2a153b1bfb3 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java @@ -117,9 +117,10 @@ public static ClassLoader[] getClassLoaders() { classLoaders.add(parent); } } - ClassLoader parent = tcl; + ClassLoader parent = tcl.getParent(); while (parent != null && !classLoaders.contains(parent)) { classLoaders.add(parent); + parent = parent.getParent(); } if (!classLoaders.contains(ClassLoader.getSystemClassLoader())) { classLoaders.add(ClassLoader.getSystemClassLoader()); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 49c8d9009cd..554ba35b9d6 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -102,6 +102,9 @@ + + LoaderUtil was not looping properly over classloaders. + Documentation fix in manual page for custom configurations. From af12af4ca0162e595102afee3c022850e5fb3a7a Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sat, 17 Mar 2018 19:43:19 -0700 Subject: [PATCH 0100/2347] Fix site issues. Add articles --- src/site/markdown/articles.md | 8 ++++++++ src/site/site.xml | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/site/markdown/articles.md b/src/site/markdown/articles.md index fb04a0384f3..cd70431d224 100644 --- a/src/site/markdown/articles.md +++ b/src/site/markdown/articles.md @@ -44,6 +44,14 @@ guide for up-to-date and detailed information on how to configure and use Log4j ## English +* [Tales from the Field: Migrating from Log4J to Log4J2](https://www.javacodegeeks.com/2018/03/tales-from-the-field-migrating-from-log4j-to-log4j2.html) +(March 12th, 2018) +* [Log4J2 and Java configuration with properties file](https://www.youtube.com/watch?v=sdOiA1Xql0o) +(February 18, 2018) +* [Apache Log4j 2 Configuration| Log4j2 with JDK 9.0](https://www.youtube.com/watch?v=BbcSNOtEGWs) +(January 8, 2018) +* [Spring Boot - log4j 2 configuration example](https://www.youtube.com/watch?v=KKO5wGi_vEc) +(December 30,2017) * [Log4j 2 Best Practices example](https://examples.javacodegeeks.com/enterprise-java/log4j/log4j-2-best-practices-example/) (November 14, 2017) * [Intro to Log4j2 - Appenders, Layouts and Filters](http://www.baeldung.com/log4j2-appenders-layouts-filters) diff --git a/src/site/site.xml b/src/site/site.xml index b30d20147c9..66841fa0bf2 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -21,7 +21,7 @@ xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd"> - + @@ -285,7 +285,8 @@ - + + @@ -306,7 +307,6 @@ - From 7002fb555e6254adae1dedb552aba0345df78f4c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 13 Mar 2018 22:23:02 +0100 Subject: [PATCH 0101/2347] LOG4J2-2268 - Improve error msg if invalid value --- .../log4j/core/config/plugins/util/PluginBuilder.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java index ebaabe90155..443c612d3f3 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java @@ -23,6 +23,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -165,6 +166,7 @@ private void injectFields(final Builder builder) throws IllegalAccessExceptio AccessibleObject.setAccessible(fields.toArray(new Field[] {}), true); final StringBuilder log = new StringBuilder(); boolean invalid = false; + String reason = ""; for (final Field field : fields) { log.append(log.length() == 0 ? simpleName(builder) + "(" : ", "); final Annotation[] annotations = field.getDeclaredAnnotations(); @@ -194,13 +196,17 @@ private void injectFields(final Builder builder) throws IllegalAccessExceptio for (final ConstraintValidator validator : validators) { if (!validator.isValid(field.getName(), value)) { invalid = true; + if (!reason.isEmpty()) { + reason += ", "; + } + reason += "field '" + field.getName() + "' has invalid value '" + value + "'"; } } } log.append(log.length() == 0 ? builder.getClass().getSimpleName() + "()" : ")"); LOGGER.debug(log.toString()); if (invalid) { - throw new ConfigurationException("Arguments given for element " + node.getName() + " are invalid"); + throw new ConfigurationException("Arguments given for element " + node.getName() + " are invalid: " + reason); } checkForRemainingAttributes(); verifyNodeChildrenUsed(); From d4cbbfa5d0df614e99fb0265ac3a1617351970e8 Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Sun, 18 Mar 2018 11:17:15 -0700 Subject: [PATCH 0102/2347] Closes #160 --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 554ba35b9d6..1f1d1608880 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -31,6 +31,9 @@ - "remove" - Removed --> + + Improve plugin error message when elements are missing. + Use Spotbugs instead of Findbugs. Minimum version is Java 8. From 80d025ba68fc12d7b4d767fb25455306878279e1 Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Tue, 20 Mar 2018 16:47:33 -0600 Subject: [PATCH 0103/2347] [LOG4J2-2283] ParserConfigurationException when using Log4j with oracle.xml.jaxp.JXDocumentBuilderFactory. --- .../logging/log4j/core/config/xml/XmlConfiguration.java | 7 ++----- src/changes/changes.xml | 3 +++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java index 7efb6aba01f..07d5740c95f 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java @@ -199,7 +199,7 @@ static DocumentBuilder newDocumentBuilder(final boolean xIncludeAware) throws Pa return factory.newDocumentBuilder(); } - private static void disableDtdProcessing(final DocumentBuilderFactory factory) throws ParserConfigurationException { + private static void disableDtdProcessing(final DocumentBuilderFactory factory) { factory.setValidating(false); factory.setExpandEntityReferences(false); setFeature(factory, "http://xml.org/sax/features/external-general-entities", false); @@ -207,12 +207,9 @@ private static void disableDtdProcessing(final DocumentBuilderFactory factory) t setFeature(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); } - private static void setFeature(final DocumentBuilderFactory factory, final String featureName, final boolean value) - throws ParserConfigurationException { + private static void setFeature(final DocumentBuilderFactory factory, final String featureName, final boolean value) { try { factory.setFeature(featureName, value); - } catch (ParserConfigurationException e) { - throw e; } catch (Exception | LinkageError e) { getStatusLogger().error("Caught {} setting feature {} to {} on DocumentBuilderFactory {}: {}", e.getClass().getCanonicalName(), featureName, value, factory, e, e); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1f1d1608880..83dc4d7ff7b 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -103,6 +103,9 @@ Move ProcessIdUtil from log4j-api to log4j-core. + + ParserConfigurationException when using Log4j with oracle.xml.jaxp.JXDocumentBuilderFactory. + From 445395c709b9550f30a3bb70d7ca23d2c5854368 Mon Sep 17 00:00:00 2001 From: rpopma Date: Wed, 21 Mar 2018 20:07:40 +0900 Subject: [PATCH 0104/2347] [BUILD] removed picocli tests from core tests; they do not add value here and occasionally fail when building Log4j on a console that supports ANSI colors (cherry picked from commit dd8ded9) --- .../tools/picocli/CommandLineArityTest.java | 898 ----- .../tools/picocli/CommandLineHelpTest.java | 2536 ------------- .../core/tools/picocli/CommandLineTest.java | 3188 ----------------- .../core/tools/picocli/CustomLayoutDemo.java | 264 -- .../log4j/core/tools/picocli/Demo.java | 719 ---- 5 files changed, 7605 deletions(-) delete mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java delete mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java delete mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineTest.java delete mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CustomLayoutDemo.java delete mode 100644 log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/Demo.java diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java deleted file mode 100644 index e35b5934e78..00000000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java +++ /dev/null @@ -1,898 +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.tools.picocli; - -import java.io.File; -import java.net.InetAddress; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.*; - -import static org.junit.Assert.*; - -public class CommandLineArityTest { - @Before public void setUp() { System.clearProperty("picocli.trace"); } - @After public void tearDown() { System.clearProperty("picocli.trace"); } - - private static void setTraceLevel(String level) { - System.setProperty("picocli.trace", level); - } - @Test - public void testArityConstructor_fixedRange() { - Range arity = new Range(1, 23, false, false, null); - assertEquals("min", 1, arity.min); - assertEquals("max", 23, arity.max); - assertEquals("1..23", arity.toString()); - assertEquals(Range.valueOf("1..23"), arity); - } - @Test - public void testArityConstructor_variableRange() { - Range arity = new Range(1, Integer.MAX_VALUE, true, false, null); - assertEquals("min", 1, arity.min); - assertEquals("max", Integer.MAX_VALUE, arity.max); - assertEquals("1..*", arity.toString()); - assertEquals(Range.valueOf("1..*"), arity); - } - @Test - public void testArityForOption_booleanFieldImplicitArity0() throws Exception { - Range arity = Range.optionArity(CommandLineTest.SupportedTypes.class.getDeclaredField("booleanField")); - assertEquals(Range.valueOf("0"), arity); - assertEquals("0", arity.toString()); - } - @Test - public void testArityForOption_intFieldImplicitArity1() throws Exception { - Range arity = Range.optionArity(CommandLineTest.SupportedTypes.class.getDeclaredField("intField")); - assertEquals(Range.valueOf("1"), arity); - assertEquals("1", arity.toString()); - } - @Test - public void testArityForOption_isExplicitlyDeclaredValue() throws Exception { - class Params { - @Option(names = "-timeUnitList", type = TimeUnit.class, arity = "3") List timeUnitList; - } - Range arity = Range.optionArity(Params.class.getDeclaredField("timeUnitList")); - assertEquals(Range.valueOf("3"), arity); - assertEquals("3", arity.toString()); - } - @Test - public void testArityForOption_listFieldImplicitArity1() throws Exception { - class ImplicitList { @Option(names = "-a") List listIntegers; } - Range arity = Range.optionArity(ImplicitList.class.getDeclaredField("listIntegers")); - assertEquals(Range.valueOf("1"), arity); - assertEquals("1", arity.toString()); - } - @Test - public void testArityForOption_arrayFieldImplicitArity1() throws Exception { - class ImplicitList { @Option(names = "-a") int[] intArray; } - Range arity = Range.optionArity(ImplicitList.class.getDeclaredField("intArray")); - assertEquals(Range.valueOf("1"), arity); - assertEquals("1", arity.toString()); - } - @Test - public void testArityForParameters_booleanFieldImplicitArity1() throws Exception { - class ImplicitBoolField { @Parameters boolean boolSingleValue; } - Range arity = Range.parameterArity(ImplicitBoolField.class.getDeclaredField("boolSingleValue")); - assertEquals(Range.valueOf("1"), arity); - assertEquals("1", arity.toString()); - } - @Test - public void testArityForParameters_intFieldImplicitArity1() throws Exception { - class ImplicitSingleField { @Parameters int intSingleValue; } - Range arity = Range.parameterArity(ImplicitSingleField.class.getDeclaredField("intSingleValue")); - assertEquals(Range.valueOf("1"), arity); - assertEquals("1", arity.toString()); - } - @Test - public void testArityForParameters_listFieldImplicitArity0_1() throws Exception { - class Params { - @Parameters(type = Integer.class) List list; - } - Range arity = Range.parameterArity(Params.class.getDeclaredField("list")); - assertEquals(Range.valueOf("0..1"), arity); - assertEquals("0..1", arity.toString()); - } - @Test - public void testArityForParameters_arrayFieldImplicitArity0_1() throws Exception { - class Args { - @Parameters File[] inputFiles; - } - Range arity = Range.parameterArity(Args.class.getDeclaredField("inputFiles")); - assertEquals(Range.valueOf("0..1"), arity); - assertEquals("0..1", arity.toString()); - } - @Test - public void testArrayOptionsWithArity0_nConsumeAllArguments() { - final double[] DEFAULT_PARAMS = new double[] {1, 2}; - class ArrayOptionsArity0_nAndParameters { - @Parameters double[] doubleParams = DEFAULT_PARAMS; - @Option(names = "-doubles", arity = "0..*") double[] doubleOptions; - } - ArrayOptionsArity0_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionsArity0_nAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001); - assertArrayEquals(DEFAULT_PARAMS, params.doubleParams, 0.000001); - } - - @Test - public void testArrayOptionsWithArity1_nConsumeAllArguments() { - class ArrayOptionsArity1_nAndParameters { - @Parameters double[] doubleParams; - @Option(names = "-doubles", arity = "1..*") double[] doubleOptions; - } - ArrayOptionsArity1_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionsArity1_nAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001); - assertArrayEquals(null, params.doubleParams, 0.000001); - } - - @Test - public void testArrayOptionsWithArity2_nConsumeAllArguments() { - class ArrayOptionsArity2_nAndParameters { - @Parameters double[] doubleParams; - @Option(names = "-doubles", arity = "2..*") double[] doubleOptions; - } - ArrayOptionsArity2_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionsArity2_nAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001); - assertArrayEquals(null, params.doubleParams, 0.000001); - } - - @Test - public void testArrayOptionArity2_nConsumesAllArgumentsUpToClusteredOption() { - class ArrayOptionsArity2_nAndParameters { - @Parameters String[] stringParams; - @Option(names = "-s", arity = "2..*") String[] stringOptions; - @Option(names = "-v") boolean verbose; - @Option(names = "-f") File file; - } - ArrayOptionsArity2_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionsArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 -vfFILE 5.5".split(" ")); - assertArrayEquals(Arrays.toString(params.stringOptions), - new String[] {"1.1", "2.2", "3.3", "4.4"}, params.stringOptions); - assertTrue(params.verbose); - assertEquals(new File("FILE"), params.file); - assertArrayEquals(new String[] {"5.5"}, params.stringParams); - } - - @Test - public void testArrayOptionArity2_nConsumesAllArgumentIncludingQuotedSimpleOption() { - class ArrayOptionArity2_nAndParameters { - @Parameters String[] stringParams; - @Option(names = "-s", arity = "2..*") String[] stringOptions; - @Option(names = "-v") boolean verbose; - @Option(names = "-f") File file; - } - ArrayOptionArity2_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 \"-v\" \"-f\" \"FILE\" 5.5".split(" ")); - assertArrayEquals(Arrays.toString(params.stringOptions), - new String[] {"1.1", "2.2", "3.3", "4.4", "-v", "-f", "FILE", "5.5"}, params.stringOptions); - assertFalse("verbose", params.verbose); - assertNull("file", params.file); - assertArrayEquals(null, params.stringParams); - } - - @Test - public void testArrayOptionArity2_nConsumesAllArgumentIncludingQuotedClusteredOption() { - class ArrayOptionArity2_nAndParameters { - @Parameters String[] stringParams; - @Option(names = "-s", arity = "2..*") String[] stringOptions; - @Option(names = "-v") boolean verbose; - @Option(names = "-f") File file; - } - ArrayOptionArity2_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 \"-vfFILE\" 5.5".split(" ")); - assertArrayEquals(Arrays.toString(params.stringOptions), - new String[] {"1.1", "2.2", "3.3", "4.4", "-vfFILE", "5.5"}, params.stringOptions); - assertFalse("verbose", params.verbose); - assertNull("file", params.file); - assertArrayEquals(null, params.stringParams); - } - - @Test - public void testArrayOptionArity2_nConsumesAllArgumentsUpToNextSimpleOption() { - class ArrayOptionArity2_nAndParameters { - @Parameters double[] doubleParams; - @Option(names = "-s", arity = "2..*") String[] stringOptions; - @Option(names = "-v") boolean verbose; - @Option(names = "-f") File file; - } - ArrayOptionArity2_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 -v -f=FILE 5.5".split(" ")); - assertArrayEquals(Arrays.toString(params.stringOptions), - new String[] {"1.1", "2.2", "3.3", "4.4"}, params.stringOptions); - assertTrue(params.verbose); - assertEquals(new File("FILE"), params.file); - assertArrayEquals(new double[] {5.5}, params.doubleParams, 0.000001); - } - - @Test - public void testArrayOptionArity2_nConsumesAllArgumentsUpToNextOptionWithAttachment() { - class ArrayOptionArity2_nAndParameters { - @Parameters double[] doubleParams; - @Option(names = "-s", arity = "2..*") String[] stringOptions; - @Option(names = "-v") boolean verbose; - @Option(names = "-f") File file; - } - ArrayOptionArity2_nAndParameters - params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 -f=FILE -v 5.5".split(" ")); - assertArrayEquals(Arrays.toString(params.stringOptions), - new String[] {"1.1", "2.2", "3.3", "4.4"}, params.stringOptions); - assertTrue(params.verbose); - assertEquals(new File("FILE"), params.file); - assertArrayEquals(new double[] {5.5}, params.doubleParams, 0.000001); - } - - @Test - public void testArrayOptionArityNConsumeAllArguments() { - class ArrayOptionArityNAndParameters { - @Parameters char[] charParams; - @Option(names = "-chars", arity = "*") char[] charOptions; - } - ArrayOptionArityNAndParameters - params = CommandLine.populateCommand(new ArrayOptionArityNAndParameters(), "-chars a b c d".split(" ")); - assertArrayEquals(Arrays.toString(params.charOptions), - new char[] {'a', 'b', 'c', 'd'}, params.charOptions); - assertArrayEquals(null, params.charParams); - } - @Test - public void testMissingRequiredParams() { - class Example { - @Parameters(index = "1", arity = "0..1") String optional; - @Parameters(index = "0") String mandatory; - } - try { CommandLine.populateCommand(new Example(), new String[] {"mandatory"}); } - catch (MissingParameterException ex) { fail(); } - - try { - CommandLine.populateCommand(new Example(), new String[0]); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameter: ", ex.getMessage()); - } - } - @Test - public void testMissingRequiredParams1() { - class Tricky1 { - @Parameters(index = "2") String anotherMandatory; - @Parameters(index = "1", arity = "0..1") String optional; - @Parameters(index = "0") String mandatory; - } - try { - CommandLine.populateCommand(new Tricky1(), new String[0]); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameters: , ", ex.getMessage()); - } - try { - CommandLine.populateCommand(new Tricky1(), new String[] {"firstonly"}); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameter: ", ex.getMessage()); - } - } - @Test - public void testMissingRequiredParams2() { - class Tricky2 { - @Parameters(index = "2", arity = "0..1") String anotherOptional; - @Parameters(index = "1", arity = "0..1") String optional; - @Parameters(index = "0") String mandatory; - } - try { CommandLine.populateCommand(new Tricky2(), new String[] {"mandatory"}); } - catch (MissingParameterException ex) { fail(); } - - try { - CommandLine.populateCommand(new Tricky2(), new String[0]); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameter: ", ex.getMessage()); - } - } - @Test - public void testMissingRequiredParamsWithOptions() { - class Tricky3 { - @Option(names="-v") boolean more; - @Option(names="-t") boolean any; - @Parameters(index = "1") String alsoMandatory; - @Parameters(index = "0") String mandatory; - } - try { - CommandLine.populateCommand(new Tricky3(), new String[] {"-t", "-v", "mandatory"}); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameter: ", ex.getMessage()); - } - - try { - CommandLine.populateCommand(new Tricky3(), new String[] { "-t", "-v"}); - fail("Should not accept missing two mandatory parameters"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameters: , ", ex.getMessage()); - } - } - @Test - public void testMissingRequiredParamWithOption() { - class Tricky3 { - @Option(names="-t") boolean any; - @Parameters(index = "0") String mandatory; - } - try { - CommandLine.populateCommand(new Tricky3(), new String[] {"-t"}); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameter: ", ex.getMessage()); - } - } - @Test - public void testNoMissingRequiredParamErrorIfHelpOptionSpecified() { - class App { - @Parameters(hidden = true) // "hidden": don't show this parameter in usage help message - List allParameters; // no "index" attribute: captures _all_ arguments (as Strings) - - @Parameters(index = "0") InetAddress host; - @Parameters(index = "1") int port; - @Parameters(index = "2..*") File[] files; - - @Option(names = "-?", help = true) boolean help; - } - CommandLine.populateCommand(new App(), new String[] {"-?"}); - try { - CommandLine.populateCommand(new App(), new String[0]); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameters: , ", ex.getMessage()); - } - } - @Test - public void testNoMissingRequiredParamErrorWithLabelIfHelpOptionSpecified() { - class App { - @Parameters(hidden = true) // "hidden": don't show this parameter in usage help message - List allParameters; // no "index" attribute: captures _all_ arguments (as Strings) - - @Parameters(index = "0", paramLabel = "HOST") InetAddress host; - @Parameters(index = "1", paramLabel = "PORT") int port; - @Parameters(index = "2..*", paramLabel = "FILES") File[] files; - - @Option(names = "-?", help = true) boolean help; - } - CommandLine.populateCommand(new App(), new String[] {"-?"}); - try { - CommandLine.populateCommand(new App(), new String[0]); - fail("Should not accept missing mandatory parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameters: HOST, PORT", ex.getMessage()); - } - } - - private static class BooleanOptionsArity0_nAndParameters { - @Parameters String[] params; - @Option(names = "-bool", arity = "0..*") boolean bool; - @Option(names = {"-v", "-other"}, arity="0..*") boolean vOrOther; - @Option(names = "-r") boolean rBoolean; - } - @Test - public void testBooleanOptionsArity0_nConsume1ArgumentIfPossible() { // ignores varargs - BooleanOptionsArity0_nAndParameters - params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool false false true".split(" ")); - assertFalse(params.bool); - assertArrayEquals(new String[]{ "false", "true"}, params.params); - } - @Test - public void testBooleanOptionsArity0_nRequiresNoArgument() { // ignores varargs - BooleanOptionsArity0_nAndParameters - params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool".split(" ")); - assertTrue(params.bool); - } - @Test - public void testBooleanOptionsArity0_nConsume0ArgumentsIfNextArgIsOption() { // ignores varargs - BooleanOptionsArity0_nAndParameters - params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool -other".split(" ")); - assertTrue(params.bool); - assertTrue(params.vOrOther); - } - @Test - public void testBooleanOptionsArity0_nConsume0ArgumentsIfNextArgIsParameter() { // ignores varargs - BooleanOptionsArity0_nAndParameters - params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool 123 -other".split(" ")); - assertTrue(params.bool); - assertTrue(params.vOrOther); - assertArrayEquals(new String[]{ "123"}, params.params); - } - @Test - public void testBooleanOptionsArity0_nFailsIfAttachedParamNotABoolean() { // ignores varargs - try { - CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool=123 -other".split(" ")); - fail("was able to assign 123 to boolean"); - } catch (CommandLine.ParameterException ex) { - assertEquals("'123' is not a boolean for option '-bool'", ex.getMessage()); - } - } - @Test - public void testBooleanOptionsArity0_nShortFormFailsIfAttachedParamNotABoolean() { // ignores varargs - try { - CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-rv234 -bool".split(" ")); - fail("Expected exception"); - } catch (UnmatchedArgumentException ok) { - assertEquals("Unmatched argument [-234]", ok.getMessage()); - } - } - @Test - public void testBooleanOptionsArity0_nShortFormFailsIfAttachedParamNotABooleanWithUnmatchedArgsAllowed() { // ignores varargs - setTraceLevel("OFF"); - CommandLine cmd = new CommandLine(new BooleanOptionsArity0_nAndParameters()).setUnmatchedArgumentsAllowed(true); - cmd.parse("-rv234 -bool".split(" ")); - assertEquals(Arrays.asList("-234"), cmd.getUnmatchedArguments()); - } - @Test - public void testBooleanOptionsArity0_nShortFormFailsIfAttachedWithSepParamNotABoolean() { // ignores varargs - try { - CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-rv=234 -bool".split(" ")); - fail("was able to assign 234 to boolean"); - } catch (CommandLine.ParameterException ex) { - assertEquals("'234' is not a boolean for option '-v'", ex.getMessage()); - } - } - - private static class BooleanOptionsArity1_nAndParameters { - @Parameters boolean[] boolParams; - @Option(names = "-bool", arity = "1..*") boolean aBoolean; - } - @Test - public void testBooleanOptionsArity1_nConsume1Argument() { // ignores varargs - BooleanOptionsArity1_nAndParameters - params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool false false true".split(" ")); - assertFalse(params.aBoolean); - assertArrayEquals(new boolean[]{ false, true}, params.boolParams); - - params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool true false true".split(" ")); - assertTrue(params.aBoolean); - assertArrayEquals(new boolean[]{ false, true}, params.boolParams); - } - @Test - public void testBooleanOptionsArity1_nCaseInsensitive() { // ignores varargs - BooleanOptionsArity1_nAndParameters - params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool fAlsE false true".split(" ")); - assertFalse(params.aBoolean); - assertArrayEquals(new boolean[]{ false, true}, params.boolParams); - - params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool FaLsE false true".split(" ")); - assertFalse(params.aBoolean); - assertArrayEquals(new boolean[]{ false, true}, params.boolParams); - - params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool tRuE false true".split(" ")); - assertTrue(params.aBoolean); - assertArrayEquals(new boolean[]{ false, true}, params.boolParams); - } - @Test - public void testBooleanOptionsArity1_nErrorIfValueNotTrueOrFalse() { // ignores varargs - try { - CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool abc".split(" ")); - fail("Invalid format abc was accepted for boolean"); - } catch (CommandLine.ParameterException expected) { - assertEquals("'abc' is not a boolean for option '-bool'", expected.getMessage()); - } - } - @Test - public void testBooleanOptionsArity1_nErrorIfValueMissing() { - try { - CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool".split(" ")); - fail("Missing param was accepted for boolean with arity=1"); - } catch (CommandLine.ParameterException expected) { - assertEquals("Missing required parameter for option '-bool' at index 0 ()", expected.getMessage()); - } - } - - @Test - public void testBooleanOptionArity0Consumes0Arguments() { - class BooleanOptionArity0AndParameters { - @Parameters boolean[] boolParams; - @Option(names = "-bool", arity = "0") boolean aBoolean; - } - BooleanOptionArity0AndParameters - params = CommandLine.populateCommand(new BooleanOptionArity0AndParameters(), "-bool true false true".split(" ")); - assertTrue(params.aBoolean); - assertArrayEquals(new boolean[]{true, false, true}, params.boolParams); - } - @Test(expected = MissingParameterException.class) - public void testSingleValueFieldDefaultMinArityIs1() { - CommandLine.populateCommand(new CommandLineTest.SupportedTypes(), "-Long"); - } - @Test - public void testSingleValueFieldDefaultMinArityIsOne() { - try { - CommandLine.populateCommand(new CommandLineTest.SupportedTypes(), "-Long", "-boolean"); - fail("should fail"); - } catch (CommandLine.ParameterException ex) { - assertEquals("Could not convert '-boolean' to Long for option '-Long'" + - ": java.lang.NumberFormatException: For input string: \"-boolean\"", ex.getMessage()); - } - } - - @Test - public void testIntOptionArity1_nConsumes1Argument() { // ignores varargs - class IntOptionArity1_nAndParameters { - @Parameters int[] intParams; - @Option(names = "-int", arity = "1..*") int anInt; - } - IntOptionArity1_nAndParameters - params = CommandLine.populateCommand(new IntOptionArity1_nAndParameters(), "-int 23 42 7".split(" ")); - assertEquals(23, params.anInt); - assertArrayEquals(new int[]{ 42, 7}, params.intParams); - } - - @Test - public void testArrayOptionsWithArity0Consume0Arguments() { - class OptionsArray0ArityAndParameters { - @Parameters double[] doubleParams; - @Option(names = "-doubles", arity = "0") double[] doubleOptions; - } - OptionsArray0ArityAndParameters - params = CommandLine.populateCommand(new OptionsArray0ArityAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[0], params.doubleOptions, 0.000001); - assertArrayEquals(new double[]{1.1, 2.2, 3.3, 4.4}, params.doubleParams, 0.000001); - } - - @Test - public void testArrayOptionWithArity1Consumes1Argument() { - class Options1ArityAndParameters { - @Parameters double[] doubleParams; - @Option(names = "-doubles", arity = "1") double[] doubleOptions; - } - Options1ArityAndParameters - params = CommandLine.populateCommand(new Options1ArityAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1}, params.doubleOptions, 0.000001); - assertArrayEquals(new double[]{2.2, 3.3, 4.4}, params.doubleParams, 0.000001); - - // repeated occurrence - params = CommandLine.populateCommand(new Options1ArityAndParameters(), "-doubles 1.1 -doubles 2.2 -doubles 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, 3.3}, params.doubleOptions, 0.000001); - assertArrayEquals(new double[]{4.4}, params.doubleParams, 0.000001); - - } - - private static class ArrayOptionArity2AndParameters { - @Parameters double[] doubleParams; - @Option(names = "-doubles", arity = "2") double[] doubleOptions; - } - @Test - public void testArrayOptionWithArity2Consumes2Arguments() { - ArrayOptionArity2AndParameters - params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, }, params.doubleOptions, 0.000001); - assertArrayEquals(new double[]{3.3, 4.4}, params.doubleParams, 0.000001); - - // repeated occurrence - params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles 1.1 2.2 -doubles 3.3 4.4 0".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, 3.3, 4.4 }, params.doubleOptions, 0.000001); - assertArrayEquals(new double[]{ 0.0 }, params.doubleParams, 0.000001); - } - @Test - public void testArrayOptionsWithArity2Consume2ArgumentsEvenIfFirstIsAttached() { - ArrayOptionArity2AndParameters - params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles=1.1 2.2 3.3 4.4".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, }, params.doubleOptions, 0.000001); - assertArrayEquals(new double[]{3.3, 4.4}, params.doubleParams, 0.000001); - - // repeated occurrence - params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles=1.1 2.2 -doubles=3.3 4.4 0".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001); - assertArrayEquals(new double[]{0}, params.doubleParams, 0.000001); - } - /** Arity should not limit the total number of values put in an array or collection #191 */ - @Test - public void testArrayOptionsWithArity2MayContainMoreThan2Values() { - ArrayOptionArity2AndParameters - params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles=1 2 -doubles 3 4 -doubles 5 6".split(" ")); - assertArrayEquals(Arrays.toString(params.doubleOptions), - new double[] {1, 2, 3, 4, 5, 6 }, params.doubleOptions, 0.000001); - assertArrayEquals(null, params.doubleParams, 0.000001); - } - - @Test - public void testArrayOptionWithoutArityConsumesOneArgument() { // #192 - class OptionsNoArityAndParameters { - @Parameters char[] charParams; - @Option(names = "-chars") char[] charOptions; - } - OptionsNoArityAndParameters - params = CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars a b c d".split(" ")); - assertArrayEquals(Arrays.toString(params.charOptions), - new char[] {'a', }, params.charOptions); - assertArrayEquals(Arrays.toString(params.charParams), new char[] {'b', 'c', 'd'}, params.charParams); - - // repeated occurrence - params = CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars a -chars b c d".split(" ")); - assertArrayEquals(Arrays.toString(params.charOptions), - new char[] {'a', 'b', }, params.charOptions); - assertArrayEquals(Arrays.toString(params.charParams), new char[] {'c', 'd'}, params.charParams); - - try { - CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars".split(" ")); - fail("expected MissingParameterException"); - } catch (MissingParameterException ok) { - assertEquals("Missing required parameter for option '-chars' ()", ok.getMessage()); - } - } - - @Test - public void testArrayParametersWithDefaultArity() { - class ArrayParamsDefaultArity { - @Parameters - List params; - } - ArrayParamsDefaultArity params = CommandLine.populateCommand(new ArrayParamsDefaultArity(), "a", "b", "c"); - assertEquals(Arrays.asList("a", "b", "c"), params.params); - - params = CommandLine.populateCommand(new ArrayParamsDefaultArity(), "a"); - assertEquals(Arrays.asList("a"), params.params); - - params = CommandLine.populateCommand(new ArrayParamsDefaultArity()); - assertEquals(null, params.params); - } - - @Test - public void testArrayParametersWithArityMinusOneToN() { - class ArrayParamsNegativeArity { - @Parameters(arity = "-1..*") - List params; - } - ArrayParamsNegativeArity params = CommandLine.populateCommand(new ArrayParamsNegativeArity(), "a", "b", "c"); - assertEquals(Arrays.asList("a", "b", "c"), params.params); - - params = CommandLine.populateCommand(new ArrayParamsNegativeArity(), "a"); - assertEquals(Arrays.asList("a"), params.params); - - params = CommandLine.populateCommand(new ArrayParamsNegativeArity()); - assertEquals(null, params.params); - } - - @Test - public void testArrayParametersArity0_n() { - class ArrayParamsArity0_n { - @Parameters(arity = "0..*") - List params; - } - ArrayParamsArity0_n params = CommandLine.populateCommand(new ArrayParamsArity0_n(), "a", "b", "c"); - assertEquals(Arrays.asList("a", "b", "c"), params.params); - - params = CommandLine.populateCommand(new ArrayParamsArity0_n(), "a"); - assertEquals(Arrays.asList("a"), params.params); - - params = CommandLine.populateCommand(new ArrayParamsArity0_n()); - assertEquals(null, params.params); - } - - @Test - public void testArrayParametersArity1_n() { - class ArrayParamsArity1_n { - @Parameters(arity = "1..*") - List params; - } - ArrayParamsArity1_n params = CommandLine.populateCommand(new ArrayParamsArity1_n(), "a", "b", "c"); - assertEquals(Arrays.asList("a", "b", "c"), params.params); - - params = CommandLine.populateCommand(new ArrayParamsArity1_n(), "a"); - assertEquals(Arrays.asList("a"), params.params); - - try { - params = CommandLine.populateCommand(new ArrayParamsArity1_n()); - fail("Should not accept input with missing parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameters at positions 0..*: ", ex.getMessage()); - } - } - - @Test - public void testArrayParametersArity2_n() { - class ArrayParamsArity2_n { - @Parameters(arity = "2..*") - List params; - } - ArrayParamsArity2_n params = CommandLine.populateCommand(new ArrayParamsArity2_n(), "a", "b", "c"); - assertEquals(Arrays.asList("a", "b", "c"), params.params); - - try { - params = CommandLine.populateCommand(new ArrayParamsArity2_n(), "a"); - fail("Should not accept input with missing parameter"); - } catch (MissingParameterException ex) { - assertEquals("positional parameter at index 0..* () requires at least 2 values, but only 1 were specified: [a]", ex.getMessage()); - } - - try { - params = CommandLine.populateCommand(new ArrayParamsArity2_n()); - fail("Should not accept input with missing parameter"); - } catch (MissingParameterException ex) { - assertEquals("positional parameter at index 0..* () requires at least 2 values, but none were specified.", ex.getMessage()); - } - } - - @Test - public void testNonVarargArrayParametersWithNegativeArityConsumesZeroArguments() { - class NonVarArgArrayParamsNegativeArity { - @Parameters(arity = "-1") - List params; - } - try { - CommandLine.populateCommand(new NonVarArgArrayParamsNegativeArity(), "a", "b", "c"); - fail("Expected UnmatchedArgumentException"); - } catch (UnmatchedArgumentException ex) { - assertEquals("Unmatched arguments [a, b, c]", ex.getMessage()); - } - try { - CommandLine.populateCommand(new NonVarArgArrayParamsNegativeArity(), "a"); - fail("Expected UnmatchedArgumentException"); - } catch (UnmatchedArgumentException ex) { - assertEquals("Unmatched argument [a]", ex.getMessage()); - } - NonVarArgArrayParamsNegativeArity params = CommandLine.populateCommand(new NonVarArgArrayParamsNegativeArity()); - assertEquals(null, params.params); - } - - @Test - public void testNonVarargArrayParametersWithArity0() { - class NonVarArgArrayParamsZeroArity { - @Parameters(arity = "0") - List params; - } - try { - CommandLine.populateCommand(new NonVarArgArrayParamsZeroArity(), "a", "b", "c"); - fail("Expected UnmatchedArgumentException"); - } catch (UnmatchedArgumentException ex) { - assertEquals("Unmatched arguments [a, b, c]", ex.getMessage()); - } - try { - CommandLine.populateCommand(new NonVarArgArrayParamsZeroArity(), "a"); - fail("Expected UnmatchedArgumentException"); - } catch (UnmatchedArgumentException ex) { - assertEquals("Unmatched argument [a]", ex.getMessage()); - } - NonVarArgArrayParamsZeroArity params = CommandLine.populateCommand(new NonVarArgArrayParamsZeroArity()); - assertEquals(null, params.params); - } - - @Test - public void testNonVarargArrayParametersWithArity1() { - class NonVarArgArrayParamsArity1 { - @Parameters(arity = "1") - List params; - } - NonVarArgArrayParamsArity1 actual = CommandLine.populateCommand(new NonVarArgArrayParamsArity1(), "a", "b", "c"); - assertEquals(Arrays.asList("a", "b", "c"), actual.params); - - NonVarArgArrayParamsArity1 params = CommandLine.populateCommand(new NonVarArgArrayParamsArity1(), "a"); - assertEquals(Arrays.asList("a"), params.params); - - try { - params = CommandLine.populateCommand(new NonVarArgArrayParamsArity1()); - fail("Should not accept input with missing parameter"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameter: ", ex.getMessage()); - } - } - - @Test - public void testNonVarargArrayParametersWithArity2() { - class NonVarArgArrayParamsArity2 { - @Parameters(arity = "2") - List params; - } - NonVarArgArrayParamsArity2 params = null; - try { - CommandLine.populateCommand(new NonVarArgArrayParamsArity2(), "a", "b", "c"); - fail("expected MissingParameterException"); - } catch (MissingParameterException ex) { - assertEquals("positional parameter at index 0..* () requires at least 2 values, but only 1 were specified: [c]", ex.getMessage()); - } - - try { - params = CommandLine.populateCommand(new NonVarArgArrayParamsArity2(), "a"); - fail("Should not accept input with missing parameter"); - } catch (MissingParameterException ex) { - assertEquals("positional parameter at index 0..* () requires at least 2 values, but only 1 were specified: [a]", ex.getMessage()); - } - - try { - params = CommandLine.populateCommand(new NonVarArgArrayParamsArity2()); - fail("Should not accept input with missing parameter"); - } catch (MissingParameterException ex) { - assertEquals("positional parameter at index 0..* () requires at least 2 values, but none were specified.", ex.getMessage()); - } - } - @Test - public void testMixPositionalParamsWithOptions_ParamsUnboundedArity_isGreedy() { - class Arg { - @Parameters(arity = "1..*") List parameters; - @Option(names = "-o") List options; - } - Arg result = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3", "p4"); - assertEquals(Arrays.asList("p1", "p2", "-o", "v2", "p3", "p4"), result.parameters); - assertEquals(Arrays.asList("v1"), result.options); - - Arg result2 = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "-o", "v2", "p3"); - assertEquals(Arrays.asList("p1", "-o", "v2", "p3"), result2.parameters); - assertEquals(Arrays.asList("v1"), result2.options); - - try { - CommandLine.populateCommand(new Arg(), "-o", "v1", "-o", "v2"); - fail("Expected MissingParameterException"); - } catch (MissingParameterException ex) { - assertEquals("Missing required parameters at positions 0..*: ", ex.getMessage()); - } - } - - @Test - public void test130MixPositionalParamsWithOptions() { - @CommandLine.Command(name = "test-command", description = "tests help from a command script") - class Arg { - - @Parameters(description = "some parameters") - List parameters; - - @Option(names = {"-cp", "--codepath"}, description = "the codepath") - List codepath; - } - Arg result = CommandLine.populateCommand(new Arg(), "--codepath", "/usr/x.jar", "placeholder", "-cp", "/bin/y.jar", "another"); - assertEquals(Arrays.asList("/usr/x.jar", "/bin/y.jar"), result.codepath); - assertEquals(Arrays.asList("placeholder", "another"), result.parameters); - } - - @Test - public void test130MixPositionalParamsWithOptions1() { - class Arg { - @Parameters List parameters; - @Option(names = "-o") List options; - } - Arg result = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3"); - assertEquals(Arrays.asList("v1", "v2"), result.options); - assertEquals(Arrays.asList("p1", "p2", "p3"), result.parameters); - } - - @Test - public void test130MixPositionalParamsWithOptionsArity() { - class Arg { - @Parameters(arity = "2") List parameters; - @Option(names = "-o") List options; - } - Arg result = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3", "p4"); - assertEquals(Arrays.asList("v1", "v2"), result.options); - assertEquals(Arrays.asList("p1", "p2", "p3", "p4"), result.parameters); - - Arg result2 = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "-o", "v2", "p3"); - assertEquals(Arrays.asList("v1"), result2.options); - assertEquals(Arrays.asList("p1", "-o", "v2", "p3"), result2.parameters); - - try { - CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3"); - fail("Expected MissingParameterException"); - } catch (MissingParameterException ex) { - assertEquals("positional parameter at index 0..* () requires at least 2 values, but only 1 were specified: [p3]", ex.getMessage()); - } - } -} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java deleted file mode 100644 index 3651b221af6..00000000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java +++ /dev/null @@ -1,2536 +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.tools.picocli; - -import org.junit.After; -import org.junit.Ignore; -import org.junit.Test; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.IStyle; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Style; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Text; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.ColorScheme; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.TextTable; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Option; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Parameters; -import org.apache.logging.log4j.core.tools.picocli.CommandLine.Command; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.io.UnsupportedEncodingException; -import java.lang.String; -import java.lang.reflect.Field; -import java.net.InetAddress; -import java.net.URI; -import java.net.URL; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import static java.lang.String.format; -import static org.junit.Assert.*; - -/** - * Tests for picoCLI's "Usage" help functionality. - */ -public class CommandLineHelpTest { - private static final String LINESEP = System.getProperty("line.separator"); - - @After - public void after() { - System.getProperties().remove("picocli.color.commands"); - System.getProperties().remove("picocli.color.options"); - System.getProperties().remove("picocli.color.parameters"); - System.getProperties().remove("picocli.color.optionParams"); - } - private static String usageString(Object annotatedObject, Help.Ansi ansi) throws UnsupportedEncodingException { - return usageString(new CommandLine(annotatedObject), ansi); - } - private static String usageString(CommandLine commandLine, Help.Ansi ansi) throws UnsupportedEncodingException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - commandLine.usage(new PrintStream(baos, true, "UTF8"), ansi); - String result = baos.toString("UTF8"); - - if (ansi == Help.Ansi.AUTO) { - baos.reset(); - commandLine.usage(new PrintStream(baos, true, "UTF8")); - assertEquals(result, baos.toString("UTF8")); - } else if (ansi == Help.Ansi.ON) { - baos.reset(); - commandLine.usage(new PrintStream(baos, true, "UTF8"), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(result, baos.toString("UTF8")); - } - return result; - } - private static Field field(Class cls, String fieldName) throws NoSuchFieldException { - return cls.getDeclaredField(fieldName); - } - private static Field[] fields(Class cls, String... fieldNames) throws NoSuchFieldException { - Field[] result = new Field[fieldNames.length]; - for (int i = 0; i < fieldNames.length; i++) { - result[i] = cls.getDeclaredField(fieldNames[i]); - } - return result; - } - - @Test - public void testWithoutShowDefaultValues() throws Exception { - @CommandLine.Command() - class Params { - @Option(names = {"-f", "--file"}, required = true, description = "the file to use") File file; - } - String result = usageString(new Params(), Help.Ansi.OFF); - assertEquals(format("" + - "Usage:
    -f=%n" + - " -f, --file= the file to use%n", - ""), result); - } - - @Test - public void testShowDefaultValues() throws Exception { - @CommandLine.Command(showDefaultValues = true) - class Params { - @Option(names = {"-f", "--file"}, required = true, description = "the file to use") - File file = new File("theDefault.txt"); - } - String result = usageString(new Params(), Help.Ansi.OFF); - assertEquals(format("" + - "Usage:
    -f=%n" + - " -f, --file= the file to use%n" + - " Default: theDefault.txt%n"), result); - } - - @Test - public void testShowDefaultValuesArrayField() throws Exception { - @CommandLine.Command(showDefaultValues = true) - class Params { - @Option(names = {"-x", "--array"}, required = true, description = "the array") - int[] array = {1, 5, 11, 23}; - } - String result = usageString(new Params(), Help.Ansi.OFF); - assertEquals(format("" + - "Usage:
    -x= [-x=]...%n" + - " -x, --array= the array%n" + - " Default: [1, 5, 11, 23]%n"), result); - } - - @Test - public void testUsageSeparatorWithoutDefault() throws Exception { - @Command() - class Params { - @Option(names = {"-f", "--file"}, required = true, description = "the file to use") File file = new File("def.txt"); - } - String result = usageString(new Params(), Help.Ansi.OFF); - assertEquals(format("" + - "Usage:
    -f=%n" + - " -f, --file= the file to use%n", - ""), result); - } - - @Test - public void testUsageSeparator() throws Exception { - @Command(showDefaultValues = true) - class Params { - @Option(names = {"-f", "--file"}, required = true, description = "the file to use") File file = new File("def.txt"); - } - String result = usageString(new Params(), Help.Ansi.OFF); - assertEquals(format("" + - "Usage:
    -f=%n" + - " -f, --file= the file to use%n" + - " Default: def.txt%n", - ""), result); - } - - @Test - public void testUsageParamLabels() throws Exception { - @Command() - class ParamLabels { - @Option(names = "-P", paramLabel = "KEY=VALUE", type = {String.class, String.class}, - description = "Project properties (key-value pairs)") Map props; - @Option(names = "-f", paramLabel = "FILE", description = "files") File[] f; - @Option(names = "-n", description = "a number option") int number; - @Parameters(index = "0", paramLabel = "NUM", description = "number param") int n; - @Parameters(index = "1", description = "the host parameter") InetAddress host; - } - String result = usageString(new ParamLabels(), Help.Ansi.OFF); - assertEquals(format("" + - "Usage:
    [-n=] [-f=FILE]... [-P=KEY=VALUE]... NUM %n" + - " NUM number param%n" + - " the host parameter%n" + - " -f= FILE files%n" + - " -n= a number option%n" + - " -P= KEY=VALUE Project properties (key-value pairs)%n", - ""), result); - } - - @Test - public void testUsageParamLabelsWithLongMapOptionName() throws Exception { - @Command() - class ParamLabels { - @Option(names = {"-P", "--properties"}, - paramLabel = "KEY=VALUE", type = {String.class, String.class}, - description = "Project properties (key-value pairs)") Map props; - @Option(names = "-f", paramLabel = "FILE", description = "a file") File f; - @Option(names = "-n", description = "a number option") int number; - @Parameters(index = "0", paramLabel = "NUM", description = "number param") int n; - @Parameters(index = "1", description = "the host parameter") InetAddress host; - } - String result = usageString(new ParamLabels(), Help.Ansi.OFF); - assertEquals(format("" + - "Usage:
    [-f=FILE] [-n=] [-P=KEY=VALUE]... NUM %n" + - " NUM number param%n" + - " the host parameter%n" + - " -f= FILE a file%n" + - " -n= a number option%n" + - " -P, --properties=KEY=VALUE Project properties (key-value pairs)%n", - ""), result); - } - - // --------------- - @Test - public void testUsageVariableArityRequiredShortOptionArray() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "-a", required = true, paramLabel = "ARG") // default - String[] a; - @Option(names = "-b", required = true, paramLabel = "ARG", arity = "0..*") - List b; - @Option(names = "-c", required = true, paramLabel = "ARG", arity = "1..*") - String[] c; - @Option(names = "-d", required = true, paramLabel = "ARG", arity = "2..*") - List d; - } - String expected = String.format("" + - "Usage:
    -a=ARG [-a=ARG]... -b=[ARG]... [-b=[ARG]...]... -c=ARG...%n" + - " [-c=ARG...]... -d=ARG ARG... [-d=ARG ARG...]...%n" + - " -a= ARG%n" + - " -b= [ARG]...%n" + - " -c= ARG...%n" + - " -d= ARG ARG...%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageVariableArityShortOptionArray() throws UnsupportedEncodingException { - class Args { - @Option(names = "-a", paramLabel = "ARG") // default - List a; - @Option(names = "-b", paramLabel = "ARG", arity = "0..*") - String[] b; - @Option(names = "-c", paramLabel = "ARG", arity = "1..*") - List c; - @Option(names = "-d", paramLabel = "ARG", arity = "2..*") - String[] d; - } - String expected = String.format("" + - "Usage:
    [-a=ARG]... [-b=[ARG]...]... [-c=ARG...]... [-d=ARG%n" + - " ARG...]...%n" + - " -a= ARG%n" + - " -b= [ARG]...%n" + - " -c= ARG...%n" + - " -d= ARG ARG...%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityRequiredShortOptionArray() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "-a", required = true, paramLabel = "ARG", arity = "0..1") - List a; - @Option(names = "-b", required = true, paramLabel = "ARG", arity = "1..2") - String[] b; - @Option(names = "-c", required = true, paramLabel = "ARG", arity = "1..3") - String[] c; - @Option(names = "-d", required = true, paramLabel = "ARG", arity = "2..4") - String[] d; - } - String expected = String.format("" + - "Usage:
    -a[=ARG] [-a[=ARG]]... -b=ARG [ARG] [-b=ARG [ARG]]...%n" + - " -c=ARG [ARG [ARG]] [-c=ARG [ARG [ARG]]]... -d=ARG ARG [ARG%n" + - " [ARG]] [-d=ARG ARG [ARG [ARG]]]...%n" + - " -a= [ARG]%n" + - " -b= ARG [ARG]%n" + - " -c= ARG [ARG [ARG]]%n" + - " -d= ARG ARG [ARG [ARG]]%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityShortOptionArray() throws UnsupportedEncodingException { - class Args { - @Option(names = "-a", paramLabel = "ARG", arity = "0..1") - List a; - @Option(names = "-b", paramLabel = "ARG", arity = "1..2") - String[] b; - @Option(names = "-c", paramLabel = "ARG", arity = "1..3") - String[] c; - @Option(names = "-d", paramLabel = "ARG", arity = "2..4") - String[] d; - } - String expected = String.format("" + - "Usage:
    [-a[=ARG]]... [-b=ARG [ARG]]... [-c=ARG [ARG [ARG]]]...%n" + - " [-d=ARG ARG [ARG [ARG]]]...%n" + - " -a= [ARG]%n" + - " -b= ARG [ARG]%n" + - " -c= ARG [ARG [ARG]]%n" + - " -d= ARG ARG [ARG [ARG]]%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityRequiredShortOptionArray() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "-a", required = true, paramLabel = "ARG") // default - String[] a; - @Option(names = "-b", required = true, paramLabel = "ARG", arity = "0") - String[] b; - @Option(names = "-c", required = true, paramLabel = "ARG", arity = "1") - String[] c; - @Option(names = "-d", required = true, paramLabel = "ARG", arity = "2") - String[] d; - } - String expected = String.format("" + - "Usage:
    -b [-b]... -a=ARG [-a=ARG]... -c=ARG [-c=ARG]... -d=ARG ARG%n" + - " [-d=ARG ARG]...%n" + - " -a= ARG%n" + - " -b%n" + - " -c= ARG%n" + - " -d= ARG ARG%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityShortOptionArray() throws UnsupportedEncodingException { - class Args { - @Option(names = "-a", paramLabel = "ARG") // default - String[] a; - @Option(names = "-b", paramLabel = "ARG", arity = "0") - String[] b; - @Option(names = "-c", paramLabel = "ARG", arity = "1") - String[] c; - @Option(names = "-d", paramLabel = "ARG", arity = "2") - String[] d; - } - String expected = String.format("" + - "Usage:
    [-b]... [-a=ARG]... [-c=ARG]... [-d=ARG ARG]...%n" + - " -a= ARG%n" + - " -b%n" + - " -c= ARG%n" + - " -d= ARG ARG%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - //-------------- - @Test - public void testUsageVariableArityRequiredLongOptionArray() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "--aa", required = true, paramLabel = "ARG") // default - String[] a; - @Option(names = "--bb", required = true, paramLabel = "ARG", arity = "0..*") - List b; - @Option(names = "--cc", required = true, paramLabel = "ARG", arity = "1..*") - String[] c; - @Option(names = "--dd", required = true, paramLabel = "ARG", arity = "2..*") - List d; - } - String expected = String.format("" + - "Usage:
    --aa=ARG [--aa=ARG]... --bb=[ARG]... [--bb=[ARG]...]...%n" + - " --cc=ARG... [--cc=ARG...]... --dd=ARG ARG... [--dd=ARG%n" + - " ARG...]...%n" + - " --aa=ARG%n" + - " --bb=[ARG]...%n" + - " --cc=ARG...%n" + - " --dd=ARG ARG...%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageVariableArityLongOptionArray() throws UnsupportedEncodingException { - class Args { - @Option(names = "--aa", paramLabel = "ARG") // default - List a; - @Option(names = "--bb", paramLabel = "ARG", arity = "0..*") - String[] b; - @Option(names = "--cc", paramLabel = "ARG", arity = "1..*") - List c; - @Option(names = "--dd", paramLabel = "ARG", arity = "2..*") - String[] d; - } - String expected = String.format("" + - "Usage:
    [--aa=ARG]... [--bb=[ARG]...]... [--cc=ARG...]... [--dd=ARG%n" + - " ARG...]...%n" + - " --aa=ARG%n" + - " --bb=[ARG]...%n" + - " --cc=ARG...%n" + - " --dd=ARG ARG...%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityRequiredLongOptionArray() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "--aa", required = true, paramLabel = "ARG", arity = "0..1") - List a; - @Option(names = "--bb", required = true, paramLabel = "ARG", arity = "1..2") - String[] b; - @Option(names = "--cc", required = true, paramLabel = "ARG", arity = "1..3") - String[] c; - @Option(names = "--dd", required = true, paramLabel = "ARG", arity = "2..4", description = "foobar") - String[] d; - } - String expected = String.format("" + - "Usage:
    --aa[=ARG] [--aa[=ARG]]... --bb=ARG [ARG] [--bb=ARG%n" + - " [ARG]]... --cc=ARG [ARG [ARG]] [--cc=ARG [ARG [ARG]]]...%n" + - " --dd=ARG ARG [ARG [ARG]] [--dd=ARG ARG [ARG [ARG]]]...%n" + - " --aa[=ARG]%n" + - " --bb=ARG [ARG]%n" + - " --cc=ARG [ARG [ARG]]%n" + - " --dd=ARG ARG [ARG [ARG]]%n" + - " foobar%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityLongOptionArray() throws UnsupportedEncodingException { - class Args { - @Option(names = "--aa", paramLabel = "ARG", arity = "0..1") - List a; - @Option(names = "--bb", paramLabel = "ARG", arity = "1..2") - String[] b; - @Option(names = "--cc", paramLabel = "ARG", arity = "1..3") - String[] c; - @Option(names = "--dd", paramLabel = "ARG", arity = "2..4", description = "foobar") - String[] d; - } - String expected = String.format("" + - "Usage:
    [--aa[=ARG]]... [--bb=ARG [ARG]]... [--cc=ARG [ARG%n" + - " [ARG]]]... [--dd=ARG ARG [ARG [ARG]]]...%n" + - " --aa[=ARG]%n" + - " --bb=ARG [ARG]%n" + - " --cc=ARG [ARG [ARG]]%n" + - " --dd=ARG ARG [ARG [ARG]]%n" + - " foobar%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityRequiredLongOptionArray() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "--aa", required = true, paramLabel = "ARG") // default - String[] a; - @Option(names = "--bb", required = true, paramLabel = "ARG", arity = "0") - String[] b; - @Option(names = "--cc", required = true, paramLabel = "ARG", arity = "1") - String[] c; - @Option(names = "--dd", required = true, paramLabel = "ARG", arity = "2") - String[] d; - } - String expected = String.format("" + - "Usage:
    --bb [--bb]... --aa=ARG [--aa=ARG]... --cc=ARG%n" + - " [--cc=ARG]... --dd=ARG ARG [--dd=ARG ARG]...%n" + - " --aa=ARG%n" + - " --bb%n" + - " --cc=ARG%n" + - " --dd=ARG ARG%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityLongOptionArray() throws UnsupportedEncodingException { - class Args { - @Option(names = "--aa", paramLabel = "ARG") // default - String[] a; - @Option(names = "--bb", paramLabel = "ARG", arity = "0") - String[] b; - @Option(names = "--cc", paramLabel = "ARG", arity = "1") - String[] c; - @Option(names = "--dd", paramLabel = "ARG", arity = "2") - String[] d; - } - String expected = String.format("" + - "Usage:
    [--bb]... [--aa=ARG]... [--cc=ARG]... [--dd=ARG ARG]...%n" + - " --aa=ARG%n" + - " --bb%n" + - " --cc=ARG%n" + - " --dd=ARG ARG%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - //------------------ - @Test - public void testUsageVariableArityRequiredShortOptionMap() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "-a", required = true, paramLabel = "KEY=VAL") // default - Map a; - @Option(names = "-b", required = true, arity = "0..*") - @SuppressWarnings("unchecked") - Map b; - @Option(names = "-c", required = true, arity = "1..*", type = {String.class, TimeUnit.class}) - Map c; - @Option(names = "-d", required = true, arity = "2..*", type = {Integer.class, URL.class}, description = "description") - Map d; - } - String expected = String.format("" + - "Usage:
    -a=KEY=VAL [-a=KEY=VAL]... -b=[]... [-b=%n" + - " []...]... -c=...%n" + - " [-c=...]... -d=%n" + - " ... [-d= ...]...%n" + - " -a= KEY=VAL%n" + - " -b= []...%n" + - " -c= ...%n" + - " -d= ...%n" + - " description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageVariableArityOptionMap() throws UnsupportedEncodingException { - class Args { - @Option(names = "-a") // default - Map a; - @Option(names = "-b", arity = "0..*", type = {Integer.class, Integer.class}) - Map b; - @Option(names = "-c", paramLabel = "KEY=VALUE", arity = "1..*", type = {String.class, TimeUnit.class}) - Map c; - @Option(names = "-d", arity = "2..*", type = {String.class, URL.class}, description = "description") - Map d; - } - String expected = String.format("" + - "Usage:
    [-a=]... [-b=[]...]...%n" + - " [-c=KEY=VALUE...]... [-d= ...]...%n" + - " -a= %n" + - " -b= []...%n" + - " -c= KEY=VALUE...%n" + - " -d= ...%n" + - " description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityRequiredOptionMap() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "-a", required = true, arity = "0..1", description = "a description") - Map a; - @Option(names = "-b", required = true, arity = "1..2", type = {Integer.class, Integer.class}, description = "b description") - Map b; - @Option(names = "-c", required = true, arity = "1..3", type = {String.class, URL.class}, description = "c description") - Map c; - @Option(names = "-d", required = true, paramLabel = "K=URL", arity = "2..4", description = "d description") - Map d; - } - String expected = String.format("" + - "Usage:
    -a[=] [-a[=]]...%n" + - " -b= []%n" + - " [-b= []]...%n" + - " -c= [ []]%n" + - " [-c= [ []]]... -d=K=URL%n" + - " K=URL [K=URL [K=URL]] [-d=K=URL K=URL [K=URL [K=URL]]]...%n" + - " -a= [] a description%n" + - " -b= []%n" + - " b description%n" + - " -c= [ []]%n" + - " c description%n" + - " -d= K=URL K=URL [K=URL [K=URL]]%n" + - " d description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityOptionMap() throws UnsupportedEncodingException { - class Args { - @Option(names = "-a", arity = "0..1"/*, type = {UUID.class, URL.class}*/, description = "a description") - Map a; - @Option(names = "-b", arity = "1..2", type = {Long.class, UUID.class}, description = "b description") - Map b; - @Option(names = "-c", arity = "1..3", type = {Long.class}, description = "c description") - Map c; - @Option(names = "-d", paramLabel = "K=V", arity = "2..4", description = "d description") - Map d; - } - String expected = String.format("" + - "Usage:
    [-a[=]]... [-b= []]...%n" + - " [-c= [ []]]...%n" + - " [-d=K=V K=V [K=V [K=V]]]...%n" + - " -a= [] a description%n" + - " -b= []%n" + - " b description%n" + - " -c= [ []]%n" + - " c description%n" + - " -d= K=V K=V [K=V [K=V]] d description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityRequiredOptionMap() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Option(names = "-a", required = true, description = "a description") - Map a; - @Option(names = "-b", required = true, paramLabel = "KEY=VAL", arity = "0", description = "b description") - @SuppressWarnings("unchecked") - Map b; - @Option(names = "-c", required = true, arity = "1", type = {Long.class, File.class}, description = "c description") - Map c; - @Option(names = "-d", required = true, arity = "2", type = {URI.class, URL.class}, description = "d description") - Map d; - } - String expected = String.format("" + - "Usage:
    -b [-b]... -a= [-a=]...%n" + - " -c= [-c=]... -d= %n" + - " [-d= ]...%n" + - " -a= a description%n" + - " -b b description%n" + - " -c= c description%n" + - " -d= d description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityOptionMap() throws UnsupportedEncodingException { - class Args { - @Option(names = "-a", type = {Short.class, Field.class}, description = "a description") - Map a; - @Option(names = "-b", arity = "0", type = {UUID.class, Long.class}, description = "b description") - @SuppressWarnings("unchecked") - Map b; - @Option(names = "-c", arity = "1", description = "c description") - Map c; - @Option(names = "-d", arity = "2", type = {URI.class, URL.class}, description = "d description") - Map d; - } - String expected = String.format("" + - "Usage:
    [-b]... [-a=]... [-c=]...%n" + - " [-d= ]...%n" + - " -a= a description%n" + - " -b b description%n" + - " -c= c description%n" + - " -d= d description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - //-------------- - @Test - public void testUsageVariableArityParametersArray() throws UnsupportedEncodingException { - // if option is required at least once and can be specified multiple times: - // -f=ARG [-f=ARG]... - class Args { - @Parameters(paramLabel = "APARAM", description = "APARAM description") - String[] a; - @Parameters(arity = "0..*", description = "b description") - List b; - @Parameters(arity = "1..*", description = "c description") - String[] c; - @Parameters(arity = "2..*", description = "d description") - List d; - } - String expected = String.format("" + - "Usage:
    [APARAM]... []... ... ...%n" + - " [APARAM]... APARAM description%n" + - " []... b description%n" + - " ... c description%n" + - " ... d description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityParameterArray() throws UnsupportedEncodingException { - class Args { - @Parameters(index = "0", paramLabel = "PARAMA", arity = "0..1", description = "PARAMA description") - List a; - @Parameters(index = "0", paramLabel = "PARAMB", arity = "1..2", description = "PARAMB description") - String[] b; - @Parameters(index = "0", paramLabel = "PARAMC", arity = "1..3", description = "PARAMC description") - String[] c; - @Parameters(index = "0", paramLabel = "PARAMD", arity = "2..4", description = "PARAMD description") - String[] d; - } - String expected = String.format("" + - "Usage:
    [PARAMA] PARAMB [PARAMB] PARAMC [PARAMC [PARAMC]] PARAMD%n" + - " PARAMD [PARAMD [PARAMD]]%n" + - " [PARAMA] PARAMA description%n" + - " PARAMB [PARAMB] PARAMB description%n" + - " PARAMC [PARAMC [PARAMC]]%n" + - " PARAMC description%n" + - " PARAMD PARAMD [PARAMD [PARAMD]]%n" + - " PARAMD description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityParametersArray() throws UnsupportedEncodingException { - class Args { - @Parameters(description = "a description (default arity)") - String[] a; - @Parameters(index = "0", arity = "0", description = "b description (arity=0)") - String[] b; - @Parameters(index = "1", arity = "1", description = "b description (arity=1)") - String[] c; - @Parameters(index = "2", arity = "2", description = "b description (arity=2)") - String[] d; - } - String expected = String.format("" + - "Usage:
    []... %n" + - " b description (arity=0)%n" + - " []... a description (default arity)%n" + - " b description (arity=1)%n" + - " b description (arity=2)%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageVariableArityParametersMap() throws UnsupportedEncodingException { - class Args { - @Parameters() - Map a; - @Parameters(arity = "0..*", description = "a description (arity=0..*)") - Map b; - @Parameters(paramLabel = "KEY=VALUE", arity = "1..*", type = {String.class, TimeUnit.class}) - Map c; - @Parameters(arity = "2..*", type = {String.class, URL.class}, description = "description") - Map d; - } - String expected = String.format("" + - "Usage:
    []... []... KEY=VALUE...%n" + - " ...%n" + - " []...%n" + - " []... a description (arity=0..*)%n" + - " KEY=VALUE...%n" + - " ...%n" + - " description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageRangeArityParametersMap() throws UnsupportedEncodingException { - class Args { - @Parameters(index = "0", arity = "0..1"/*, type = {UUID.class, URL.class}*/, description = "a description") - Map a; - @Parameters(index = "1", arity = "1..2", type = {Long.class, UUID.class}, description = "b description") - Map b; - @Parameters(index = "2", arity = "1..3", type = {Long.class}, description = "c description") - Map c; - @Parameters(index = "3", paramLabel = "K=V", arity = "2..4", description = "d description") - Map d; - } - String expected = String.format("" + - "Usage:
    [] [] %n" + - " [ []] K=V K=V [K=V [K=V]]%n" + - " [] a description%n" + - " []%n" + - " b description%n" + - " [ []]%n" + - " c description%n" + - " K=V K=V [K=V [K=V]] d description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - - @Test - public void testUsageFixedArityParametersMap() throws UnsupportedEncodingException { - class Args { - @Parameters(type = {Short.class, Field.class}, description = "a description") - Map a; - @Parameters(index = "0", arity = "0", type = {UUID.class, Long.class}, description = "b description (arity=0)") - @SuppressWarnings("unchecked") - Map b; - @Parameters(index = "1", arity = "1", description = "c description") - Map c; - @Parameters(index = "2", arity = "2", type = {URI.class, URL.class}, description = "d description") - Map d; - } - String expected = String.format("" + - "Usage:
    []... %n" + - " b description (arity=0)%n" + - " []... a description%n" + - " c description%n" + - " d description%n"); - //CommandLine.usage(new Args(), System.out); - assertEquals(expected, usageString(new Args(), Help.Ansi.OFF)); - } - //---------- - @Test - public void testShortestFirstComparator_sortsShortestFirst() { - String[] values = {"12345", "12", "123", "123456", "1", "", "1234"}; - Arrays.sort(values, new Help.ShortestFirst()); - String[] expected = {"", "1", "12", "123", "1234", "12345", "123456"}; - assertArrayEquals(expected, values); - } - - @Test - public void testShortestFirstComparator_sortsDeclarationOrderIfEqualLength() { - String[] values = {"-d", "-", "-a", "--alpha", "--b", "--a", "--beta"}; - Arrays.sort(values, new Help.ShortestFirst()); - String[] expected = {"-", "-d", "-a", "--b", "--a", "--beta", "--alpha"}; - assertArrayEquals(expected, values); - } - - @Test - public void testSortByShortestOptionNameComparator() throws Exception { - class App { - @Option(names = {"-t", "--aaaa"}) boolean aaaa; - @Option(names = {"--bbbb", "-k"}) boolean bbbb; - @Option(names = {"-c", "--cccc"}) boolean cccc; - } - Field[] fields = fields(App.class, "aaaa", "bbbb", "cccc"); // -tkc - Arrays.sort(fields, new Help.SortByShortestOptionNameAlphabetically()); - Field[] expected = fields(App.class, "cccc", "bbbb", "aaaa"); // -ckt - assertArrayEquals(expected, fields); - } - - @Test - public void testSortByOptionArityAndNameComparator_sortsByMaxThenMinThenName() throws Exception { - class App { - @Option(names = {"-t", "--aaaa"} ) boolean tImplicitArity0; - @Option(names = {"-e", "--EEE"}, arity = "1" ) boolean explicitArity1; - @Option(names = {"--bbbb", "-k"} ) boolean kImplicitArity0; - @Option(names = {"--AAAA", "-a"} ) int aImplicitArity1; - @Option(names = {"--BBBB", "-z"} ) String[] zImplicitArity1; - @Option(names = {"--ZZZZ", "-b"}, arity = "1..3") String[] bExplicitArity1_3; - @Option(names = {"-f", "--ffff"} ) boolean fImplicitArity0; - } - Field[] fields = fields(App.class, "tImplicitArity0", "explicitArity1", "kImplicitArity0", - "aImplicitArity1", "zImplicitArity1", "bExplicitArity1_3", "fImplicitArity0"); - Arrays.sort(fields, new Help.SortByOptionArityAndNameAlphabetically()); - Field[] expected = fields(App.class, - "fImplicitArity0", - "kImplicitArity0", - "tImplicitArity0", - "aImplicitArity1", - "explicitArity1", - "zImplicitArity1", - "bExplicitArity1_3"); - assertArrayEquals(expected, fields); - } - - @Test - public void testCreateMinimalOptionRenderer_ReturnsMinimalOptionRenderer() { - assertEquals(Help.MinimalOptionRenderer.class, Help.createMinimalOptionRenderer().getClass()); - } - - @Test - public void testMinimalOptionRenderer_rendersFirstDeclaredOptionNameAndDescription() { - class Example { - @Option(names = {"---long", "-L"}, description = "long description") String longField; - @Option(names = {"-b", "-a", "--alpha"}, description = "other") String otherField; - } - Help.IOptionRenderer renderer = Help.createMinimalOptionRenderer(); - Help help = new Help(new Example(), Help.defaultColorScheme(Help.Ansi.ON)); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - Field field = help.optionFields.get(0); - Text[][] row1 = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, Help.defaultColorScheme( - help.ansi())); - assertEquals(1, row1.length); - //assertArrayEquals(new String[]{"---long=", "long description"}, row1[0]); - assertArrayEquals(new Text[]{ - help.ansi().new Text(format("%s---long%s=%s%s", "@|fg(yellow) ", "|@", "@|italic ", "|@")), - help.ansi().new Text("long description")}, row1[0]); - - field = help.optionFields.get(1); - Text[][] row2 = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, Help.defaultColorScheme( - help.ansi())); - assertEquals(1, row2.length); - //assertArrayEquals(new String[]{"-b=", "other"}, row2[0]); - assertArrayEquals(new Text[]{ - help.ansi().new Text(format("%s-b%s=%s%s", "@|fg(yellow) ", "|@", "@|italic ", "|@")), - help.ansi().new Text("other")}, row2[0]); - } - - @Test - public void testCreateDefaultOptionRenderer_ReturnsDefaultOptionRenderer() { - assertEquals(Help.DefaultOptionRenderer.class, new Help(new UsageDemo()).createDefaultOptionRenderer().getClass()); - } - - private static Text[] textArray(Help help, String... str) { - return textArray(help.ansi(), str); - } - private static Text[] textArray(Help.Ansi ansi, String... str) { - Text[] result = new Text[str.length]; - for (int i = 0; i < str.length; i++) { - result[i] = str[i] == null ? Help.Ansi.EMPTY_TEXT : ansi.new Text(str[i]); - } - return result; - } - - @Test - public void testDefaultOptionRenderer_rendersShortestOptionNameThenOtherOptionNamesAndDescription() { - @Command(showDefaultValues = true) - class Example { - @Option(names = {"---long", "-L"}, description = "long description") String longField; - @Option(names = {"-b", "-a", "--alpha"}, description = "other") String otherField = "abc"; - } - Help help = new Help(new Example()); - Help.IOptionRenderer renderer = help.createDefaultOptionRenderer(); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - Field field = help.optionFields.get(0); - Text[][] row1 = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row1.length); - assertArrayEquals(Arrays.toString(row1[0]), textArray(help, "", "-L", ",", "---long=", "long description"), row1[0]); - //assertArrayEquals(Arrays.toString(row1[1]), textArray(help, "", "", "", "", " Default: null"), row1[1]); // #201 don't show null defaults - - field = help.optionFields.get(1); - Text[][] row2 = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(2, row2.length); - assertArrayEquals(Arrays.toString(row2[0]), textArray(help, "", "-b", ",", "-a, --alpha=", "other"), row2[0]); - assertArrayEquals(Arrays.toString(row2[1]), textArray(help, "", "", "", "", " Default: abc"), row2[1]); - } - - @Test - public void testDefaultOptionRenderer_rendersSpecifiedMarkerForRequiredOptionsWithDefault() { - @Command(requiredOptionMarker = '*', showDefaultValues = true) - class Example { - @Option(names = {"-b", "-a", "--alpha"}, required = true, description = "other") String otherField ="abc"; - } - Help help = new Help(new Example()); - Help.IOptionRenderer renderer = help.createDefaultOptionRenderer(); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - Field field = help.optionFields.get(0); - Text[][] row = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(2, row.length); - assertArrayEquals(Arrays.toString(row[0]), textArray(help, "*", "-b", ",", "-a, --alpha=", "other"), row[0]); - assertArrayEquals(Arrays.toString(row[1]), textArray(help, "", "", "", "", " Default: abc"), row[1]); - } - - @Test - public void testDefaultOptionRenderer_rendersSpecifiedMarkerForRequiredOptionsWithoutDefault() { - @Command(requiredOptionMarker = '*') - class Example { - @Option(names = {"-b", "-a", "--alpha"}, required = true, description = "other") String otherField ="abc"; - } - Help help = new Help(new Example()); - Help.IOptionRenderer renderer = help.createDefaultOptionRenderer(); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - Field field = help.optionFields.get(0); - Text[][] row = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row.length); - assertArrayEquals(Arrays.toString(row[0]), textArray(help, "*", "-b", ",", "-a, --alpha=", "other"), row[0]); - } - - @Test - public void testDefaultOptionRenderer_rendersSpacePrefixByDefaultForRequiredOptionsWithoutDefaultValue() { - class Example { - @Option(names = {"-b", "-a", "--alpha"}, required = true, description = "other") String otherField; - } - Help help = new Help(new Example()); - Help.IOptionRenderer renderer = help.createDefaultOptionRenderer(); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - Field field = help.optionFields.get(0); - Text[][] row = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row.length); - assertArrayEquals(Arrays.toString(row[0]), textArray(help, " ", "-b", ",", "-a, --alpha=", "other"), row[0]); - } - - @Test - public void testDefaultOptionRenderer_rendersSpacePrefixByDefaultForRequiredOptionsWithDefaultValue() { - //@Command(showDefaultValues = true) // set programmatically - class Example { - @Option(names = {"-b", "-a", "--alpha"}, required = true, description = "other") String otherField; - } - Help help = new Help(new Example()); - help.showDefaultValues = true; - Help.IOptionRenderer renderer = help.createDefaultOptionRenderer(); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - Field field = help.optionFields.get(0); - Text[][] row = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row.length); - assertArrayEquals(Arrays.toString(row[0]), textArray(help, " ", "-b", ",", "-a, --alpha=", "other"), row[0]); - // assertArrayEquals(Arrays.toString(row[1]), textArray(help, "", "", "", "", " Default: null"), row[1]); // #201 don't show null defaults - } - - @Test - public void testDefaultParameterRenderer_rendersSpacePrefixByDefaultForParametersWithPositiveArity() { - class Required { - @Parameters(description = "required") String required; - } - Help help = new Help(new Required()); - Help.IParameterRenderer renderer = help.createDefaultParameterRenderer(); - Help.IParamLabelRenderer parameterRenderer = Help.createMinimalParamLabelRenderer(); - Field field = help.positionalParametersFields.get(0); - Text[][] row1 = renderer.render(field.getAnnotation(Parameters.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row1.length); - assertArrayEquals(Arrays.toString(row1[0]), textArray(help, " ", "", "", "", "required"), row1[0]); - } - - @Test - public void testDefaultParameterRenderer_rendersSpecifiedMarkerForParametersWithPositiveArity() { - @Command(requiredOptionMarker = '*') - class Required { - @Parameters(description = "required") String required; - } - Help help = new Help(new Required()); - Help.IParameterRenderer renderer = help.createDefaultParameterRenderer(); - Help.IParamLabelRenderer parameterRenderer = Help.createMinimalParamLabelRenderer(); - Field field = help.positionalParametersFields.get(0); - Text[][] row1 = renderer.render(field.getAnnotation(Parameters.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row1.length); - assertArrayEquals(Arrays.toString(row1[0]), textArray(help, "*", "", "", "", "required"), row1[0]); - } - - @Test - public void testDefaultParameterRenderer_rendersSpacePrefixForParametersWithZeroArity() { - @Command(requiredOptionMarker = '*') - class Optional { - @Parameters(arity = "0..1", description = "optional") String optional; - } - Help help = new Help(new Optional()); - Help.IParameterRenderer renderer = help.createDefaultParameterRenderer(); - Help.IParamLabelRenderer parameterRenderer = Help.createMinimalParamLabelRenderer(); - Field field = help.positionalParametersFields.get(0); - Text[][] row1 = renderer.render(field.getAnnotation(Parameters.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row1.length); - assertArrayEquals(Arrays.toString(row1[0]), textArray(help, "", "", "", "", "optional"), row1[0]); - } - - @Test - public void testDefaultOptionRenderer_rendersCommaOnlyIfBothShortAndLongOptionNamesExist() { - class Example { - @Option(names = {"-v"}, description = "shortBool") boolean shortBoolean; - @Option(names = {"--verbose"}, description = "longBool") boolean longBoolean; - @Option(names = {"-x", "--xeno"}, description = "combiBool") boolean combiBoolean; - @Option(names = {"-s"}, description = "shortOnly") String shortOnlyField; - @Option(names = {"--long"}, description = "longOnly") String longOnlyField; - @Option(names = {"-b", "--beta"}, description = "combi") String combiField; - } - Help help = new Help(new Example()); - help.showDefaultValues = false; // omit default values from description column - Help.IOptionRenderer renderer = help.createDefaultOptionRenderer(); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - - String[][] expected = new String[][] { - {"", "-v", "", "", "shortBool"}, - {"", "", "", "--verbose", "longBool"}, - {"", "-x", ",", "--xeno", "combiBool"}, - {"", "-s", "=", "", "shortOnly"}, - {"", "", "", "--long=", "longOnly"}, - {"", "-b", ",", "--beta=", "combi"}, - }; - int i = -1; - for (Field field : help.optionFields) { - Text[][] row = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(1, row.length); - assertArrayEquals(Arrays.toString(row[0]), textArray(help, expected[++i]), row[0]); - } - } - - @Test - public void testDefaultOptionRenderer_omitsDefaultValuesForBooleanFields() { - @Command(showDefaultValues = true) - class Example { - @Option(names = {"-v"}, description = "shortBool") boolean shortBoolean; - @Option(names = {"--verbose"}, description = "longBool") Boolean longBoolean; - @Option(names = {"-s"}, description = "shortOnly") String shortOnlyField = "short"; - @Option(names = {"--long"}, description = "longOnly") String longOnlyField = "long"; - @Option(names = {"-b", "--beta"}, description = "combi") int combiField = 123; - } - Help help = new Help(new Example()); - Help.IOptionRenderer renderer = help.createDefaultOptionRenderer(); - Help.IParamLabelRenderer parameterRenderer = help.createDefaultParamLabelRenderer(); - - String[][] expected = new String[][] { - {"", "-v", "", "", "shortBool"}, - {"", "", "", "--verbose", "longBool"}, - {"", "-s", "=", "", "shortOnly"}, - {"", "", "", "", "Default: short"}, - {"", "", "", "--long=", "longOnly"}, - {"", "", "", "", "Default: long"}, - {"", "-b", ",", "--beta=", "combi"}, - {"", "", "", "", "Default: 123"}, - }; - int[] rowCount = {1, 1, 2, 2, 2}; - int i = -1; - int rowIndex = 0; - for (Field field : help.optionFields) { - Text[][] row = renderer.render(field.getAnnotation(Option.class), field, parameterRenderer, help.colorScheme); - assertEquals(rowCount[++i], row.length); - assertArrayEquals(Arrays.toString(row[0]), textArray(help, expected[rowIndex]), row[0]); - rowIndex += rowCount[i]; - } - } - - @Test - public void testCreateDefaultParameterRenderer_ReturnsDefaultParameterRenderer() { - assertEquals(Help.DefaultParamLabelRenderer.class, new Help(new UsageDemo()).createDefaultParamLabelRenderer().getClass()); - } - - @Test - public void testDefaultParameterRenderer_showsParamLabelIfPresentOrFieldNameOtherwise() { - class Example { - @Option(names = "--without" ) String longField; - @Option(names = "--with", paramLabel = "LABEL") String otherField; - } - Help help = new Help(new Example()); - Help.IParamLabelRenderer equalSeparatedParameterRenderer = help.createDefaultParamLabelRenderer(); - help.separator = " "; - Help.IParamLabelRenderer spaceSeparatedParameterRenderer = help.createDefaultParamLabelRenderer(); - - String[] expected = new String[] { - "", - "LABEL", - }; - int i = -1; - for (Field field : help.optionFields) { - i++; - Text withSpace = spaceSeparatedParameterRenderer.renderParameterLabel(field, help.ansi(), Collections.emptyList()); - assertEquals(withSpace.toString(), " " + expected[i], withSpace.toString()); - Text withEquals = equalSeparatedParameterRenderer.renderParameterLabel(field, help.ansi(), Collections.emptyList()); - assertEquals(withEquals.toString(), "=" + expected[i], withEquals.toString()); - } - } - - @Test - public void testDefaultParameterRenderer_appliesToPositionalArgumentsIgnoresSeparator() { - class WithLabel { @Parameters(paramLabel = "POSITIONAL_ARGS") String positional; } - class WithoutLabel { @Parameters() String positional; } - - Help withLabel = new Help(new WithLabel()); - Help.IParamLabelRenderer equals = withLabel.createDefaultParamLabelRenderer(); - withLabel.separator = "="; - Help.IParamLabelRenderer spaced = withLabel.createDefaultParamLabelRenderer(); - - Text withSpace = spaced.renderParameterLabel(withLabel.positionalParametersFields.get(0), withLabel.ansi(), Collections.emptyList()); - assertEquals(withSpace.toString(), "POSITIONAL_ARGS", withSpace.toString()); - Text withEquals = equals.renderParameterLabel(withLabel.positionalParametersFields.get(0), withLabel.ansi(), Collections.emptyList()); - assertEquals(withEquals.toString(), "POSITIONAL_ARGS", withEquals.toString()); - - Help withoutLabel = new Help(new WithoutLabel()); - withSpace = spaced.renderParameterLabel(withoutLabel.positionalParametersFields.get(0), withoutLabel.ansi(), Collections.emptyList()); - assertEquals(withSpace.toString(), "", withSpace.toString()); - withEquals = equals.renderParameterLabel(withoutLabel.positionalParametersFields.get(0), withoutLabel.ansi(), Collections.emptyList()); - assertEquals(withEquals.toString(), "", withEquals.toString()); - } - - @Test - public void testDefaultLayout_addsEachRowToTable() { - final Text[][] values = { - textArray(Help.Ansi.OFF, "a", "b", "c", "d"), - textArray(Help.Ansi.OFF, "1", "2", "3", "4") - }; - final int[] count = {0}; - TextTable tt = new TextTable(Help.Ansi.OFF) { - @Override public void addRowValues(Text[] columnValues) { - assertArrayEquals(values[count[0]], columnValues); - count[0]++; - } - }; - Help.Layout layout = new Help.Layout(Help.defaultColorScheme(Help.Ansi.OFF), tt); - layout.layout(null, values); - assertEquals(2, count[0]); - } - - @Test - public void testAbreviatedSynopsis_withoutParameters() { - @CommandLine.Command(abbreviateSynopsis = true) - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [OPTIONS]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testAbreviatedSynopsis_withoutParameters_ANSI() { - @CommandLine.Command(abbreviateSynopsis = true) - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [OPTIONS]" + LINESEP).toString(), help.synopsis(0)); - } - - @Test - public void testAbreviatedSynopsis_withParameters() { - @CommandLine.Command(abbreviateSynopsis = true) - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [OPTIONS] []..." + LINESEP, help.synopsis(0)); - } - - @Test - public void testAbreviatedSynopsis_withParameters_ANSI() { - @CommandLine.Command(abbreviateSynopsis = true) - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [OPTIONS] [@|yellow |@]..." + LINESEP).toString(), help.synopsis(0)); - } - - @Test - public void testAbreviatedSynopsis_commandNameCustomizableDeclaratively() throws UnsupportedEncodingException { - @CommandLine.Command(abbreviateSynopsis = true, name = "aprogram") - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - String expected = "" + - "Usage: aprogram [OPTIONS] []...%n" + - " []...%n" + - " -c, --count=%n" + - " -v, --verbose%n"; - String actual = usageString(new CommandLine(new App()), Help.Ansi.OFF); - assertEquals(String.format(expected), actual); - } - - @Test - public void testAbreviatedSynopsis_commandNameCustomizableProgrammatically() throws UnsupportedEncodingException { - @CommandLine.Command(abbreviateSynopsis = true) - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - String expected = "" + - "Usage: anotherProgram [OPTIONS] []...%n" + - " []...%n" + - " -c, --count=%n" + - " -v, --verbose%n"; - String actual = usageString(new CommandLine(new App()).setCommandName("anotherProgram"), Help.Ansi.OFF); - assertEquals(String.format(expected), actual); - } - - @Test - public void testSynopsis_commandNameCustomizableDeclaratively() throws UnsupportedEncodingException { - @CommandLine.Command(name = "aprogram") - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - String expected = "" + - "Usage: aprogram [-v] [-c=] []...%n" + - " []...%n" + - " -c, --count=%n" + - " -v, --verbose%n"; - String actual = usageString(new CommandLine(new App()), Help.Ansi.OFF); - assertEquals(String.format(expected), actual); - } - - @Test - public void testSynopsis_commandNameCustomizableProgrammatically() throws UnsupportedEncodingException { - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - String expected = "" + - "Usage: anotherProgram [-v] [-c=] []...%n" + - " []...%n" + - " -c, --count=%n" + - " -v, --verbose%n"; - String actual = usageString(new CommandLine(new App()).setCommandName("anotherProgram"), Help.Ansi.OFF); - assertEquals(String.format(expected), actual); - } - - @Test - public void testSynopsis_optionalOptionArity1_n_withDefaultSeparator() { - @Command() class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, arity = "1..*") int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c=...]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_optionalOptionArity1_n_withDefaultSeparator_ANSI() { - @Command() class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, arity = "1..*") int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [@|yellow -v|@] [@|yellow -c|@=@|italic |@...]" + LINESEP), - help.synopsis(0)); - } - - @Test - public void testSynopsis_optionalOptionArity0_1_withSpaceSeparator() { - @CommandLine.Command(separator = " ") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, arity = "0..1") int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c []]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_optionalOptionArity0_1_withSpaceSeparator_ANSI() { - @CommandLine.Command(separator = " ") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, arity = "0..1") int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [@|yellow -v|@] [@|yellow -c|@ [@|italic |@]]" + LINESEP), help.synopsis(0)); - } - - @Test - public void testSynopsis_requiredOptionWithSeparator() { - @Command() class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, required = true) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] -c=" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_requiredOptionWithSeparator_ANSI() { - @Command() class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, required = true) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [@|yellow -v|@] @|yellow -c|@=@|italic |@" + LINESEP), help.synopsis(0)); - } - - @Test - public void testSynopsis_optionalOption_withSpaceSeparator() { - @CommandLine.Command(separator = " ") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c ]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_optionalOptionArity0_1__withSeparator() { - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, arity = "0..1") int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c[=]]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_optionalOptionArity0_n__withSeparator() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, arity = "0..*") int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - // NOTE Expected :
    [-v] [-c[=]...] but arity=0 for int field is weird anyway... - assertEquals("
    [-v] [-c=[]...]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_optionalOptionArity1_n__withSeparator() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}, arity = "1..*") int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c=...]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_withProgrammaticallySetSeparator_withParameters() throws UnsupportedEncodingException { - class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - CommandLine commandLine = new CommandLine(new App()).setSeparator(":"); - String actual = usageString(commandLine, Help.Ansi.OFF); - String expected = "" + - "Usage:
    [-v] [-c:] []...%n" + - " []...%n" + - " -c, --count:%n" + - " -v, --verbose%n"; - assertEquals(String.format(expected), actual); - } - - @Test - public void testSynopsis_withSeparator_withParameters() { - @CommandLine.Command(separator = ":") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c:] []..." + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_withSeparator_withParameters_ANSI() { - @CommandLine.Command(separator = ":") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters File[] files; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [@|yellow -v|@] [@|yellow -c|@:@|italic |@] [@|yellow |@]..." + LINESEP), - help.synopsis(0)); - } - - @Test - public void testSynopsis_withSeparator_withLabeledParameters() { - @Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters(paramLabel = "FILE") File[] files; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c=] [FILE]..." + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_withSeparator_withLabeledParameters_ANSI() { - @Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters(paramLabel = "FILE") File[] files; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [@|yellow -v|@] [@|yellow -c|@=@|italic |@] [@|yellow FILE|@]..." + LINESEP), - help.synopsis(0)); - } - - @Test - public void testSynopsis_withSeparator_withLabeledRequiredParameters() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters(paramLabel = "FILE", arity = "1..*") File[] files; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-v] [-c=] FILE..." + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_withSeparator_withLabeledRequiredParameters_ANSI() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters(paramLabel = "FILE", arity = "1..*") File[] files; - } - Help help = new Help(new App(), Help.Ansi.ON); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ [@|yellow -v|@] [@|yellow -c|@=@|italic |@] @|yellow FILE|@..." + LINESEP), - help.synopsis(0)); - } - - @Test - public void testSynopsis_clustersBooleanOptions() { - @Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--aaaa", "-a"}) boolean aBoolean; - @Option(names = {"--xxxx", "-x"}) Boolean xBoolean; - @Option(names = {"--count", "-c"}, paramLabel = "COUNT") int count; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    [-avx] [-c=COUNT]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_clustersRequiredBooleanOptions() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}, required = true) boolean verbose; - @Option(names = {"--aaaa", "-a"}, required = true) boolean aBoolean; - @Option(names = {"--xxxx", "-x"}, required = true) Boolean xBoolean; - @Option(names = {"--count", "-c"}, paramLabel = "COUNT") int count; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    -avx [-c=COUNT]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_clustersRequiredBooleanOptionsSeparately() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--aaaa", "-a"}) boolean aBoolean; - @Option(names = {"--xxxx", "-x"}) Boolean xBoolean; - @Option(names = {"--Verbose", "-V"}, required = true) boolean requiredVerbose; - @Option(names = {"--Aaaa", "-A"}, required = true) boolean requiredABoolean; - @Option(names = {"--Xxxx", "-X"}, required = true) Boolean requiredXBoolean; - @Option(names = {"--count", "-c"}, paramLabel = "COUNT") int count; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals("
    -AVX [-avx] [-c=COUNT]" + LINESEP, help.synopsis(0)); - } - - @Test - public void testSynopsis_clustersRequiredBooleanOptionsSeparately_ANSI() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--aaaa", "-a"}) boolean aBoolean; - @Option(names = {"--xxxx", "-x"}) Boolean xBoolean; - @Option(names = {"--Verbose", "-V"}, required = true) boolean requiredVerbose; - @Option(names = {"--Aaaa", "-A"}, required = true) boolean requiredABoolean; - @Option(names = {"--Xxxx", "-X"}, required = true) Boolean requiredXBoolean; - @Option(names = {"--count", "-c"}, paramLabel = "COUNT") int count; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text("@|bold
    |@ @|yellow -AVX|@ [@|yellow -avx|@] [@|yellow -c|@=@|italic COUNT|@]" + LINESEP), - help.synopsis(0)); - } - - @Test - public void testSynopsis_firstLineLengthAdjustedForSynopsisHeading() throws Exception { - //Usage: small-test-program [-acorv!?] [--version] [-h ] [-p |] [-d -// []] [-i -// [...]] - @CommandLine.Command(name="small-test-program", sortOptions = false, separator = " ") - class App { - @Option(names = "-a") boolean a; - @Option(names = "-c") boolean c; - @Option(names = "-o") boolean o; - @Option(names = "-r") boolean r; - @Option(names = "-v") boolean v; - @Option(names = "-!") boolean exclamation; - @Option(names = "-?") boolean question; - @Option(names = {"--version"}) boolean version; - @Option(names = {"--handle", "-h"}) int number; - @Option(names = {"--ppp", "-p"}, paramLabel = "|") File f; - @Option(names = {"--ddd", "-d"}, paramLabel = "", arity="1..2") File[] d; - @Option(names = {"--include", "-i"}, paramLabel = "") String pattern; - } - Help help = new Help(new App(), Help.Ansi.OFF); - String expected = "" + - "Usage: small-test-program [-!?acorv] [--version] [-h ] [-i" + LINESEP + - " ] [-p |] [-d " + LINESEP + - " []]..." + LINESEP; - assertEquals(expected, help.synopsisHeading() + help.synopsis(help.synopsisHeadingLength())); - - help.synopsisHeading = "Usage:%n"; - expected = "" + - "Usage:" + LINESEP + - "small-test-program [-!?acorv] [--version] [-h ] [-i ]" + LINESEP + - " [-p |] [-d []]..." + LINESEP; - assertEquals(expected, help.synopsisHeading() + help.synopsis(help.synopsisHeadingLength())); - } - - @Test - public void testLongMultiLineSynopsisIndented() { - @Command(name = "") - class App { - @Option(names = "--long-option-name", paramLabel = "") int a; - @Option(names = "--another-long-option-name", paramLabel = "") int b; - @Option(names = "--third-long-option-name", paramLabel = "") int c; - @Option(names = "--fourth-long-option-name", paramLabel = "") int d; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals(String.format( - " [--another-long-option-name=]%n" + - " [--fourth-long-option-name=]%n" + - " [--long-option-name=]%n" + - " [--third-long-option-name=]%n"), - help.synopsis(0)); - } - - @Test - public void testLongMultiLineSynopsisWithAtMarkIndented() { - @Command(name = "") - class App { - @Option(names = "--long-option@-name", paramLabel = "") int a; - @Option(names = "--another-long-option-name", paramLabel = "^[]") int b; - @Option(names = "--third-long-option-name", paramLabel = "") int c; - @Option(names = "--fourth-long-option-name", paramLabel = "") int d; - } - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals(String.format( - " [--another-long-option-name=^[]]%n" + - " [--fourth-long-option-name=]%n" + - " [--long-option@-name=]%n" + - " [--third-long-option-name=]%n"), - help.synopsis(0)); - } - - @Test - public void testLongMultiLineSynopsisWithAtMarkIndented_ANSI() { - @Command(name = "") - class App { - @Option(names = "--long-option@-name", paramLabel = "") int a; - @Option(names = "--another-long-option-name", paramLabel = "^[]") int b; - @Option(names = "--third-long-option-name", paramLabel = "") int c; - @Option(names = "--fourth-long-option-name", paramLabel = "") int d; - } - Help help = new Help(new App(), Help.defaultColorScheme(Help.Ansi.ON)); - assertEquals(Help.Ansi.ON.new Text(String.format( - "@|bold |@ [@|yellow --another-long-option-name|@=@|italic ^[]|@]%n" + - " [@|yellow --fourth-long-option-name|@=@|italic |@]%n" + - " [@|yellow --long-option@-name|@=@|italic |@]%n" + - " [@|yellow --third-long-option-name|@=@|italic |@]%n")), - help.synopsis(0)); - } - - @Test - public void testCustomSynopsis() { - @Command(customSynopsis = { - " --number=NUMBER --other-option=", - " --more=OTHER --and-other-option=", - " --number=NUMBER --and-other-option=", - }) - class App {@Option(names = "--ignored") boolean ignored;} - Help help = new Help(new App(), Help.Ansi.OFF); - assertEquals(String.format( - " --number=NUMBER --other-option=%n" + - " --more=OTHER --and-other-option=%n" + - " --number=NUMBER --and-other-option=%n"), - help.synopsis(0)); - } - @Test - public void testTextTable() { - TextTable table = new TextTable(Help.Ansi.OFF); - table.addRowValues(textArray(Help.Ansi.OFF, "", "-v", ",", "--verbose", "show what you're doing while you are doing it")); - table.addRowValues(textArray(Help.Ansi.OFF, "", "-p", null, null, "the quick brown fox jumped over the lazy dog. The quick brown fox jumped over the lazy dog.")); - assertEquals(String.format( - " -v, --verbose show what you're doing while you are doing it%n" + - " -p the quick brown fox jumped over the lazy dog. The%n" + - " quick brown fox jumped over the lazy dog.%n" - ,""), table.toString(new StringBuilder()).toString()); - } - - @Test(expected = IllegalArgumentException.class) - public void testTextTableAddsNewRowWhenTooManyValuesSpecified() { - TextTable table = new TextTable(Help.Ansi.OFF); - table.addRowValues(textArray(Help.Ansi.OFF, "", "-c", ",", "--create", "description", "INVALID", "Row 3")); -// assertEquals(String.format("" + -// " -c, --create description %n" + -// " INVALID %n" + -// " Row 3 %n" -// ,""), table.toString(new StringBuilder()).toString()); - } - - @Test - public void testTextTableAddsNewRowWhenAnyColumnTooLong() { - TextTable table = new TextTable(Help.Ansi.OFF); - table.addRowValues("*", "-c", ",", - "--create, --create2, --create3, --create4, --create5, --create6, --create7, --create8", - "description"); - assertEquals(String.format("" + - "* -c, --create, --create2, --create3, --create4, --create5, --create6,%n" + - " --create7, --create8%n" + - " description%n" - ,""), table.toString(new StringBuilder()).toString()); - - table = new TextTable(Help.Ansi.OFF); - table.addRowValues("", "-c", ",", - "--create, --create2, --create3, --create4, --create5, --create6, --createAA7, --create8", - "description"); - assertEquals(String.format("" + - " -c, --create, --create2, --create3, --create4, --create5, --create6,%n" + - " --createAA7, --create8%n" + - " description%n" - ,""), table.toString(new StringBuilder()).toString()); - } - - @Test - public void testCatUsageFormat() { - @Command(name = "cat", - customSynopsis = "cat [OPTIONS] [FILE...]", - description = "Concatenate FILE(s), or standard input, to standard output.", - footer = "Copyright(c) 2017") - class Cat { - @Parameters(paramLabel = "FILE", hidden = true, description = "Files whose contents to display") List files; - @Option(names = "--help", help = true, description = "display this help and exit") boolean help; - @Option(names = "--version", help = true, description = "output version information and exit") boolean version; - @Option(names = "-u", description = "(ignored)") boolean u; - @Option(names = "-t", description = "equivalent to -vT") boolean t; - @Option(names = "-e", description = "equivalent to -vET") boolean e; - @Option(names = {"-A", "--show-all"}, description = "equivalent to -vET") boolean showAll; - @Option(names = {"-s", "--squeeze-blank"}, description = "suppress repeated empty output lines") boolean squeeze; - @Option(names = {"-v", "--show-nonprinting"}, description = "use ^ and M- notation, except for LDF and TAB") boolean v; - @Option(names = {"-b", "--number-nonblank"}, description = "number nonempty output lines, overrides -n") boolean b; - @Option(names = {"-T", "--show-tabs"}, description = "display TAB characters as ^I") boolean T; - @Option(names = {"-E", "--show-ends"}, description = "display $ at end of each line") boolean E; - @Option(names = {"-n", "--number"}, description = "number all output lines") boolean n; - } - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - CommandLine.usage(new Cat(), new PrintStream(baos), Help.Ansi.OFF); - String expected = String.format( - "Usage: cat [OPTIONS] [FILE...]%n" + - "Concatenate FILE(s), or standard input, to standard output.%n" + - " -A, --show-all equivalent to -vET%n" + - " -b, --number-nonblank number nonempty output lines, overrides -n%n" + - " -e equivalent to -vET%n" + - " -E, --show-ends display $ at end of each line%n" + - " -n, --number number all output lines%n" + - " -s, --squeeze-blank suppress repeated empty output lines%n" + - " -t equivalent to -vT%n" + - " -T, --show-tabs display TAB characters as ^I%n" + - " -u (ignored)%n" + - " -v, --show-nonprinting use ^ and M- notation, except for LDF and TAB%n" + - " --help display this help and exit%n" + - " --version output version information and exit%n" + - "Copyright(c) 2017%n", ""); - assertEquals(expected, baos.toString()); - } - - @Test - public void testZipUsageFormat() { - String expected = String.format("" + - "Copyright (c) 1990-2008 Info-ZIP - Type 'zip \"-L\"' for software license.%n" + - "Zip 3.0 (July 5th 2008). Command:%n" + - "zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]%n" + - " The default action is to add or replace zipfile entries from list, which%n" + - " can include the special name - to compress standard input.%n" + - " If zipfile and list are omitted, zip compresses stdin to stdout.%n" + - " -f freshen: only changed files -u update: only changed or new files%n" + - " -d delete entries in zipfile -m move into zipfile (delete OS files)%n" + - " -r recurse into directories -j junk (don't record) directory names%n" + - " -0 store only -l convert LF to CR LF (-ll CR LF to LF)%n" + - " -1 compress faster -9 compress better%n" + - " -q quiet operation -v verbose operation/print version info%n" + - " -c add one-line comments -z add zipfile comment%n" + - " -@ read names from stdin -o make zipfile as old as latest entry%n" + - " -x exclude the following names -i include only the following names%n" + - " -F fix zipfile (-FF try harder) -D do not add directory entries%n" + - " -A adjust self-extracting exe -J junk zipfile prefix (unzipsfx)%n" + - " -T test zipfile integrity -X eXclude eXtra file attributes%n" + - " -y store symbolic links as the link instead of the referenced file%n" + - " -e encrypt -n don't compress these suffixes%n" + - " -h2 show more help%n"); - assertEquals(expected, CustomLayoutDemo.createZipUsageFormat(Help.Ansi.OFF)); - } - @Test - public void testNetstatUsageFormat() { - String expected = String.format("" + - "Displays protocol statistics and current TCP/IP network connections.%n" + - "%n" + - "NETSTAT [-a] [-b] [-e] [-f] [-n] [-o] [-p proto] [-q] [-r] [-s] [-t] [-x] [-y]%n" + - " [interval]%n" + - "%n" + - " -a Displays all connections and listening ports.%n" + - " -b Displays the executable involved in creating each connection or%n" + - " listening port. In some cases well-known executables host%n" + - " multiple independent components, and in these cases the%n" + - " sequence of components involved in creating the connection or%n" + - " listening port is displayed. In this case the executable name%n" + - " is in [] at the bottom, on top is the component it called, and%n" + - " so forth until TCP/IP was reached. Note that this option can be%n" + - " time-consuming and will fail unless you have sufficient%n" + - " permissions.%n" + - " -e Displays Ethernet statistics. This may be combined with the -s%n" + - " option.%n" + - " -f Displays Fully Qualified Domain Names (FQDN) for foreign%n" + - " addresses.%n" + - " -n Displays addresses and port numbers in numerical form.%n" + - " -o Displays the owning process ID associated with each connection.%n" + - " -p proto Shows connections for the protocol specified by proto; proto%n" + - " may be any of: TCP, UDP, TCPv6, or UDPv6. If used with the -s%n" + - " option to display per-protocol statistics, proto may be any of:%n" + - " IP, IPv6, ICMP, ICMPv6, TCP, TCPv6, UDP, or UDPv6.%n" + - " -q Displays all connections, listening ports, and bound%n" + - " nonlistening TCP ports. Bound nonlistening ports may or may not%n" + - " be associated with an active connection.%n" + - " -r Displays the routing table.%n" + - " -s Displays per-protocol statistics. By default, statistics are%n" + - " shown for IP, IPv6, ICMP, ICMPv6, TCP, TCPv6, UDP, and UDPv6;%n" + - " the -p option may be used to specify a subset of the default.%n" + - " -t Displays the current connection offload state.%n" + - " -x Displays NetworkDirect connections, listeners, and shared%n" + - " endpoints.%n" + - " -y Displays the TCP connection template for all connections.%n" + - " Cannot be combined with the other options.%n" + - " interval Redisplays selected statistics, pausing interval seconds%n" + - " between each display. Press CTRL+C to stop redisplaying%n" + - " statistics. If omitted, netstat will print the current%n" + - " configuration information once.%n" - , ""); - assertEquals(expected, CustomLayoutDemo.createNetstatUsageFormat(Help.Ansi.OFF)); - } - - @Test - public void testUsageIndexedPositionalParameters() throws UnsupportedEncodingException { - @Command() - class App { - @Parameters(index = "0", description = "source host") InetAddress host1; - @Parameters(index = "1", description = "source port") int port1; - @Parameters(index = "2", description = "destination host") InetAddress host2; - @Parameters(index = "3", arity = "1..2", description = "destination port range") int[] port2range; - @Parameters(index = "4..*", description = "files to transfer") String[] files; - @Parameters(hidden = true) String[] all; - } - String actual = usageString(new App(), Help.Ansi.OFF); - String expected = String.format( - "Usage:
    []%n" + - " []...%n" + - " source host%n" + - " source port%n" + - " destination host%n" + - " []%n" + - " destination port range%n" + - " []... files to transfer%n" - ); - assertEquals(expected, actual); - } - @Command(name = "base", abbreviateSynopsis = true, commandListHeading = "c o m m a n d s", - customSynopsis = "cust", description = "base description", descriptionHeading = "base descr heading", - footer = "base footer", footerHeading = "base footer heading", - header = "base header", headerHeading = "base header heading", - optionListHeading = "base option heading", parameterListHeading = "base param heading", - requiredOptionMarker = '&', separator = ";", showDefaultValues = true, - sortOptions = false, synopsisHeading = "abcd") - class Base { } - - @Test - public void testAttributesInheritedWhenSubclassingForReuse() throws UnsupportedEncodingException { - @Command - class EmptySub extends Base {} - Help help = new Help(new EmptySub()); - assertEquals("base", help.commandName); - assertEquals(String.format("cust%n"), help.synopsis(0)); - assertEquals(String.format("cust%n"), help.customSynopsis()); - assertEquals(String.format("base%n"), help.abbreviatedSynopsis()); - assertEquals(String.format("base%n"), help.detailedSynopsis(0,null, true)); - assertEquals("abcd", help.synopsisHeading); - assertEquals("", help.commandList()); - assertEquals("c o m m a n d s", help.commandListHeading); - assertEquals(String.format("base description%n"), help.description()); - assertEquals("base descr heading", help.descriptionHeading); - assertEquals(String.format("base footer%n"), help.footer()); - assertEquals("base footer heading", help.footerHeading); - assertEquals(String.format("base header%n"), help.header()); - assertEquals("base header heading", help.headerHeading); - assertEquals("", help.optionList()); - assertEquals("base option heading", help.optionListHeading); - assertEquals("", help.parameterList()); - assertEquals("base param heading", help.parameterListHeading); - - // these values NOT inherited!! - assertEquals("=", help.separator); - assertEquals(' ', help.requiredOptionMarker.charValue()); - assertFalse(help.abbreviateSynopsis); - assertFalse(help.showDefaultValues); - assertTrue(help.sortOptions); - } - - @Test - public void testSubclassAttributesOverrideEmptySuper() { - @Command - class EmptyBase {} - @Command(name = "base", abbreviateSynopsis = true, commandListHeading = "c o m m a n d s", - customSynopsis = "cust", description = "base description", descriptionHeading = "base descr heading", - footer = "base footer", footerHeading = "base footer heading", - header = "base header", headerHeading = "base header heading", - optionListHeading = "base option heading", parameterListHeading = "base param heading", - requiredOptionMarker = '&', separator = ";", showDefaultValues = true, - sortOptions = false, synopsisHeading = "abcd") - class FullBase extends EmptyBase{ } - Help help = new Help(new FullBase()); - assertEquals("base", help.commandName); - assertEquals(String.format("cust%n"), help.synopsis(0)); - assertEquals(String.format("cust%n"), help.customSynopsis()); - assertEquals(String.format("base%n"), help.abbreviatedSynopsis()); - assertEquals(String.format("base%n"), help.detailedSynopsis(0, null, true)); - assertEquals("abcd", help.synopsisHeading); - assertEquals("", help.commandList()); - assertEquals("c o m m a n d s", help.commandListHeading); - assertEquals(String.format("base description%n"), help.description()); - assertEquals("base descr heading", help.descriptionHeading); - assertEquals(String.format("base footer%n"), help.footer()); - assertEquals("base footer heading", help.footerHeading); - assertEquals(String.format("base header%n"), help.header()); - assertEquals("base header heading", help.headerHeading); - assertEquals("", help.optionList()); - assertEquals("base option heading", help.optionListHeading); - assertEquals("", help.parameterList()); - assertEquals("base param heading", help.parameterListHeading); - assertTrue(help.abbreviateSynopsis); - assertTrue(help.showDefaultValues); - assertFalse(help.sortOptions); - assertEquals(";", help.separator); - assertEquals('&', help.requiredOptionMarker.charValue()); - } - @Test - public void testSubclassAttributesOverrideSuperValues() { - @Command(name = "sub", abbreviateSynopsis = false, commandListHeading = "subc o m m a n d s", - customSynopsis = "subcust", description = "sub description", descriptionHeading = "sub descr heading", - footer = "sub footer", footerHeading = "sub footer heading", - header = "sub header", headerHeading = "sub header heading", - optionListHeading = "sub option heading", parameterListHeading = "sub param heading", - requiredOptionMarker = '%', separator = ":", showDefaultValues = false, - sortOptions = true, synopsisHeading = "xyz") - class FullSub extends Base{ } - Help help = new Help(new FullSub()); - assertEquals("sub", help.commandName); - assertEquals(String.format("subcust%n"), help.synopsis(0)); - assertEquals(String.format("subcust%n"), help.customSynopsis()); - assertEquals(String.format("sub%n"), help.abbreviatedSynopsis()); - assertEquals(String.format("sub%n"), help.detailedSynopsis(0,null, true)); - assertEquals("xyz", help.synopsisHeading); - assertEquals("", help.commandList()); - assertEquals("subc o m m a n d s", help.commandListHeading); - assertEquals(String.format("sub description%n"), help.description()); - assertEquals("sub descr heading", help.descriptionHeading); - assertEquals(String.format("sub footer%n"), help.footer()); - assertEquals("sub footer heading", help.footerHeading); - assertEquals(String.format("sub header%n"), help.header()); - assertEquals("sub header heading", help.headerHeading); - assertEquals("", help.optionList()); - assertEquals("sub option heading", help.optionListHeading); - assertEquals("", help.parameterList()); - assertEquals("sub param heading", help.parameterListHeading); - assertFalse(help.abbreviateSynopsis); - assertFalse(help.showDefaultValues); - assertTrue(help.sortOptions); - assertEquals(":", help.separator); - assertEquals('%', help.requiredOptionMarker.charValue()); - } - static class UsageDemo { - @Option(names = "-a", description = "boolean option with short name only") - boolean a; - - @Option(names = "-b", paramLabel = "INT", description = "short option with a parameter") - int b; - - @Option(names = {"-c", "--c-option"}, description = "boolean option with short and long name") - boolean c; - - @Option(names = {"-d", "--d-option"}, paramLabel = "FILE", description = "option with parameter and short and long name") - File d; - - @Option(names = "--e-option", description = "boolean option with only a long name") - boolean e; - - @Option(names = "--f-option", paramLabel = "STRING", description = "option with parameter and only a long name") - String f; - - @Option(names = {"-g", "--g-option-with-a-name-so-long-that-it-runs-into-the-descriptions-column"}, description = "boolean option with short and long name") - boolean g; - - @Parameters(index = "0", paramLabel = "0BLAH", description = "first parameter") - String param0; - - @Parameters(index = "1", paramLabel = "1PARAMETER-with-a-name-so-long-that-it-runs-into-the-descriptions-column", description = "2nd parameter") - String param1; - - @Parameters(index = "2..*", paramLabel = "remaining", description = "remaining parameters") - String param2_n; - - @Parameters(index = "*", paramLabel = "all", description = "all parameters") - String param_n; - } - - @Test - public void testSubclassedCommandHelp() throws Exception { - @Command(name = "parent", description = "parent description") - class ParentOption { - } - @Command(name = "child", description = "child description") - class ChildOption extends ParentOption { - } - String actual = usageString(new ChildOption(), Help.Ansi.OFF); - assertEquals(String.format( - "Usage: child%n" + - "child description%n"), actual); - } - - @Test - public void testSynopsisOrderCorrectWhenParametersDeclaredOutOfOrder() { - class WithParams { - @Parameters(index = "1") String param1; - @Parameters(index = "0") String param0; - } - Help help = new Help(new WithParams()); - assertEquals(format("
    %n"), help.synopsis(0)); - } - - @Test - public void testSynopsisOrderCorrectWhenSubClassAddsParameters() { - class BaseWithParams { - @Parameters(index = "1") String param1; - @Parameters(index = "0") String param0; - } - class SubWithParams extends BaseWithParams { - @Parameters(index = "3") String param3; - @Parameters(index = "2") String param2; - } - Help help = new Help(new SubWithParams()); - assertEquals(format("
    %n"), help.synopsis(0)); - } - - @Test - public void testUsageMainCommand_NoAnsi() throws Exception { - String actual = usageString(Demo.mainCommand(), Help.Ansi.OFF); - assertEquals(String.format(Demo.EXPECTED_USAGE_MAIN), actual); - } - - @Test - public void testUsageMainCommand_ANSI() throws Exception { - String actual = usageString(Demo.mainCommand(), Help.Ansi.ON); - assertEquals(Help.Ansi.ON.new Text(String.format(Demo.EXPECTED_USAGE_MAIN_ANSI)), actual); - } - - @Test - public void testUsageSubcommandGitStatus_NoAnsi() throws Exception { - String actual = usageString(new Demo.GitStatus(), Help.Ansi.OFF); - assertEquals(String.format(Demo.EXPECTED_USAGE_GITSTATUS), actual); - } - - @Test - public void testUsageSubcommandGitStatus_ANSI() throws Exception { - String actual = usageString(new Demo.GitStatus(), Help.Ansi.ON); - assertEquals(Help.Ansi.ON.new Text(String.format(Demo.EXPECTED_USAGE_GITSTATUS_ANSI)), actual); - } - - @Test - public void testUsageSubcommandGitCommit_NoAnsi() throws Exception { - String actual = usageString(new Demo.GitCommit(), Help.Ansi.OFF); - assertEquals(String.format(Demo.EXPECTED_USAGE_GITCOMMIT), actual); - } - - @Test - public void testUsageSubcommandGitCommit_ANSI() throws Exception { - String actual = usageString(new Demo.GitCommit(), Help.Ansi.ON); - assertEquals(Help.Ansi.ON.new Text(String.format(Demo.EXPECTED_USAGE_GITCOMMIT_ANSI)), actual); - } - - @Test - public void testUsageNestedSubcommand() throws IOException { - @Command(name = "main") class MainCommand { @Option(names = "-a") boolean a; @Option(names = "-h", help = true) boolean h;} - @Command(name = "cmd1") class ChildCommand1 { @Option(names = "-b") boolean b; } - @Command(name = "cmd2") class ChildCommand2 { @Option(names = "-c") boolean c; @Option(names = "-h", help = true) boolean h;} - @Command(name = "sub11") class GrandChild1Command1 { @Option(names = "-d") boolean d; } - @Command(name = "sub12") class GrandChild1Command2 { @Option(names = "-e") int e; } - @Command(name = "sub21") class GrandChild2Command1 { @Option(names = "-h", help = true) boolean h; } - @Command(name = "sub22") class GrandChild2Command2 { @Option(names = "-g") boolean g; } - @Command(name = "sub22sub1") class GreatGrandChild2Command2_1 { - @Option(names = "-h", help = true) boolean h; - @Option(names = {"-t", "--type"}) String customType; - } - CommandLine commandLine = new CommandLine(new MainCommand()); - commandLine - .addSubcommand("cmd1", new CommandLine(new ChildCommand1()) - .addSubcommand("sub11", new GrandChild1Command1()) - .addSubcommand("sub12", new GrandChild1Command2()) - ) - .addSubcommand("cmd2", new CommandLine(new ChildCommand2()) - .addSubcommand("sub21", new GrandChild2Command1()) - .addSubcommand("sub22", new CommandLine(new GrandChild2Command2()) - .addSubcommand("sub22sub1", new GreatGrandChild2Command2_1()) - ) - ); - String main = usageString(commandLine, Help.Ansi.OFF); - assertEquals(String.format("" + - "Usage: main [-ah]%n" + - " -a%n" + - " -h%n" + - "Commands:%n" + - " cmd1%n" + - " cmd2%n"), main); - - String cmd2 = usageString(commandLine.getSubcommands().get("cmd2"), Help.Ansi.OFF); - assertEquals(String.format("" + - "Usage: cmd2 [-ch]%n" + - " -c%n" + - " -h%n" + - "Commands:%n" + - " sub21%n" + - " sub22%n"), cmd2); - - String sub22 = usageString(commandLine.getSubcommands().get("cmd2").getSubcommands().get("sub22"), Help.Ansi.OFF); - assertEquals(String.format("" + - "Usage: sub22 [-g]%n" + - " -g%n" + - "Commands:%n" + - " sub22sub1%n"), sub22); - } - - @Test - public void testTextConstructorPlain() { - assertEquals("--NoAnsiFormat", Help.Ansi.ON.new Text("--NoAnsiFormat").toString()); - } - - @Test - public void testTextConstructorWithStyle() { - assertEquals("\u001B[1m--NoAnsiFormat\u001B[21m\u001B[0m", Help.Ansi.ON.new Text("@|bold --NoAnsiFormat|@").toString()); - } - - @Ignore("Until nested styles are supported") - @Test - public void testTextConstructorWithNestedStyle() { - assertEquals("\u001B[1mfirst \u001B[2msecond\u001B[22m\u001B[21m", Help.Ansi.ON.new Text("@|bold first @|underline second|@|@").toString()); - assertEquals("\u001B[1mfirst \u001B[4msecond\u001B[24m third\u001B[21m", Help.Ansi.ON.new Text("@|bold first @|underline second|@ third|@").toString()); - } - - @Test - public void testTextApply() { - Text txt = Help.Ansi.ON.apply("--p", Arrays.asList(Style.fg_red, Style.bold)); - assertEquals(Help.Ansi.ON.new Text("@|fg(red),bold --p|@"), txt); - } - - @Test - public void testTextDefaultColorScheme() { - Help.Ansi ansi = Help.Ansi.ON; - ColorScheme scheme = Help.defaultColorScheme(ansi); - assertEquals(scheme.ansi().new Text("@|yellow -p|@"), scheme.optionText("-p")); - assertEquals(scheme.ansi().new Text("@|bold command|@"), scheme.commandText("command")); - assertEquals(scheme.ansi().new Text("@|yellow FILE|@"), scheme.parameterText("FILE")); - assertEquals(scheme.ansi().new Text("@|italic NUMBER|@"), scheme.optionParamText("NUMBER")); - } - - @Test - public void testTextSubString() { - Help.Ansi ansi = Help.Ansi.ON; - Text txt = ansi.new Text("@|bold 01234|@").append("56").append("@|underline 7890|@"); - assertEquals(ansi.new Text("@|bold 01234|@56@|underline 7890|@"), txt.substring(0)); - assertEquals(ansi.new Text("@|bold 1234|@56@|underline 7890|@"), txt.substring(1)); - assertEquals(ansi.new Text("@|bold 234|@56@|underline 7890|@"), txt.substring(2)); - assertEquals(ansi.new Text("@|bold 34|@56@|underline 7890|@"), txt.substring(3)); - assertEquals(ansi.new Text("@|bold 4|@56@|underline 7890|@"), txt.substring(4)); - assertEquals(ansi.new Text("56@|underline 7890|@"), txt.substring(5)); - assertEquals(ansi.new Text("6@|underline 7890|@"), txt.substring(6)); - assertEquals(ansi.new Text("@|underline 7890|@"), txt.substring(7)); - assertEquals(ansi.new Text("@|underline 890|@"), txt.substring(8)); - assertEquals(ansi.new Text("@|underline 90|@"), txt.substring(9)); - assertEquals(ansi.new Text("@|underline 0|@"), txt.substring(10)); - assertEquals(ansi.new Text(""), txt.substring(11)); - assertEquals(ansi.new Text("@|bold 01234|@56@|underline 7890|@"), txt.substring(0, 11)); - assertEquals(ansi.new Text("@|bold 01234|@56@|underline 789|@"), txt.substring(0, 10)); - assertEquals(ansi.new Text("@|bold 01234|@56@|underline 78|@"), txt.substring(0, 9)); - assertEquals(ansi.new Text("@|bold 01234|@56@|underline 7|@"), txt.substring(0, 8)); - assertEquals(ansi.new Text("@|bold 01234|@56"), txt.substring(0, 7)); - assertEquals(ansi.new Text("@|bold 01234|@5"), txt.substring(0, 6)); - assertEquals(ansi.new Text("@|bold 01234|@"), txt.substring(0, 5)); - assertEquals(ansi.new Text("@|bold 0123|@"), txt.substring(0, 4)); - assertEquals(ansi.new Text("@|bold 012|@"), txt.substring(0, 3)); - assertEquals(ansi.new Text("@|bold 01|@"), txt.substring(0, 2)); - assertEquals(ansi.new Text("@|bold 0|@"), txt.substring(0, 1)); - assertEquals(ansi.new Text(""), txt.substring(0, 0)); - assertEquals(ansi.new Text("@|bold 1234|@56@|underline 789|@"), txt.substring(1, 10)); - assertEquals(ansi.new Text("@|bold 234|@56@|underline 78|@"), txt.substring(2, 9)); - assertEquals(ansi.new Text("@|bold 34|@56@|underline 7|@"), txt.substring(3, 8)); - assertEquals(ansi.new Text("@|bold 4|@56"), txt.substring(4, 7)); - assertEquals(ansi.new Text("5"), txt.substring(5, 6)); - assertEquals(ansi.new Text("@|bold 2|@"), txt.substring(2, 3)); - assertEquals(ansi.new Text("@|underline 8|@"), txt.substring(8, 9)); - - Text txt2 = ansi.new Text("@|bold abc|@@|underline DEF|@"); - assertEquals(ansi.new Text("@|bold abc|@@|underline DEF|@"), txt2.substring(0)); - assertEquals(ansi.new Text("@|bold bc|@@|underline DEF|@"), txt2.substring(1)); - assertEquals(ansi.new Text("@|bold abc|@@|underline DE|@"), txt2.substring(0,5)); - assertEquals(ansi.new Text("@|bold bc|@@|underline DE|@"), txt2.substring(1,5)); - } - @Test - public void testTextSplitLines() { - Help.Ansi ansi = Help.Ansi.ON; - Text[] all = { - ansi.new Text("@|bold 012\n34|@").append("5\nAA\n6").append("@|underline 78\n90|@"), - ansi.new Text("@|bold 012\r34|@").append("5\rAA\r6").append("@|underline 78\r90|@"), - ansi.new Text("@|bold 012\r\n34|@").append("5\r\nAA\r\n6").append("@|underline 78\r\n90|@"), - }; - for (Text text : all) { - Text[] lines = text.splitLines(); - int i = 0; - assertEquals(ansi.new Text("@|bold 012|@"), lines[i++]); - assertEquals(ansi.new Text("@|bold 34|@5"), lines[i++]); - assertEquals(ansi.new Text("AA"), lines[i++]); - assertEquals(ansi.new Text("6@|underline 78|@"), lines[i++]); - assertEquals(ansi.new Text("@|underline 90|@"), lines[i++]); - } - } - @Test - public void testTextSplitLinesStartEnd() { - Help.Ansi ansi = Help.Ansi.ON; - Text[] all = { - ansi.new Text("\n@|bold 012\n34|@").append("5\nAA\n6").append("@|underline 78\n90|@\n"), - ansi.new Text("\r@|bold 012\r34|@").append("5\rAA\r6").append("@|underline 78\r90|@\r"), - ansi.new Text("\r\n@|bold 012\r\n34|@").append("5\r\nAA\r\n6").append("@|underline 78\r\n90|@\r\n"), - }; - for (Text text : all) { - Text[] lines = text.splitLines(); - int i = 0; - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text("@|bold 012|@"), lines[i++]); - assertEquals(ansi.new Text("@|bold 34|@5"), lines[i++]); - assertEquals(ansi.new Text("AA"), lines[i++]); - assertEquals(ansi.new Text("6@|underline 78|@"), lines[i++]); - assertEquals(ansi.new Text("@|underline 90|@"), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - } - } - @Test - public void testTextSplitLinesStartEndIntermediate() { - Help.Ansi ansi = Help.Ansi.ON; - Text[] all = { - ansi.new Text("\n@|bold 012\n\n\n34|@").append("5\n\n\nAA\n\n\n6").append("@|underline 78\n90|@\n"), - ansi.new Text("\r@|bold 012\r\r\r34|@").append("5\r\r\rAA\r\r\r6").append("@|underline 78\r90|@\r"), - ansi.new Text("\r\n@|bold 012\r\n\r\n\r\n34|@").append("5\r\n\r\n\r\nAA\r\n\r\n\r\n6").append("@|underline 78\r\n90|@\r\n"), - }; - for (Text text : all) { - Text[] lines = text.splitLines(); - int i = 0; - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text("@|bold 012|@"), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text("@|bold 34|@5"), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text("AA"), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - assertEquals(ansi.new Text("6@|underline 78|@"), lines[i++]); - assertEquals(ansi.new Text("@|underline 90|@"), lines[i++]); - assertEquals(ansi.new Text(""), lines[i++]); - } - } - @Test - public void testEmbeddedNewLinesInUsageSections() throws UnsupportedEncodingException { - @Command(description = "first line\nsecond line\nthird line", headerHeading = "headerHeading1\nheaderHeading2", - header = "header1\nheader2", descriptionHeading = "descriptionHeading1\ndescriptionHeading2", - footerHeading = "footerHeading1\nfooterHeading2", footer = "footer1\nfooter2") - class App { - @Option(names = {"-v", "--verbose"}, description = "optionDescription1\noptionDescription2") boolean v; - @Parameters(description = "paramDescription1\nparamDescription2") String file; - } - String actual = usageString(new App(), Help.Ansi.OFF); - String expected = String.format("" + - "headerHeading1%n" + - "headerHeading2header1%n" + - "header2%n" + - "Usage:
    [-v] %n" + - "descriptionHeading1%n" + - "descriptionHeading2first line%n" + - "second line%n" + - "third line%n" + - " paramDescription1%n" + - " paramDescription2%n" + - " -v, --verbose optionDescription1%n" + - " optionDescription2%n" + - "footerHeading1%n" + - "footerHeading2footer1%n" + - "footer2%n"); - assertEquals(expected, actual); - } - @Test - public void testTextWithMultipleStyledSections() { - assertEquals("\u001B[1m
    \u001B[21m\u001B[0m [\u001B[33m-v\u001B[39m\u001B[0m] [\u001B[33m-c\u001B[39m\u001B[0m [\u001B[3m\u001B[23m\u001B[0m]]", - Help.Ansi.ON.new Text("@|bold
    |@ [@|yellow -v|@] [@|yellow -c|@ [@|italic |@]]").toString()); - } - - @Test - public void testTextAdjacentStyles() { - assertEquals("\u001B[3m\u001B[23m\u001B[0m%n", - Help.Ansi.ON.new Text("@|italic |@%n").toString()); - } - - @Test - public void testTextNoConversionWithoutClosingTag() { - assertEquals("\u001B[3mabc\u001B[23m\u001B[0m", Help.Ansi.ON.new Text("@|italic abc|@").toString()); - assertEquals("@|italic abc", Help.Ansi.ON.new Text("@|italic abc").toString()); - } - - @Test - public void testTextNoConversionWithoutSpaceSeparator() { - assertEquals("\u001B[3ma\u001B[23m\u001B[0m", Help.Ansi.ON.new Text("@|italic a|@").toString()); - assertEquals("@|italic|@", Help.Ansi.ON.new Text("@|italic|@").toString()); - assertEquals("", Help.Ansi.ON.new Text("@|italic |@").toString()); - } - - @Test - public void testPalette236ColorForegroundIndex() { - assertEquals("\u001B[38;5;45mabc\u001B[39m\u001B[0m", Help.Ansi.ON.new Text("@|fg(45) abc|@").toString()); - } - - @Test - public void testPalette236ColorForegroundRgb() { - int num = 16 + 36 * 5 + 6 * 5 + 5; - assertEquals("\u001B[38;5;" + num + "mabc\u001B[39m\u001B[0m", Help.Ansi.ON.new Text("@|fg(5;5;5) abc|@").toString()); - } - - @Test - public void testPalette236ColorBackgroundIndex() { - assertEquals("\u001B[48;5;77mabc\u001B[49m\u001B[0m", Help.Ansi.ON.new Text("@|bg(77) abc|@").toString()); - } - - @Test - public void testPalette236ColorBackgroundRgb() { - int num = 16 + 36 * 3 + 6 * 3 + 3; - assertEquals("\u001B[48;5;" + num + "mabc\u001B[49m\u001B[0m", Help.Ansi.ON.new Text("@|bg(3;3;3) abc|@").toString()); - } - - @Test - public void testAnsiEnabled() { - assertTrue(Help.Ansi.ON.enabled()); - assertFalse(Help.Ansi.OFF.enabled()); - - System.setProperty("picocli.ansi", "true"); - assertEquals(true, Help.Ansi.AUTO.enabled()); - - System.setProperty("picocli.ansi", "false"); - assertEquals(false, Help.Ansi.AUTO.enabled()); - - System.clearProperty("picocli.ansi"); - boolean isWindows = System.getProperty("os.name").startsWith("Windows"); - boolean isXterm = System.getenv("TERM") != null && System.getenv("TERM").startsWith("xterm"); - boolean isAtty = (isWindows && isXterm) // cygwin pseudo-tty - || hasConsole(); - assertEquals(isAtty && (!isWindows || isXterm), Help.Ansi.AUTO.enabled()); - } - - private boolean hasConsole() { - try { return System.class.getDeclaredMethod("console").invoke(null) != null; } - catch (Throwable reflectionFailed) { return true; } - } - - @Test - public void testSystemPropertiesOverrideDefaultColorScheme() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters(paramLabel = "FILE", arity = "1..*") File[] files; - } - Help.Ansi ansi = Help.Ansi.ON; - // default color scheme - assertEquals(ansi.new Text("@|bold
    |@ [@|yellow -v|@] [@|yellow -c|@=@|italic |@] @|yellow FILE|@..." + LINESEP), - new Help(new App(), ansi).synopsis(0)); - - System.setProperty("picocli.color.commands", "blue"); - System.setProperty("picocli.color.options", "green"); - System.setProperty("picocli.color.parameters", "cyan"); - System.setProperty("picocli.color.optionParams", "magenta"); - assertEquals(ansi.new Text("@|blue
    |@ [@|green -v|@] [@|green -c|@=@|magenta |@] @|cyan FILE|@..." + LINESEP), - new Help(new App(), ansi).synopsis(0)); - } - - @Test - public void testSystemPropertiesOverrideExplicitColorScheme() { - @CommandLine.Command(separator = "=") class App { - @Option(names = {"--verbose", "-v"}) boolean verbose; - @Option(names = {"--count", "-c"}) int count; - @Option(names = {"--help", "-h"}, hidden = true) boolean helpRequested; - @Parameters(paramLabel = "FILE", arity = "1..*") File[] files; - } - Help.Ansi ansi = Help.Ansi.ON; - ColorScheme explicit = new ColorScheme(ansi) - .commands(Style.faint, Style.bg_magenta) - .options(Style.bg_red) - .parameters(Style.reverse) - .optionParams(Style.bg_green); - // default color scheme - assertEquals(ansi.new Text("@|faint,bg(magenta)
    |@ [@|bg(red) -v|@] [@|bg(red) -c|@=@|bg(green) |@] @|reverse FILE|@..." + LINESEP), - new Help(new App(), explicit).synopsis(0)); - - System.setProperty("picocli.color.commands", "blue"); - System.setProperty("picocli.color.options", "blink"); - System.setProperty("picocli.color.parameters", "red"); - System.setProperty("picocli.color.optionParams", "magenta"); - assertEquals(ansi.new Text("@|blue
    |@ [@|blink -v|@] [@|blink -c|@=@|magenta |@] @|red FILE|@..." + LINESEP), - new Help(new App(), explicit).synopsis(0)); - } - - @Test - public void testCommandLine_printVersionInfo_printsSinglePlainTextString() throws Exception { - @Command(version = "1.0") class Versioned {} - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new CommandLine(new Versioned()).printVersionHelp(new PrintStream(baos, true, "UTF8"), Help.Ansi.OFF); - String result = baos.toString("UTF8"); - assertEquals(String.format("1.0%n"), result); - } - - @Test - public void testCommandLine_printVersionInfo_printsArrayOfPlainTextStrings() throws Exception { - @Command(version = {"Versioned Command 1.0", "512-bit superdeluxe", "(c) 2017"}) class Versioned {} - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new CommandLine(new Versioned()).printVersionHelp(new PrintStream(baos, true, "UTF8"), Help.Ansi.OFF); - String result = baos.toString("UTF8"); - assertEquals(String.format("Versioned Command 1.0%n512-bit superdeluxe%n(c) 2017%n"), result); - } - - @Test - public void testCommandLine_printVersionInfo_printsSingleStringWithMarkup() throws Exception { - @Command(version = "@|red 1.0|@") class Versioned {} - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new CommandLine(new Versioned()).printVersionHelp(new PrintStream(baos, true, "UTF8"), Help.Ansi.ON); - String result = baos.toString("UTF8"); - assertEquals(String.format("\u001B[31m1.0\u001B[39m\u001B[0m%n"), result); - } - - @Test - public void testCommandLine_printVersionInfo_printsArrayOfStringsWithMarkup() throws Exception { - @Command(version = { - "@|yellow Versioned Command 1.0|@", - "@|blue Build 12345|@", - "@|red,bg(white) (c) 2017|@" }) - class Versioned {} - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - new CommandLine(new Versioned()).printVersionHelp(new PrintStream(baos, true, "UTF8"), Help.Ansi.ON); - String result = baos.toString("UTF8"); - assertEquals(String.format("" + - "\u001B[33mVersioned Command 1.0\u001B[39m\u001B[0m%n" + - "\u001B[34mBuild 12345\u001B[39m\u001B[0m%n" + - "\u001B[31m\u001B[47m(c) 2017\u001B[49m\u001B[39m\u001B[0m%n"), result); - } - @Test - public void testCommandLine_printVersionInfo_formatsArguments() throws Exception { - @Command(version = {"First line %1$s", "Second line %2$s", "Third line %s %s"}) class Versioned {} - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos, true, "UTF8"); - new CommandLine(new Versioned()).printVersionHelp(ps, Help.Ansi.OFF, "VALUE1", "VALUE2", "VALUE3"); - String result = baos.toString("UTF8"); - assertEquals(String.format("First line VALUE1%nSecond line VALUE2%nThird line VALUE1 VALUE2%n"), result); - } - - @Test - public void testCommandLine_printVersionInfo_withMarkupAndParameterContainingMarkup() throws Exception { - @Command(version = { - "@|yellow Versioned Command 1.0|@", - "@|blue Build 12345|@%1$s", - "@|red,bg(white) (c) 2017|@%2$s" }) - class Versioned {} - String[] args = {"@|bold VALUE1|@", "@|underline VALUE2|@", "VALUE3"}; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos, true, "UTF8"); - new CommandLine(new Versioned()).printVersionHelp(ps, Help.Ansi.ON, (Object[]) args); - String result = baos.toString("UTF8"); - assertEquals(String.format("" + - "\u001B[33mVersioned Command 1.0\u001B[39m\u001B[0m%n" + - "\u001B[34mBuild 12345\u001B[39m\u001B[0m\u001B[1mVALUE1\u001B[21m\u001B[0m%n" + - "\u001B[31m\u001B[47m(c) 2017\u001B[49m\u001B[39m\u001B[0m\u001B[4mVALUE2\u001B[24m\u001B[0m%n"), result); - } - - @Test - public void testMapFieldHelp() throws Exception { - class App { - @Parameters(arity = "2", split = "\\|", - paramLabel = "FIXTAG=VALUE", - description = "Exactly two lists of vertical bar '|'-separated FIXTAG=VALUE pairs.") - Map message; - - @Option(names = {"-P", "-map"}, split = ",", - paramLabel = "TIMEUNIT=VALUE", - description = "Any number of TIMEUNIT=VALUE pairs. These may be specified separately (-PTIMEUNIT=VALUE) or as a comma-separated list.") - Map map; - } - String actual = usageString(new App(), Help.Ansi.OFF); - String expected = String.format("" + - "Usage:
    [-P=TIMEUNIT=VALUE[,TIMEUNIT=VALUE]...]... FIXTAG=VALUE%n" + - " [\\|FIXTAG=VALUE]... FIXTAG=VALUE[\\|FIXTAG=VALUE]...%n" + - " FIXTAG=VALUE[\\|FIXTAG=VALUE]... FIXTAG=VALUE[\\|FIXTAG=VALUE]...%n" + - " Exactly two lists of vertical bar '|'-separated%n" + - " FIXTAG=VALUE pairs.%n" + - " -P, -map=TIMEUNIT=VALUE[,TIMEUNIT=VALUE]...%n" + - " Any number of TIMEUNIT=VALUE pairs. These may be%n" + - " specified separately (-PTIMEUNIT=VALUE) or as a%n" + - " comma-separated list.%n"); - assertEquals(expected, actual); - } - @Test - public void testMapFieldTypeInference() throws UnsupportedEncodingException { - class App { - @Option(names = "-a") Map a; - @Option(names = "-b") Map b; - @SuppressWarnings("unchecked") - @Option(names = "-c") Map c; - @Option(names = "-d") List d; - @Option(names = "-e") Map e; - @Option(names = "-f", type = {Long.class, Float.class}) Map f; - @SuppressWarnings("unchecked") - @Option(names = "-g", type = {TimeUnit.class, Float.class}) Map g; - } - String actual = usageString(new App(), Help.Ansi.OFF); - String expected = String.format("" + - "Usage:
    [-a=]... [-b=]...%n" + - " [-c=]... [-d=]... [-e=]...%n" + - " [-f=]... [-g=]...%n" + - " -a= %n" + - " -b= %n" + - "%n" + - " -c= %n" + - " -d= %n" + - " -e= %n" + - " -f= %n" + - " -g= %n"); - assertEquals(expected, actual); - } - @Test - public void test200NPEWithEmptyCommandName() throws UnsupportedEncodingException { - @Command(name = "") class Args {} - String actual = usageString(new Args(), Help.Ansi.OFF); - String expected = String.format("" + - "Usage: %n" + - ""); - assertEquals(expected, actual); - } -} diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineTest.java deleted file mode 100644 index 118a59f442c..00000000000 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineTest.java +++ /dev/null @@ -1,3188 +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.tools.picocli; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.PrintStream; -import java.io.UnsupportedEncodingException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.Socket; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.UnknownHostException; -import java.nio.charset.Charset; -import java.sql.Time; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.UUID; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import static java.util.concurrent.TimeUnit.*; -import static org.junit.Assert.*; -import static org.apache.logging.log4j.core.tools.picocli.CommandLine.*; - -/** - * Tests for the CommandLine argument parsing interpreter functionality. - */ -// DONE arrays -// DONE collection fields -// DONE all built-in types -// DONE private fields, public fields (TODO methods?) -// DONE arity 2, 3 -// DONE arity -1, -2, -3 -// TODO arity ignored for single-value types (non-array, non-collection) -// DONE positional arguments with '--' separator (where positional arguments look like options) -// DONE positional arguments without '--' separator (based on arity of last option?) -// DONE positional arguments based on arity of last option -// TODO ambiguous options: writing --input ARG (as opposed to --input=ARG) is ambiguous, -// meaning it is not possible to tell whether ARG is option's argument or a positional argument. -// In usage patterns this will be interpreted as an option with argument only if a description (covered below) -// for that option is provided. -// Otherwise it will be interpreted as an option and separate positional argument. -// TODO ambiguous short options: ambiguity with the -f FILE and -fFILE notation. -// In the latter case it is not possible to tell whether it is a number of stacked short options, -// or an option with an argument. These notations will be interpreted as an option with argument only if a -// description for the option is provided. -// DONE compact flags -// DONE compact flags where last option has an argument, separate by space -// DONE compact flags where last option has an argument attached to the option character -// DONE long options with argument separate by space -// DONE long options with argument separated by '=' (no spaces) -// TODO document that if arity>1 and args="-opt=val1 val2", arity overrules the "=": both values are assigned -// TODO test superclass bean and child class bean where child class field shadows super class and have same annotation Option name -// TODO test superclass bean and child class bean where child class field shadows super class and have different annotation Option name -// DONE -vrx, -vro outputFile, -vrooutputFile, -vro=outputFile, -vro:outputFile, -vro=, -vro:, -vro -// DONE --out outputFile, --out=outputFile, --out:outputFile, --out=, --out:, --out -public class CommandLineTest { - @Before public void setUp() { System.clearProperty("picocli.trace"); } - @After public void tearDown() { System.clearProperty("picocli.trace"); } - - private static void setTraceLevel(String level) { - System.setProperty("picocli.trace", level); - } - @Test - public void testVersion() { - assertEquals("2.0.3", CommandLine.VERSION); - } - - static class SupportedTypes { - @Option(names = "-boolean") boolean booleanField; - @Option(names = "-Boolean") Boolean aBooleanField; - @Option(names = "-byte") byte byteField; - @Option(names = "-Byte") Byte aByteField; - @Option(names = "-char") char charField; - @Option(names = "-Character") Character aCharacterField; - @Option(names = "-short") short shortField; - @Option(names = "-Short") Short aShortField; - @Option(names = "-int") int intField; - @Option(names = "-Integer") Integer anIntegerField; - @Option(names = "-long") long longField; - @Option(names = "-Long") Long aLongField; - @Option(names = "-float") float floatField; - @Option(names = "-Float") Float aFloatField; - @Option(names = "-double") double doubleField; - @Option(names = "-Double") Double aDoubleField; - @Option(names = "-String") String aStringField; - @Option(names = "-StringBuilder") StringBuilder aStringBuilderField; - @Option(names = "-CharSequence") CharSequence aCharSequenceField; - @Option(names = "-File") File aFileField; - @Option(names = "-URL") URL anURLField; - @Option(names = "-URI") URI anURIField; - @Option(names = "-Date") Date aDateField; - @Option(names = "-Time") Time aTimeField; - @Option(names = "-BigDecimal") BigDecimal aBigDecimalField; - @Option(names = "-BigInteger") BigInteger aBigIntegerField; - @Option(names = "-Charset") Charset aCharsetField; - @Option(names = "-InetAddress") InetAddress anInetAddressField; - @Option(names = "-Pattern") Pattern aPatternField; - @Option(names = "-UUID") UUID anUUIDField; - } - @Test - public void testDefaults() { - SupportedTypes bean = CommandLine.populateCommand(new SupportedTypes()); - assertEquals("boolean", false, bean.booleanField); - assertEquals("Boolean", null, bean.aBooleanField); - assertEquals("byte", 0, bean.byteField); - assertEquals("Byte", null, bean.aByteField); - assertEquals("char", 0, bean.charField); - assertEquals("Character", null, bean.aCharacterField); - assertEquals("short", 0, bean.shortField); - assertEquals("Short", null, bean.aShortField); - assertEquals("int", 0, bean.intField); - assertEquals("Integer", null, bean.anIntegerField); - assertEquals("long", 0, bean.longField); - assertEquals("Long", null, bean.aLongField); - assertEquals("float", 0f, bean.floatField, Float.MIN_VALUE); - assertEquals("Float", null, bean.aFloatField); - assertEquals("double", 0d, bean.doubleField, Double.MIN_VALUE); - assertEquals("Double", null, bean.aDoubleField); - assertEquals("String", null, bean.aStringField); - assertEquals("StringBuilder", null, bean.aStringBuilderField); - assertEquals("CharSequence", null, bean.aCharSequenceField); - assertEquals("File", null, bean.aFileField); - assertEquals("URL", null, bean.anURLField); - assertEquals("URI", null, bean.anURIField); - assertEquals("Date", null, bean.aDateField); - assertEquals("Time", null, bean.aTimeField); - assertEquals("BigDecimal", null, bean.aBigDecimalField); - assertEquals("BigInteger", null, bean.aBigIntegerField); - assertEquals("Charset", null, bean.aCharsetField); - assertEquals("InetAddress", null, bean.anInetAddressField); - assertEquals("Pattern", null, bean.aPatternField); - assertEquals("UUID", null, bean.anUUIDField); - } - @Test - public void testTypeConversionSucceedsForValidInput() - throws MalformedURLException, URISyntaxException, UnknownHostException, ParseException { - SupportedTypes bean = CommandLine.populateCommand(new SupportedTypes(), - "-boolean", "-Boolean", // - "-byte", "12", "-Byte", "23", // - "-char", "p", "-Character", "i", // - "-short", "34", "-Short", "45", // - "-int", "56", "-Integer", "67", // - "-long", "78", "-Long", "89", // - "-float", "1.23", "-Float", "2.34", // - "-double", "3.45", "-Double", "4.56", // - "-String", "abc", "-StringBuilder", "bcd", "-CharSequence", "xyz", // - "-File", "abc.txt", // - "-URL", "http://pico-cli.github.io", // - "-URI", "http://pico-cli.github.io/index.html", // - "-Date", "2017-01-30", // - "-Time", "23:59:59", // - "-BigDecimal", "12345678901234567890.123", // - "-BigInteger", "123456789012345678901", // - "-Charset", "UTF8", // - "-InetAddress", InetAddress.getLocalHost().getHostName(), // - "-Pattern", "a*b", // - "-UUID", "c7d51423-bf9d-45dd-a30d-5b16fafe42e2" - ); - assertEquals("boolean", true, bean.booleanField); - assertEquals("Boolean", Boolean.TRUE, bean.aBooleanField); - assertEquals("byte", 12, bean.byteField); - assertEquals("Byte", Byte.valueOf((byte) 23), bean.aByteField); - assertEquals("char", 'p', bean.charField); - assertEquals("Character", Character.valueOf('i'), bean.aCharacterField); - assertEquals("short", 34, bean.shortField); - assertEquals("Short", Short.valueOf((short) 45), bean.aShortField); - assertEquals("int", 56, bean.intField); - assertEquals("Integer", Integer.valueOf(67), bean.anIntegerField); - assertEquals("long", 78L, bean.longField); - assertEquals("Long", Long.valueOf(89L), bean.aLongField); - assertEquals("float", 1.23f, bean.floatField, Float.MIN_VALUE); - assertEquals("Float", Float.valueOf(2.34f), bean.aFloatField); - assertEquals("double", 3.45, bean.doubleField, Double.MIN_VALUE); - assertEquals("Double", Double.valueOf(4.56), bean.aDoubleField); - assertEquals("String", "abc", bean.aStringField); - assertEquals("StringBuilder type", StringBuilder.class, bean.aStringBuilderField.getClass()); - assertEquals("StringBuilder", "bcd", bean.aStringBuilderField.toString()); - assertEquals("CharSequence", "xyz", bean.aCharSequenceField); - assertEquals("File", new File("abc.txt"), bean.aFileField); - assertEquals("URL", new URL("http://pico-cli.github.io"), bean.anURLField); - assertEquals("URI", new URI("http://pico-cli.github.io/index.html"), bean.anURIField); - assertEquals("Date", new SimpleDateFormat("yyyy-MM-dd").parse("2017-01-30"), bean.aDateField); - assertEquals("Time", new Time(new SimpleDateFormat("HH:mm:ss").parse("23:59:59").getTime()), bean.aTimeField); - assertEquals("BigDecimal", new BigDecimal("12345678901234567890.123"), bean.aBigDecimalField); - assertEquals("BigInteger", new BigInteger("123456789012345678901"), bean.aBigIntegerField); - assertEquals("Charset", Charset.forName("UTF8"), bean.aCharsetField); - assertEquals("InetAddress", InetAddress.getByName(InetAddress.getLocalHost().getHostName()), bean.anInetAddressField); - assertEquals("Pattern", Pattern.compile("a*b").pattern(), bean.aPatternField.pattern()); - assertEquals("UUID", UUID.fromString("c7d51423-bf9d-45dd-a30d-5b16fafe42e2"), bean.anUUIDField); - } - @Test - public void testByteFieldsAreDecimal() { - try { - CommandLine.populateCommand(new SupportedTypes(), "-byte", "0x1F", "-Byte", "0x0F"); - fail("Should fail on hex input"); - } catch (ParameterException expected) { - assertEquals("Could not convert '0x1F' to byte for option '-byte'" + - ": java.lang.NumberFormatException: For input string: \"0x1F\"", expected.getMessage()); - } - } - @Test - public void testCustomByteConverterAcceptsHexadecimalDecimalAndOctal() { - SupportedTypes bean = new SupportedTypes(); - CommandLine commandLine = new CommandLine(bean); - ITypeConverter converter = new ITypeConverter() { - @Override - public Byte convert(String s) { - return Byte.decode(s); - } - }; - commandLine.registerConverter(Byte.class, converter); - commandLine.registerConverter(Byte.TYPE, converter); - commandLine.parse("-byte", "0x1F", "-Byte", "0x0F"); - assertEquals(0x1F, bean.byteField); - assertEquals(Byte.valueOf((byte) 0x0F), bean.aByteField); - - commandLine.parse("-byte", "010", "-Byte", "010"); - assertEquals(8, bean.byteField); - assertEquals(Byte.valueOf((byte) 8), bean.aByteField); - - commandLine.parse("-byte", "34", "-Byte", "34"); - assertEquals(34, bean.byteField); - assertEquals(Byte.valueOf((byte) 34), bean.aByteField); - } - @Test - public void testShortFieldsAreDecimal() { - try { - CommandLine.populateCommand(new SupportedTypes(), "-short", "0xFF", "-Short", "0x6FFE"); - fail("Should fail on hex input"); - } catch (ParameterException expected) { - assertEquals("Could not convert '0xFF' to short for option '-short'" + - ": java.lang.NumberFormatException: For input string: \"0xFF\"", expected.getMessage()); - } - } - @Test - public void testCustomShortConverterAcceptsHexadecimalDecimalAndOctal() { - SupportedTypes bean = new SupportedTypes(); - CommandLine commandLine = new CommandLine(bean); - ITypeConverter shortConverter = new ITypeConverter() { - @Override - public Short convert(String s) { - return Short.decode(s); - } - }; - commandLine.registerConverter(Short.class, shortConverter); - commandLine.registerConverter(Short.TYPE, shortConverter); - commandLine.parse("-short", "0xFF", "-Short", "0x6FFE"); - assertEquals(0xFF, bean.shortField); - assertEquals(Short.valueOf((short) 0x6FFE), bean.aShortField); - - commandLine.parse("-short", "010", "-Short", "010"); - assertEquals(8, bean.shortField); - assertEquals(Short.valueOf((short) 8), bean.aShortField); - - commandLine.parse("-short", "34", "-Short", "34"); - assertEquals(34, bean.shortField); - assertEquals(Short.valueOf((short) 34), bean.aShortField); - } - @Test - public void testIntFieldsAreDecimal() { - try { - CommandLine.populateCommand(new SupportedTypes(), "-int", "0xFF", "-Integer", "0xFFFF"); - fail("Should fail on hex input"); - } catch (ParameterException expected) { - assertEquals("Could not convert '0xFF' to int for option '-int'" + - ": java.lang.NumberFormatException: For input string: \"0xFF\"", expected.getMessage()); - } - } - @Test - public void testCustomIntConverterAcceptsHexadecimalDecimalAndOctal() { - SupportedTypes bean = new SupportedTypes(); - CommandLine commandLine = new CommandLine(bean); - ITypeConverter intConverter = new ITypeConverter() { - @Override - public Integer convert(String s) { - return Integer.decode(s); - } - }; - commandLine.registerConverter(Integer.class, intConverter); - commandLine.registerConverter(Integer.TYPE, intConverter); - commandLine.parse("-int", "0xFF", "-Integer", "0xFFFF"); - assertEquals(255, bean.intField); - assertEquals(Integer.valueOf(0xFFFF), bean.anIntegerField); - - commandLine.parse("-int", "010", "-Integer", "010"); - assertEquals(8, bean.intField); - assertEquals(Integer.valueOf(8), bean.anIntegerField); - - commandLine.parse("-int", "34", "-Integer", "34"); - assertEquals(34, bean.intField); - assertEquals(Integer.valueOf(34), bean.anIntegerField); - } - @Test - public void testLongFieldsAreDecimal() { - try { - CommandLine.populateCommand(new SupportedTypes(), "-long", "0xAABBCC", "-Long", "0xAABBCCDD"); - fail("Should fail on hex input"); - } catch (ParameterException expected) { - assertEquals("Could not convert '0xAABBCC' to long for option '-long'" + - ": java.lang.NumberFormatException: For input string: \"0xAABBCC\"", expected.getMessage()); - } - } - @Test - public void testCustomLongConverterAcceptsHexadecimalDecimalAndOctal() { - SupportedTypes bean = new SupportedTypes(); - CommandLine commandLine = new CommandLine(bean); - ITypeConverter longConverter = new ITypeConverter() { - @Override - public Long convert(String s) { - return Long.decode(s); - } - }; - commandLine.registerConverter(Long.class, longConverter); - commandLine.registerConverter(Long.TYPE, longConverter); - commandLine.parse("-long", "0xAABBCC", "-Long", "0xAABBCCDD"); - assertEquals(0xAABBCC, bean.longField); - assertEquals(Long.valueOf(0xAABBCCDDL), bean.aLongField); - - commandLine.parse("-long", "010", "-Long", "010"); - assertEquals(8, bean.longField); - assertEquals(Long.valueOf(8), bean.aLongField); - - commandLine.parse("-long", "34", "-Long", "34"); - assertEquals(34, bean.longField); - assertEquals(Long.valueOf(34), bean.aLongField); - } - @Test - public void testTimeFormatHHmmSupported() throws ParseException { - SupportedTypes bean = CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59"); - assertEquals("Time", new Time(new SimpleDateFormat("HH:mm").parse("23:59").getTime()), bean.aTimeField); - } - @Test - public void testTimeFormatHHmmssSupported() throws ParseException { - SupportedTypes bean = CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59:58"); - assertEquals("Time", new Time(new SimpleDateFormat("HH:mm:ss").parse("23:59:58").getTime()), bean.aTimeField); - } - @Test - public void testTimeFormatHHmmssDotSSSSupported() throws ParseException { - SupportedTypes bean = CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59:58.123"); - assertEquals("Time", new Time(new SimpleDateFormat("HH:mm:ss.SSS").parse("23:59:58.123").getTime()), bean.aTimeField); - } - @Test - public void testTimeFormatHHmmssCommaSSSSupported() throws ParseException { - SupportedTypes bean = CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59:58,123"); - assertEquals("Time", new Time(new SimpleDateFormat("HH:mm:ss,SSS").parse("23:59:58,123").getTime()), bean.aTimeField); - } - @Test - public void testTimeFormatHHmmssSSSInvalidError() throws ParseException { - try { - CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59:58;123"); - fail("Invalid format was accepted"); - } catch (ParameterException expected) { - assertEquals("'23:59:58;123' is not a HH:mm[:ss[.SSS]] time for option '-Time'", expected.getMessage()); - } - } - @Test - public void testTimeFormatHHmmssDotInvalidError() throws ParseException { - try { - CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59:58."); - fail("Invalid format was accepted"); - } catch (ParameterException expected) { - assertEquals("'23:59:58.' is not a HH:mm[:ss[.SSS]] time for option '-Time'", expected.getMessage()); - } - } - @Test - public void testTimeFormatHHmmsssInvalidError() throws ParseException { - try { - CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59:587"); - fail("Invalid format was accepted"); - } catch (ParameterException expected) { - assertEquals("'23:59:587' is not a HH:mm[:ss[.SSS]] time for option '-Time'", expected.getMessage()); - } - } - @Test - public void testTimeFormatHHmmssColonInvalidError() throws ParseException { - try { - CommandLine.populateCommand(new SupportedTypes(), "-Time", "23:59:"); - fail("Invalid format was accepted"); - } catch (ParameterException expected) { - assertEquals("'23:59:' is not a HH:mm[:ss[.SSS]] time for option '-Time'", expected.getMessage()); - } - } - @Test - public void testDateFormatYYYYmmddInvalidError() throws ParseException { - try { - CommandLine.populateCommand(new SupportedTypes(), "-Date", "20170131"); - fail("Invalid format was accepted"); - } catch (ParameterException expected) { - assertEquals("'20170131' is not a yyyy-MM-dd date for option '-Date'", expected.getMessage()); - } - } - @Test - public void testCharConverterInvalidError() throws ParseException { - try { - CommandLine.populateCommand(new SupportedTypes(), "-Character", "aa"); - fail("Invalid format was accepted"); - } catch (ParameterException expected) { - assertEquals("'aa' is not a single character for option '-Character'", expected.getMessage()); - } - try { - CommandLine.populateCommand(new SupportedTypes(), "-char", "aa"); - fail("Invalid format was accepted"); - } catch (ParameterException expected) { - assertEquals("'aa' is not a single character for option '-char'", expected.getMessage()); - } - } - @Test - public void testNumberConvertersInvalidError() { - parseInvalidValue("-Byte", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-byte", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-Short", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-short", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-Integer", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-int", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-Long", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-long", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-Float", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-float", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-Double", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-double", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - parseInvalidValue("-BigDecimal", "aa", ": java.lang.NumberFormatException"); - parseInvalidValue("-BigInteger", "aa", ": java.lang.NumberFormatException: For input string: \"aa\""); - } - @Test - public void testURLConvertersInvalidError() { - parseInvalidValue("-URL", ":::", ": java.net.MalformedURLException: no protocol: :::"); - } - @Test - public void testURIConvertersInvalidError() { - parseInvalidValue("-URI", ":::", ": java.net.URISyntaxException: Expected scheme name at index 0: :::"); - } - @Test - public void testCharsetConvertersInvalidError() { - parseInvalidValue("-Charset", "aa", ": java.nio.charset.UnsupportedCharsetException: aa"); - } - @Test - public void testInetAddressConvertersInvalidError() { - parseInvalidValue("-InetAddress", "%$::a?*!a", ": java.net.UnknownHostException: %$::a?*!a"); - } - @Test - public void testUUIDConvertersInvalidError() { - parseInvalidValue("-UUID", "aa", ": java.lang.IllegalArgumentException: Invalid UUID string: aa"); - } - @Test - public void testRegexPatternConverterInvalidError() { - parseInvalidValue("-Pattern", "[[(aa", String.format(": java.util.regex.PatternSyntaxException: Unclosed character class near index 4%n" + - "[[(aa%n" + - " ^")); - } - - private void parseInvalidValue(String option, String value, String errorMessage) { - try { - CommandLine.populateCommand(new SupportedTypes(), option, value); - fail("Invalid format " + value + " was accepted for " + option); - } catch (ParameterException actual) { - String type = option.substring(1); - String expected = "Could not convert '" + value + "' to " + type + " for option '" + option + "'" + errorMessage; - assertTrue("expected:<" + expected + "> but was:<" + actual.getMessage() + ">", - actual.getMessage().startsWith(actual.getMessage())); - } - } - - @Test - public void testCustomConverter() { - class Glob { - public final String glob; - public Glob(String glob) { this.glob = glob; } - } - class App { - @Parameters Glob globField; - } - class GlobConverter implements ITypeConverter { - @Override - public Glob convert(String value) throws Exception { return new Glob(value); } - } - CommandLine commandLine = new CommandLine(new App()); - commandLine.registerConverter(Glob.class, new GlobConverter()); - - String[] args = {"a*glob*pattern"}; - List parsed = commandLine.parse(args); - assertEquals("not empty", 1, parsed.size()); - assertTrue(parsed.get(0).getCommand() instanceof App); - App app = (App) parsed.get(0).getCommand(); - assertEquals(args[0], app.globField.glob); - } - - private static class EnumParams { - @Option(names = "-timeUnit") TimeUnit timeUnit; - @Option(names = "-timeUnitArray", arity = "2") TimeUnit[] timeUnitArray; - @Option(names = "-timeUnitList", type = TimeUnit.class, arity = "3") List timeUnitList; - } - @Test - public void testEnumTypeConversionSuceedsForValidInput() { - EnumParams params = CommandLine.populateCommand(new EnumParams(), - "-timeUnit SECONDS -timeUnitArray MILLISECONDS SECONDS -timeUnitList SECONDS MICROSECONDS NANOSECONDS".split(" ")); - assertEquals(SECONDS, params.timeUnit); - assertArrayEquals(new TimeUnit[]{MILLISECONDS, TimeUnit.SECONDS}, params.timeUnitArray); - List expected = new ArrayList(Arrays.asList(TimeUnit.SECONDS, TimeUnit.MICROSECONDS, TimeUnit.NANOSECONDS)); - assertEquals(expected, params.timeUnitList); - } - @Test - public void testEnumTypeConversionFailsForInvalidInput() { - try { - CommandLine.populateCommand(new EnumParams(), "-timeUnit", "xyz"); - fail("Accepted invalid timeunit"); - } catch (Exception ex) { - String prefix = "Could not convert 'xyz' to TimeUnit for option '-timeUnit'" + - ": java.lang.IllegalArgumentException: No enum cons"; - String suffix = " java.util.concurrent.TimeUnit.xyz"; - assertEquals(prefix, ex.getMessage().substring(0, prefix.length())); - assertEquals(suffix, ex.getMessage().substring(ex.getMessage().length() - suffix.length(), ex.getMessage().length())); - } - } - @Ignore("Requires #14 case-insensitive enum parsing") - @Test - public void testEnumTypeConversionIsCaseInsensitive() { - EnumParams params = CommandLine.populateCommand(new EnumParams(), - "-timeUnit sEcONds -timeUnitArray milliSeconds miCroSeConds -timeUnitList SEConds MiCROsEconds nanoSEConds".split(" ")); - assertEquals(SECONDS, params.timeUnit); - assertArrayEquals(new TimeUnit[]{MILLISECONDS, TimeUnit.MICROSECONDS}, params.timeUnitArray); - List expected = new ArrayList(Arrays.asList(TimeUnit.SECONDS, TimeUnit.MICROSECONDS, TimeUnit.NANOSECONDS)); - assertEquals(expected, params.timeUnitList); - } - @Test - public void testEnumArrayTypeConversionFailsForInvalidInput() { - try { - CommandLine.populateCommand(new EnumParams(), "-timeUnitArray", "a", "b"); - fail("Accepted invalid timeunit"); - } catch (Exception ex) { - String prefix = "Could not convert 'a' to TimeUnit for option '-timeUnitArray' at index 0 ()" + - ": java.lang.IllegalArgumentException: No enum const"; - String suffix = " java.util.concurrent.TimeUnit.a"; - assertEquals(prefix, ex.getMessage().substring(0, prefix.length())); - assertEquals(suffix, ex.getMessage().substring(ex.getMessage().length() - suffix.length(), ex.getMessage().length())); - } - } - @Test - public void testEnumListTypeConversionFailsForInvalidInput() { - try { - CommandLine.populateCommand(new EnumParams(), "-timeUnitList", "SECONDS", "b", "c"); - fail("Accepted invalid timeunit"); - } catch (Exception ex) { - String prefix = "Could not convert 'b' to TimeUnit for option '-timeUnitList' at index 1 ()" + - ": java.lang.IllegalArgumentException: No enum const"; - String suffix = " java.util.concurrent.TimeUnit.b"; - assertEquals(prefix, ex.getMessage().substring(0, prefix.length())); - assertEquals(suffix, ex.getMessage().substring(ex.getMessage().length() - suffix.length(), ex.getMessage().length())); - } - } - - @Test - public void testArrayOptionParametersAreAlwaysInstantiated() { - EnumParams params = new EnumParams(); - TimeUnit[] array = params.timeUnitArray; - new CommandLine(params).parse("-timeUnitArray", "SECONDS", "MILLISECONDS"); - assertNotSame(array, params.timeUnitArray); - } - @Test - public void testListOptionParametersAreInstantiatedIfNull() { - EnumParams params = new EnumParams(); - assertNull(params.timeUnitList); - new CommandLine(params).parse("-timeUnitList", "SECONDS", "MICROSECONDS", "MILLISECONDS"); - assertEquals(Arrays.asList(SECONDS, MICROSECONDS, MILLISECONDS), params.timeUnitList); - } - @Test - public void testListOptionParametersAreReusedInstantiatedIfNonNull() { - EnumParams params = new EnumParams(); - List list = new ArrayList(); - params.timeUnitList = list; - new CommandLine(params).parse("-timeUnitList", "SECONDS", "MICROSECONDS", "SECONDS"); - assertEquals(Arrays.asList(SECONDS, MICROSECONDS, SECONDS), params.timeUnitList); - assertSame(list, params.timeUnitList); - } - @Test - public void testArrayPositionalParametersAreAppendedNotReplaced() { - class ArrayPositionalParams { - @Parameters() int[] array; - } - ArrayPositionalParams params = new ArrayPositionalParams(); - params.array = new int[3]; - int[] array = params.array; - new CommandLine(params).parse("3", "2", "1"); - assertNotSame(array, params.array); - assertArrayEquals(new int[]{0, 0, 0, 3, 2, 1}, params.array); - } - private class ListPositionalParams { - @Parameters(type = Integer.class) List list; - } - @Test - public void testListPositionalParametersAreInstantiatedIfNull() { - ListPositionalParams params = new ListPositionalParams(); - assertNull(params.list); - new CommandLine(params).parse("3", "2", "1"); - assertNotNull(params.list); - assertEquals(Arrays.asList(3, 2, 1), params.list); - } - @Test - public void testListPositionalParametersAreReusedIfNonNull() { - ListPositionalParams params = new ListPositionalParams(); - params.list = new ArrayList(); - List list = params.list; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.list); - assertEquals(Arrays.asList(3, 2, 1), params.list); - } - @Test - public void testListPositionalParametersAreAppendedToIfNonNull() { - ListPositionalParams params = new ListPositionalParams(); - params.list = new ArrayList(); - params.list.add(234); - List list = params.list; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.list); - assertEquals(Arrays.asList(234, 3, 2, 1), params.list); - } - class SortedSetPositionalParams { - @Parameters(type = Integer.class) SortedSet sortedSet; - } - @Test - public void testSortedSetPositionalParametersAreInstantiatedIfNull() { - SortedSetPositionalParams params = new SortedSetPositionalParams(); - assertNull(params.sortedSet); - new CommandLine(params).parse("3", "2", "1"); - assertNotNull(params.sortedSet); - assertEquals(Arrays.asList(1, 2, 3), new ArrayList(params.sortedSet)); - } - @Test - public void testSortedSetPositionalParametersAreReusedIfNonNull() { - SortedSetPositionalParams params = new SortedSetPositionalParams(); - params.sortedSet = new TreeSet(); - SortedSet list = params.sortedSet; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.sortedSet); - assertEquals(Arrays.asList(1, 2, 3), new ArrayList(params.sortedSet)); - } - @Test - public void testSortedSetPositionalParametersAreAppendedToIfNonNull() { - SortedSetPositionalParams params = new SortedSetPositionalParams(); - params.sortedSet = new TreeSet(); - params.sortedSet.add(234); - SortedSet list = params.sortedSet; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.sortedSet); - assertEquals(Arrays.asList(1, 2, 3, 234), new ArrayList(params.sortedSet)); - } - class SetPositionalParams { - @Parameters(type = Integer.class) Set set; - } - @Test - public void testSetPositionalParametersAreInstantiatedIfNull() { - SetPositionalParams params = new SetPositionalParams(); - assertNull(params.set); - new CommandLine(params).parse("3", "2", "1"); - assertNotNull(params.set); - assertEquals(new HashSet(Arrays.asList(1, 2, 3)), params.set); - } - @Test - public void testSetPositionalParametersAreReusedIfNonNull() { - SetPositionalParams params = new SetPositionalParams(); - params.set = new TreeSet(); - Set list = params.set; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.set); - assertEquals(new HashSet(Arrays.asList(1, 2, 3)), params.set); - } - @Test - public void testSetPositionalParametersAreAppendedToIfNonNull() { - SetPositionalParams params = new SetPositionalParams(); - params.set = new TreeSet(); - params.set.add(234); - Set list = params.set; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.set); - assertEquals(new HashSet(Arrays.asList(1, 2, 3, 234)), params.set); - } - class QueuePositionalParams { - @Parameters(type = Integer.class) Queue queue; - } - @Test - public void testQueuePositionalParametersAreInstantiatedIfNull() { - QueuePositionalParams params = new QueuePositionalParams(); - assertNull(params.queue); - new CommandLine(params).parse("3", "2", "1"); - assertNotNull(params.queue); - assertEquals(new LinkedList(Arrays.asList(3, 2, 1)), params.queue); - } - @Test - public void testQueuePositionalParametersAreReusedIfNonNull() { - QueuePositionalParams params = new QueuePositionalParams(); - params.queue = new LinkedList(); - Queue list = params.queue; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.queue); - assertEquals(new LinkedList(Arrays.asList(3, 2, 1)), params.queue); - } - @Test - public void testQueuePositionalParametersAreAppendedToIfNonNull() { - QueuePositionalParams params = new QueuePositionalParams(); - params.queue = new LinkedList(); - params.queue.add(234); - Queue list = params.queue; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.queue); - assertEquals(new LinkedList(Arrays.asList(234, 3, 2, 1)), params.queue); - } - class CollectionPositionalParams { - @Parameters(type = Integer.class) Collection collection; - } - @Test - public void testCollectionPositionalParametersAreInstantiatedIfNull() { - CollectionPositionalParams params = new CollectionPositionalParams(); - assertNull(params.collection); - new CommandLine(params).parse("3", "2", "1"); - assertNotNull(params.collection); - assertEquals(Arrays.asList(3, 2, 1), params.collection); - } - @Test - public void testCollectionPositionalParametersAreReusedIfNonNull() { - CollectionPositionalParams params = new CollectionPositionalParams(); - params.collection = new ArrayList(); - Collection list = params.collection; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.collection); - assertEquals(Arrays.asList(3, 2, 1), params.collection); - } - @Test - public void testCollectionPositionalParametersAreAppendedToIfNonNull() { - CollectionPositionalParams params = new CollectionPositionalParams(); - params.collection = new ArrayList(); - params.collection.add(234); - Collection list = params.collection; - new CommandLine(params).parse("3", "2", "1"); - assertSame(list, params.collection); - assertEquals(Arrays.asList(234, 3, 2, 1), params.collection); - } - - @Test(expected = DuplicateOptionAnnotationsException.class) - public void testDuplicateOptionsAreRejected() { - /** Duplicate parameter names are invalid. */ - class DuplicateOptions { - @Option(names = "-duplicate") public int value1; - @Option(names = "-duplicate") public int value2; - } - new CommandLine(new DuplicateOptions()); - } - - @Test(expected = DuplicateOptionAnnotationsException.class) - public void testClashingAnnotationsAreRejected() { - class ClashingAnnotation { - @Option(names = "-o") - @Parameters - public String[] bothOptionAndParameters; - } - new CommandLine(new ClashingAnnotation()); - } - - private static class PrivateFinalOptionFields { - @Option(names = "-f") private final String field = null; - @Option(names = "-p") private final int primitive = 43; - } - @Test - public void testCanInitializePrivateFinalFields() { - PrivateFinalOptionFields ff = CommandLine.populateCommand(new PrivateFinalOptionFields(), "-f", "reference value"); - assertEquals("reference value", ff.field); - } - @Ignore("Needs Reject final primitive fields annotated with @Option or @Parameters #68") - @Test - public void testCanInitializeFinalPrimitiveFields() { - PrivateFinalOptionFields ff = CommandLine.populateCommand(new PrivateFinalOptionFields(), "-p", "12"); - assertEquals("primitive value", 12, ff.primitive); - } - @Test - public void testLastValueSelectedIfOptionSpecifiedMultipleTimes() { - setTraceLevel("OFF"); - CommandLine cmd = new CommandLine(new PrivateFinalOptionFields()).setOverwrittenOptionsAllowed(true); - cmd.parse("-f", "111", "-f", "222"); - PrivateFinalOptionFields ff = (PrivateFinalOptionFields) cmd.getCommand(); - assertEquals("222", ff.field); - } - - private static class PrivateFinalParameterFields { - @Parameters(index = "0") private final String field = null; - @Parameters(index = "1", arity = "0..1") private final int primitive = 43; - } - @Test - public void testCanInitializePrivateFinalParameterFields() { - PrivateFinalParameterFields ff = CommandLine.populateCommand(new PrivateFinalParameterFields(), "ref value"); - assertEquals("ref value", ff.field); - } - @Ignore("Needs Reject final primitive fields annotated with @Option or @Parameters #68") - @Test - public void testCannotInitializePrivateFinalPrimitiveParameterFields() { - PrivateFinalParameterFields ff = CommandLine.populateCommand(new PrivateFinalParameterFields(), "ref value", "12"); - assertEquals("ref value", ff.field); - assertEquals("primitive value", 12, ff.primitive); - } - - private static class RequiredField { - @Option(names = {"-?", "/?"}, help = true) boolean isHelpRequested; - @Option(names = {"-V", "--version"}, versionHelp= true) boolean versionHelp; - @Option(names = {"-h", "--help"}, usageHelp = true) boolean usageHelp; - @Option(names = "--required", required = true) private String required; - @Parameters private String[] remainder; - } - @Test - public void testErrorIfRequiredOptionNotSpecified() { - try { - CommandLine.populateCommand(new RequiredField(), "arg1", "arg2"); - fail("Missing required field should have thrown exception"); - } catch (MissingParameterException ex) { - assertEquals("Missing required option '--required='", ex.getMessage()); - } - } - @Test - public void testNoErrorIfRequiredOptionSpecified() { - CommandLine.populateCommand(new RequiredField(), "--required", "arg1", "arg2"); - } - @Test - public void testNoErrorIfRequiredOptionNotSpecifiedWhenHelpRequested() { - RequiredField requiredField = CommandLine.populateCommand(new RequiredField(), "-?"); - assertTrue("help requested", requiredField.isHelpRequested); - } - @Test - public void testNoErrorIfRequiredOptionNotSpecifiedWhenUsageHelpRequested() { - RequiredField requiredField = CommandLine.populateCommand(new RequiredField(), "--help"); - assertTrue("usage help requested", requiredField.usageHelp); - } - @Test - public void testNoErrorIfRequiredOptionNotSpecifiedWhenVersionHelpRequested() { - RequiredField requiredField = CommandLine.populateCommand(new RequiredField(), "--version"); - assertTrue("version info requested", requiredField.versionHelp); - } - @Test - public void testCommandLine_isUsageHelpRequested_trueWhenSpecified() { - List parsedCommands = new CommandLine(new RequiredField()).parse("--help"); - assertTrue("usage help requested", parsedCommands.get(0).isUsageHelpRequested()); - } - @Test - public void testCommandLine_isVersionHelpRequested_trueWhenSpecified() { - List parsedCommands = new CommandLine(new RequiredField()).parse("--version"); - assertTrue("version info requested", parsedCommands.get(0).isVersionHelpRequested()); - } - @Test - public void testCommandLine_isUsageHelpRequested_falseWhenNotSpecified() { - List parsedCommands = new CommandLine(new RequiredField()).parse("--version"); - assertFalse("usage help requested", parsedCommands.get(0).isUsageHelpRequested()); - } - @Test - public void testCommandLine_isVersionHelpRequested_falseWhenNotSpecified() { - List parsedCommands = new CommandLine(new RequiredField()).parse("--help"); - assertFalse("version info requested", parsedCommands.get(0).isVersionHelpRequested()); - } - @Test - public void testHelpRequestedFlagResetWhenParsing_staticMethod() { - RequiredField requiredField = CommandLine.populateCommand(new RequiredField(), "-?"); - assertTrue("help requested", requiredField.isHelpRequested); - - requiredField.isHelpRequested = false; - - // should throw error again on second pass (no help was requested here...) - try { - CommandLine.populateCommand(requiredField, "arg1", "arg2"); - fail("Missing required field should have thrown exception"); - } catch (MissingParameterException ex) { - assertEquals("Missing required option '--required='", ex.getMessage()); - } - } - @Test - public void testHelpRequestedFlagResetWhenParsing_instanceMethod() { - RequiredField requiredField = new RequiredField(); - CommandLine commandLine = new CommandLine(requiredField); - commandLine.parse("-?"); - assertTrue("help requested", requiredField.isHelpRequested); - - requiredField.isHelpRequested = false; - - // should throw error again on second pass (no help was requested here...) - try { - commandLine.parse("arg1", "arg2"); - fail("Missing required field should have thrown exception"); - } catch (MissingParameterException ex) { - assertEquals("Missing required option '--required='", ex.getMessage()); - } - } - - private class CompactFields { - @Option(names = "-v") boolean verbose; - @Option(names = "-r") boolean recursive; - @Option(names = "-o") File outputFile; - @Parameters File[] inputFiles; - } - @Test - public void testCompactFieldsAnyOrder() { - //cmd -a -o arg path path - //cmd -o arg -a path path - //cmd -a -o arg -- path path - //cmd -a -oarg path path - //cmd -aoarg path path - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-rvoout"); - verifyCompact(compact, true, true, "out", null); - - // change order within compact group - compact = CommandLine.populateCommand(new CompactFields(), "-vroout"); - verifyCompact(compact, true, true, "out", null); - - // compact group with separator - compact = CommandLine.populateCommand(new CompactFields(), "-vro=out"); - verifyCompact(compact, true, true, "out", null); - - compact = CommandLine.populateCommand(new CompactFields(), "-rv p1 p2".split(" ")); - verifyCompact(compact, true, true, null, fileArray("p1", "p2")); - - compact = CommandLine.populateCommand(new CompactFields(), "-voout p1 p2".split(" ")); - verifyCompact(compact, true, false, "out", fileArray("p1", "p2")); - - compact = CommandLine.populateCommand(new CompactFields(), "-voout -r p1 p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - - compact = CommandLine.populateCommand(new CompactFields(), "-r -v -oout p1 p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - - compact = CommandLine.populateCommand(new CompactFields(), "-rv -o out p1 p2".split(" ")); //#233 - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - - compact = CommandLine.populateCommand(new CompactFields(), "-oout -r -v p1 p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - - compact = CommandLine.populateCommand(new CompactFields(), "-rvo out p1 p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - - try { - CommandLine.populateCommand(new CompactFields(), "-oout -r -vp1 p2".split(" ")); - fail("should fail: -v does not take an argument"); - } catch (UnmatchedArgumentException ex) { - assertEquals("Unmatched argument [-p1]", ex.getMessage()); - } - } - - @Test - public void testCompactFieldsWithUnmatchedArguments() { - setTraceLevel("OFF"); - CommandLine cmd = new CommandLine(new CompactFields()).setUnmatchedArgumentsAllowed(true); - cmd.parse("-oout -r -vp1 p2".split(" ")); - assertEquals(Arrays.asList("-p1"), cmd.getUnmatchedArguments()); - } - - @Test - public void testCompactWithOptionParamSeparatePlusParameters() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-r -v -o out p1 p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - } - - @Test - public void testCompactWithOptionParamAttachedEqualsSeparatorChar() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-rvo=out p1 p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - } - - @Test - public void testCompactWithOptionParamAttachedColonSeparatorChar() { - CompactFields compact = new CompactFields(); - CommandLine cmd = new CommandLine(compact); - cmd.setSeparator(":"); - cmd.parse("-rvo:out p1 p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - } - - /** See {@link #testGnuLongOptionsWithVariousSeparators()} */ - @Test - public void testDefaultSeparatorIsEquals() { - assertEquals("=", new CommandLine(new CompactFields()).getSeparator()); - } - - @Test - public void testOptionsMixedWithParameters() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-r -v p1 -o out p2".split(" ")); - verifyCompact(compact, true, true, "out", fileArray("p1", "p2")); - } - @Test - public void testShortOptionsWithSeparatorButNoValueAssignsEmptyStringEvenIfNotLast() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-ro= -v".split(" ")); - verifyCompact(compact, false, true, "-v", null); - } - @Test - public void testShortOptionsWithColonSeparatorButNoValueAssignsEmptyStringEvenIfNotLast() { - CompactFields compact = new CompactFields(); - CommandLine cmd = new CommandLine(compact); - cmd.setSeparator(":"); - cmd.parse("-ro: -v".split(" ")); - verifyCompact(compact, false, true, "-v", null); - } - @Test - public void testShortOptionsWithSeparatorButNoValueFailsIfValueRequired() { - try { - CommandLine.populateCommand(new CompactFields(), "-rvo=".split(" ")); - fail("Expected exception"); - } catch (ParameterException ex) { - assertEquals("Missing required parameter for option '-o' ()", ex.getMessage()); - } - } - @Test - public void testShortOptionsWithSeparatorButNoValueAssignsQuotedEmptyStringEvenIfNotLast() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-ro=\"\" -v".split(" ")); - verifyCompact(compact, true, true, "", null); - } - @Test - public void testShortOptionsWithColonSeparatorButNoValueAssignsQuotedEmptyStringEvenIfNotLast() { - CompactFields compact = new CompactFields(); - CommandLine cmd = new CommandLine(compact); - cmd.setSeparator(":"); - cmd.parse("-ro:\"\" -v".split(" ")); - verifyCompact(compact, true, true, "", null); - } - @Test - public void testShortOptionsWithSeparatorButNoValueAssignsEmptyQuotedStringIfLast() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-rvo=\"\"".split(" ")); - verifyCompact(compact, true, true, "", null); - } - - @Test - public void testDoubleDashSeparatesPositionalParameters() { - CompactFields compact = CommandLine.populateCommand(new CompactFields(), "-oout -- -r -v p1 p2".split(" ")); - verifyCompact(compact, false, false, "out", fileArray("-r", "-v", "p1", "p2")); - } - - @Test - public void testDebugOutputForDoubleDashSeparatesPositionalParameters() throws UnsupportedEncodingException { - PrintStream originalErr = System.err; - ByteArrayOutputStream baos = new ByteArrayOutputStream(2500); - System.setErr(new PrintStream(baos)); - final String PROPERTY = "picocli.trace"; - String old = System.getProperty(PROPERTY); - System.setProperty(PROPERTY, "DEBUG"); - CommandLine.populateCommand(new CompactFields(), "-oout -- -r -v p1 p2".split(" ")); - System.setErr(originalErr); - if (old == null) { - System.clearProperty(PROPERTY); - } else { - System.setProperty(PROPERTY, old); - } - String expected = String.format("" + - "[picocli INFO] Parsing 6 command line args [-oout, --, -r, -v, p1, p2]%n" + - "[picocli DEBUG] Initializing %1$s$CompactFields: 3 options, 1 positional parameters, 0 required, 0 subcommands.%n" + - "[picocli DEBUG] Processing argument '-oout'. Remainder=[--, -r, -v, p1, p2]%n" + - "[picocli DEBUG] '-oout' cannot be separated into
    Log4j 2 global configuration properties
    Property NameProperty Name
    (Legacy Property Name)
    Environment VariableLegacy Property Name Default Value Description
    log4j2.configurationFilelog4j2.configurationFile +
    + (
    log4j.configurationFile) +
    LOG4J_CONFIGURATION_FILElog4j.configurationFile   Path to an Log4j 2 configuration file. May also contain a comma separated list of configuration file names.
    log4j2.debuglog4j2.debug +
    + (
    log4j2.debug) +
    LOG4J_DEBUGlog4j2.debug   Log4j2 will print all internal logging to the console if system property @@ -1663,9 +1666,11 @@ public class AwesomeTest {
    log4j2.mergeFactorylog4j2.mergeFactory +
    + (
    log4j.mergeFactory) +
    LOG4J_MERGE_FACTORYlog4j.mergeFactory   The name of the class that implements the MergeStrategy interface. If not specified @@ -1673,9 +1678,11 @@ public class AwesomeTest {
    log4j2.contextSelectorlog4j2.contextSelector +
    + (
    Log4jContextSelector) +
    LOG4J_CONTEXT_SELECTORLog4jContextSelector ClassLoaderContextSelector Creates the LoggerContexts. An application can have one or more active LoggerContexts depending @@ -1691,9 +1698,11 @@ public class AwesomeTest {
    log4j2.logEventFactorylog4j2.logEventFactory +
    + (
    Log4jLogEventFactory) +
    LOG4J_LOG_EVENT_FACTORYLog4jLogEventFactory org.apache.logging.log4j.core.impl .DefaultLogEventFactory @@ -1702,9 +1711,11 @@ public class AwesomeTest {
    log4j2.loggerContextFactorylog4j2.loggerContextFactory +
    + (
    log4j2.loggerContextFactory) +
    LOG4J_LOGGER_CONTEXT_FACTORYlog4j2.loggerContextFactory org.apache.logging.log4j.simple .SimpleLoggerContextFactory @@ -1714,9 +1725,11 @@ public class AwesomeTest {
    log4j2.configurationFactorylog4j2.configurationFactory +
    + (
    log4j.configurationFactory) +
    LOG4J_CONFIGURATION_FACTORYlog4j.configurationFactory   Fully specified class name of a class extending org.apache.logging.log4j.core @@ -1725,9 +1738,11 @@ public class AwesomeTest {
    log4j2.shutdownHookEnabledlog4j2.shutdownHookEnabled +
    + (
    log4j.shutdownHookEnabled) +
    LOG4J_SHUTDOWN_HOOK_ENABLEDlog4j.shutdownHookEnabled true Overrides the global flag for whether or not a shutdown hook should be used to stop a LoggerContext. @@ -1736,9 +1751,11 @@ public class AwesomeTest {
    log4j2.shutdownCallbackRegistrylog4j2.shutdownCallbackRegistry +
    + (
    log4j.shutdownCallbackRegistry) +
    LOG4J_SHUTDOWN_CALLBACK_REGISTRYlog4j.shutdownCallbackRegistry org.apache.logging.log4j.core.util .DefaultShutdownCallbackRegistry @@ -1749,12 +1766,14 @@ public class AwesomeTest {
    log4j2.clocklog4j2.clock +
    + (
    log4j.Clock) +
    LOG4J_CLOCKlog4j.Clock SystemClock - Implementation of the org.apache.logging.log4j.core.time.Clock + Implementation of the org.apache.logging.log4j .core.time.Clock interface that is used for timestamping the log events.
    By default, System.currentTimeMillis is called on every log event. @@ -1764,9 +1783,11 @@ public class AwesomeTest {
    log4j2.levellog4j2.level +
    + (
    org.apache.logging.log4j.level) +
    LOG4J_LEVELorg.apache.logging.log4j.level ERROR Log level of the default configuration. The default configuration is used if the ConfigurationFactory @@ -1774,9 +1795,11 @@ public class AwesomeTest {
    log4j2.disableThreadContextlog4j2.disableThreadContext +
    + (disableThreadContext) +
    LOG4J_DISABLE_THREAD_CONTEXTdisableThreadContext false If true, the ThreadContext stack and map are disabled. @@ -1784,18 +1807,22 @@ public class AwesomeTest {
    log4j2.disableThreadContextStacklog4j2.disableThreadContextStack +
    + (disableThreadContextStack) +
    LOG4J_DISABLE_THREAD_CONTEXT_STACKdisableThreadContextStack false If true, the ThreadContext stack is disabled.
    log4j2.disableThreadContextMaplog4j2.disableThreadContextMap +
    + (disableThreadContextMap) +
    LOG4J_DISABLE_THREAD_CONTEXT_MAPdisableThreadContextMap false If true, the ThreadContext map is disabled. @@ -1803,18 +1830,22 @@ public class AwesomeTest {
    log4j2.threadContextMaplog4j2.threadContextMap +
    + (log4j2.threadContextMap) +
    LOG4J_THREAD_CONTEXT_MAPlog4j2.threadContextMap   Fully specified class name of a custom ThreadContextMap implementation class.
    log4j2.isThreadContextMapInheritablelog4j2.isThreadContextMapInheritable +
    + (isThreadContextMapInheritable) +
    LOG4J_IS_THREAD_CONTEXT_MAP_INHERITABLEisThreadContextMapInheritable false If true use a InheritableThreadLocal to implement the ThreadContext map. @@ -1823,27 +1854,33 @@ public class AwesomeTest {
    log4j2.contextDataInjectorlog4j2.contextDataInjector +
    + (
    log4j2.ContextDataInjector) +
    LOG4J_CONTEXT_DATA_INJECTORlog4j2.ContextDataInjector   Fully specified class name of a custom ContextDataInjector implementation class.
    log4j2.garbagefreeThreadContextMaplog4j2.garbagefreeThreadContextMap +
    + (
    log4j2.garbagefree.threadContextMap) +
    LOG4J_GARBAGEFREE_THREAD_CONTEXT_MAPlog4j2.garbagefree.threadContextMap false Specify "true" to make the ThreadContext map garbage-free.
    log4j2.disableJmxlog4j2.disableJmx +
    + (
    log4j2.disable.jmx) +
    LOG4J_DISABLE_JMXlog4j2.disable.jmx false If true, Log4j configuration objects like LoggerContexts, Appenders, Loggers, etc. @@ -1851,9 +1888,11 @@ public class AwesomeTest {
    log4j2.jmxNotifyAsynclog4j2.jmxNotifyAsync +
    + (
    log4j2.jmx.notify.async) +
    LOG4J_JMX_NOTIFY_ASYNClog4j2.jmx.notify.async false for web apps, true otherwise If true, log4j's JMX notifications are sent from a separate background thread, @@ -1864,18 +1903,22 @@ public class AwesomeTest {
    log4j2.skipJansilog4j2.skipJansi +
    + (
    log4j.skipJansi) +
    LOG4J_SKIP_JANSIlog4j.skipJansi true If true, the ConsoleAppender will not try to use the Jansi output stream on Windows.
    log4j2.ignoreTCLlog4j2.ignoreTCL +
    + (
    log4j.ignoreTCL) +
    LOG4J_IGNORE_TCLlog4j.ignoreTCL false If true, classes are only loaded with the default class loader. @@ -1884,9 +1927,11 @@ public class AwesomeTest {
    log4j2.uuidSequencelog4j2.uuidSequence +
    + (
    org.apache.logging.log4j.uuidSequence) +
    LOG4J_UUID_SEQUENCEorg.apache.logging.log4j.uuidSequence 0 System property that may be used to seed the UUID generation with an integer value. @@ -1904,55 +1949,67 @@ public class AwesomeTest {
    log4j2.simplelogShowContextMaplog4j2.simplelogShowContextMap +
    + + (
    org.apache.logging.log4j .simplelog.showContextMap) +
    LOG4J_SIMPLELOG_SHOW_CONTEXT_MAPorg.apache.logging.log4j.simplelog .showContextMap false If true, the full ThreadContext map is included in each SimpleLogger log message.
    log4j2.simplelogShowlognamelog4j2.simplelogShowlogname +
    + + (
    org.apache.logging.log4j .simplelog.showlogname) +
    LOG4J_SIMPLELOG_SHOWLOGNAMEorg.apache.logging.log4j.simplelog .showlogname false If true, the logger name is included in each SimpleLogger log message.
    log4j2.simplelogShowShortLognamelog4j2.simplelogShowShortLogname +
    + + (
    org.apache.logging.log4j .simplelog.showShortLogname) +
    LOG4J_SIMPLELOG_SHOW_SHORT_LOGNAMEorg.apache.logging.log4j.simplelog .showShortLogname true If true, only the last component of a logger name is included in SimpleLogger log messages. (E.g., if the logger name is "mycompany.myproject.mycomponent", only "mycomponent" is logged.
    log4j2.simplelogShowdatetimelog4j2.simplelogShowdatetime +
    + + (
    org.apache.logging.log4j .simplelog.showdatetime) +
    LOG4J_SIMPLELOG_SHOWDATETIMEorg.apache.logging.log4j.simplelog .showdatetime false If true, SimpleLogger log messages contain timestamp information.
    log4j2.simplelogDateTimeFormatlog4j2.simplelogDateTimeFormat +
    + + (
    org.apache.logging.log4j .simplelog.dateTimeFormat) +
    LOG4J_SIMPLELOG_DATE_TIME_FORMATorg.apache.logging.log4j.simplelog .dateTimeFormat "yyyy/MM/dd HH:mm:ss:SSS zzz" Date-time format to use. - Ignored if org.apache.logging.log4j.simplelog.showdatetime is false. + Ignored if org.apache.logging.log4j .simplelog.showdatetime is false.
    log4j2.simplelogLogFilelog4j2.simplelogLogFile +
    + + (
    org.apache.logging.log4j .simplelog.logFile) +
    LOG4J_SIMPLELOG_LOG_FILEorg.apache.logging.log4j.simplelog .logFile system.err "system.err" (case-insensitive) logs to System.err, "system.out" (case-insensitive) logs to System.out, @@ -1960,38 +2017,46 @@ public class AwesomeTest {
    log4j2.simplelogLevellog4j2.simplelogLevel +
    + + (
    org.apache.logging.log4j .simplelog.level) +
    LOG4J_SIMPLELOG_LEVELorg.apache.logging.log4j.simplelog .level ERROR Default level for new SimpleLogger instances.
    log4j2.simplelog.<loggerName>.levellog4j2.simplelog.<loggerName>.level +
    + + (org.apache.logging.log4j .simplelog.<loggerName>.level) +
    LOG4J_SIMPLELOG_<LOGGER_NAME>_LEVELorg.apache.logging.log4j.simplelog.<loggerName>.level SimpleLogger default log level Log level for a the SimpleLogger instance with the specified name.
    log4j2.simplelogStatusLoggerLevellog4j2.simplelogStatusLoggerLevel +
    + + (
    org.apache.logging.log4j.simplelog .StatusLogger.level) +
    LOG4J_SIMPLELOG_STATUS_LOGGER_LEVELorg.apache.logging.log4j.simplelog .StatusLogger.level ERROR This property is used to control the initial StatusLogger level, and can be overridden in code by calling - StatusLogger.getLogger().setLevel(someLevel). + StatusLogger.getLogger() .setLevel(someLevel). Note that the StatusLogger level is only used to determine the status log output level until a listener is registered. In practice, a listener is registered when a configuration is found, and from that point onwards, status messages are only sent to the listeners (depending on their statusLevel).
    log4j2.defaultStatusLevellog4j2.defaultStatusLevel +
    + (
    Log4jDefaultStatusLevel) +
    LOG4J_DEFAULT_STATUS_LEVELLog4jDefaultStatusLevel ERROR

    The StatusLogger logs events that occur in the logging system to the console. @@ -2005,9 +2070,11 @@ public class AwesomeTest {

    log4j2.statusLoggerLevellog4j2.statusLoggerLevel +
    + (
    log4j2.StatusLogger.level) +
    LOG4J_STATUS_LOGGER_LEVELlog4j2.StatusLogger.level WARN

    The initial "listenersLevel" of the StatusLogger. If StatusLogger listeners are added, the "listenerLevel" @@ -2025,9 +2092,11 @@ public class AwesomeTest {

    log4j2.statusEntrieslog4j2.statusEntries +
    + (
    log4j2.status.entries) +
    LOG4J_STATUS_ENTRIESlog4j2.status.entries 200 Number of StatusLogger events that are kept in a buffer and can be retrieved with @@ -2035,37 +2104,45 @@ public class AwesomeTest {
    log4j2.statusLoggerDateformatlog4j2.statusLoggerDateformat +
    + (
    log4j2.StatusLogger.dateformat) +
    LOG4J_STATUS_LOGGER_DATEFORMATlog4j2.StatusLogger.dateformat"yyyy/MM/dd HH:mm:ss:SSS zzz"  Date-time format string to use as the format for timestamps in the status logger output. See java.text.SimpleDateFormat for supported formats.
    log4j2.asyncLoggerExceptionHandlerlog4j2.asyncLoggerExceptionHandler +
    + (
    AsyncLogger.ExceptionHandler) +
    LOG4J_ASYNC_LOGGER_EXCEPTION_HANDLERAsyncLogger.ExceptionHandler default handler See Async Logger System Properties for details.
    log4j2.asyncLoggerRingBufferSizelog4j2.asyncLoggerRingBufferSize +
    + (
    AsyncLogger.RingBufferSize) +
    LOG4J_ASYNC_LOGGER_RING_BUFFER_SIZEAsyncLogger.RingBufferSize 256 * 1024 See Async Logger System Properties for details.
    log4j2.asyncLoggerWaitStrategylog4j2.asyncLoggerWaitStrategy +
    + (
    AsyncLogger.WaitStrategy) +
    LOG4J_ASYNC_LOGGER_WAIT_STRATEGYAsyncLogger.WaitStrategy Timeout
    log4j2.asyncLoggerThreadNameStrategylog4j2.asyncLoggerThreadNameStrategy +
    + (
    AsyncLogger.ThreadNameStrategy) +
    LOG4J_ASYNC_LOGGER_THREAD_NAME_STRATEGYAsyncLogger.ThreadNameStrategy CACHED
    log4j2.asyncLoggerConfigExceptionHandlerlog4j2.asyncLoggerConfigExceptionHandler +
    + (
    AsyncLoggerConfig.ExceptionHandler) +
    LOG4J_ASYNC_LOGGER_CONFIG_EXCEPTION_HANDLERAsyncLoggerConfig.ExceptionHandler default handler See Mixed Async/Synchronous Logger System Properties for details.
    log4j2.asyncLoggerConfigRingBufferSizelog4j2.asyncLoggerConfigRingBufferSize +
    + (
    AsyncLoggerConfig.RingBufferSize) +
    LOG4J_ASYNC_LOGGER_CONFIG_RING_BUFFER_SIZEAsyncLoggerConfig.RingBufferSize 256 * 1024 See Mixed Async/Synchronous Logger System Properties for details.
    log4j2.asyncLoggerConfigWaitStrategylog4j2.asyncLoggerConfigWaitStrategy +
    + (
    AsyncLoggerConfig.WaitStrategy) +
    LOG4J_ASYNC_LOGGER_CONFIG_WAIT_STRATEGYAsyncLoggerConfig.WaitStrategy Timeout
    log4j2.julLoggerAdapterlog4j2.julLoggerAdapter +
    + (
    log4j.jul.LoggerAdapter) +
    LOG4J_JUL_LOGGER_ADAPTERlog4j.jul.LoggerAdapter org.apache.logging.log4j.jul .ApiLoggerAdapterorg.apache.logging.log4j .jul.ApiLoggerAdapter Default LoggerAdapter to use in the JUL adapter. By default, if log4j-core is available, then the class org.apache.logging.log4j.jul .CoreLoggerAdapter will be used. Otherwise, the @@ -2126,9 +2213,11 @@ public class AwesomeTest {
    log4j2.formatMsgAsynclog4j2.formatMsgAsync +
    + (
    log4j.format.msg.async) +
    LOG4J_FORMAT_MSG_ASYNClog4j.format.msg.async false
    log4j2.asyncQueueFullPolicylog4j2.asyncQueueFullPolicy +
    + (
    log4j2.AsyncQueueFullPolicy) +
    LOG4J_ASYNC_QUEUE_FULL_POLICYlog4j2.AsyncQueueFullPolicy  

    Used by Async Loggers and the AsyncAppender to maintain application throughput even when @@ -2152,9 +2243,11 @@ public class AwesomeTest {

    log4j2.discardThresholdlog4j2.discardThreshold +
    + (
    log4j2.DiscardThreshold) +
    LOG4J_DISCARD_THRESHOLDlog4j2.DiscardThreshold INFO Used by the DiscardingAsyncQueueFullPolicy to determine which events to drop when the queue becomes full. By default, INFO, DEBUG and TRACE level @@ -2163,32 +2256,40 @@ public class AwesomeTest { log4j2.AsyncQueueFullPolicy.
    log4j2.messageFactorylog4j2.messageFactory +
    + (
    log4j2.messageFactory) +
    LOG4J_MESSAGE_FACTORYlog4j2.messageFactory org.apache.logging.log4j.message. ParameterizedMessageFactory or org.apache.logging.log4j.message. ReusableMessageFactory in garbage-free mode Default message factory used by Loggers if no factory was specified.
    log4j2.flowMessageFactorylog4j2.flowMessageFactory +
    + (
    log4j2.flowMessageFactory) +
    LOG4J_FLOW_MESSAGE_FACTORYlog4j2.flowMessageFactory org.apache.logging.log4j.message. DefaultFlowMessageFactory Default flow message factory used by Loggers.
    log4j2.isWebapplog4j2.isWebapp +
    + (
    log4j2.is.webapp) +
    LOG4J_IS_WEBAPPlog4j2.is.webapp true if Servlet class on class path This system property can be used to force Log4j 2 to behave as if it is part of a web application (when true) or as if it is not part of a web application (when false).
    log4j2.enableThreadlocalslog4j2.enableThreadlocals +
    + (
    log4j2.enable.threadlocals) +
    LOG4J_ENABLE_THREADLOCALSlog4j2.enable.threadlocals true This system property can be used to switch off the use of threadlocals, which will partly disable Log4j's garbage-free behaviour: to be fully garbage-free, Log4j stores @@ -2196,9 +2297,11 @@ public class AwesomeTest { Note that this property is not effective when Log4j detects it is running in a web application.
    log4j2.enableDirectEncoderslog4j2.enableDirectEncoders +
    + (
    log4j2.enable.direct.encoders) +
    LOG4J_ENABLE_DIRECT_ENCODERSlog4j2.enable.direct.encoders true This property can be used to force garbage-aware Layouts and Appenders to revert to the pre-2.6 behaviour where converting log events to text generates temporary objects like @@ -2207,33 +2310,41 @@ public class AwesomeTest { to text will convert this text to bytes without creating temporary objects.
    log4j2.initialReusableMsgSizelog4j2.initialReusableMsgSize +
    + (
    log4j.initialReusableMsgSize) +
    LOG4J_INITIAL_REUSABLE_MSG_SIZElog4j.initialReusableMsgSize 128 In GC-free mode, this property determines the initial size of the reusable StringBuilders where the message text is formatted and potentially passed to background threads.
    log4j2.maxReusableMsgSizelog4j2.maxReusableMsgSize +
    + (
    log4j.maxReusableMsgSize) +
    LOG4J_MAX_REUSABLE_MSG_SIZElog4j.maxReusableMsgSize 518 In GC-free mode, this property determines the maximum size of the reusable StringBuilders where the message text is formatted and potentially passed to background threads.
    log4j2.layoutStringBuilderMaxSizelog4j2.layoutStringBuilderMaxSize +
    + (
    log4j.layoutStringBuilder.maxSize) +
    LOG4J_LAYOUT_STRING_BUILDER_MAX_SIZElog4j.layoutStringBuilder.maxSize 2048 This property determines the maximum size of the thread-local reusable StringBuilders used to format the log event to text by Layouts that extend AbstractStringLayout.
    log4j2.unboxRingbufferSizelog4j2.unboxRingbufferSize +
    + (
    log4j.unbox.ringbuffer.size) +
    LOG4J_UNBOX_RINGBUFFER_SIZElog4j.unbox.ringbuffer.size 32 The org.apache.logging.log4j.util.Unbox utility manages a small thread-local ring buffer of StringBuilders. @@ -2245,17 +2356,21 @@ public class AwesomeTest { Note that the specified number will be rounded up to the nearest power of 2.

    log4j2.loggerContextStacktraceOnStartlog4j2.loggerContextStacktraceOnStart +
    + (
    log4j.LoggerContext.stacktrace.on.start) +
    LOG4J_LOGGER_CONTEXT_STACKTRACE_ON_STARTlog4j.LoggerContext.stacktrace.on.start false Prints a stacktrace to the status logger at DEBUG level when the LoggerContext is started. For debug purposes.
    log4j2.formatMsgNoLookupslog4j2.formatMsgNoLookups +
    + (
    log4j2.formatMsgNoLookups) +
    FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPSlog4j2.formatMsgNoLookups false Disables message pattern lookups globally when set to true. This is equivalent to defining all message patterns using %m{nolookups}.
    log4j2.statusLoggerDateformat
    - (
    log4j2.StatusLogger.dateformat) + (log4j2.StatusLogger.DateFormat)
    LOG4J_STATUS_LOGGER_DATEFORMAT  
    - + endOfBatch Outputs the EndOfBatch status of the logging event, as "true" or "false".
    - - - - - - -
    ExampleDiscussion
    String unitAbbrev = "μs";Best: perfectly clear even without a comment.
    String unitAbbrev = "\u03bcs"; // "μs"Allowed, but there's no reason to do this.
    String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"Allowed, but awkward and prone to mistakes.
    String unitAbbrev = "\u03bcs";Poor: the reader has no idea what this is.
    return '\ufeff' + content; // byte order markGood: use escapes for non-printable characters, and comment if necessary.
    -

    Tip: Never make your code less readable simply out of fear that - some programs might not handle non-ASCII characters properly. If that should happen, those - programs are broken and they must be fixed.

    -
    - - - -

    A source file consists of, in order:

    -
      -
    1. Apache license
    2. -
    3. Package statement
    4. -
    5. Import statements
    6. -
    7. Exactly one top-level class
    8. -
    -

    Exactly one blank line separates each section that is present.

    -
    -

    Apache License

    -

    The Apache license belongs here. No other license should appear. Other licenses that apply should be referenced in - a NOTICE file

    -
    -

    Package statement

    -

    The package statement is not line-wrapped. The column limit - (Column limit: 120) does not apply to package statements.

    - - -

    Import statements

    -
    -

    No wildcard imports in the main tree

    -

    Wildcard imports, static or otherwise, are not used.

    -

    Static wildcard imports in the test tree

    -

    Wildcard static imports are encouraged for test imports like JUnit, EasyMock, and Hamcrest.

    -
    -

    No line-wrapping

    -

    Import statements are not line-wrapped. The column limit - (Column limit: 120) does not apply to import statements.

    - -

    Ordering and spacing

    -

    Import statements are divided into the following groups, in this order, with each group - separated by a single blank line:

    -
      -
    1. java
    2. -
    3. javax
    4. -
    5. org
    6. -
    7. com
    8. -
    9. All static imports in a single group
    10. -
    -

    Within a group there are no blank lines, and the imported names appear in ASCII sort - order. (Note: this is not the same as the import statements being in - ASCII sort order; the presence of semicolons warps the result.)

    -

    IDE settings for ordering imports automatically can be found in the source distributions under - src/ide. For example:

    -
      -
    • Eclipse: src/ide/eclipse/4.3.2/organize-imports.importorder
    • -
    • IntelliJ: src/ide/Intellij/13/IntellijSettings.jar
    • -
    -
    -

    Class declaration

    -
    - -

    Exactly one top-level class declaration

    -

    Each top-level class resides in a source file of its own.

    -
    -

    Class member ordering

    -

    Class members should be grouped in the following order>.

    -
      -
    1. static variables grouped in the order shown below. Within a group variables may appear in any order.
    2. -
    3. -
        -
      1. public
      2. -
      3. protected
      4. -
      5. package
      6. -
      7. private
      8. -
      -
    4. -
    5. instance variables grouped in the order shown below. Within a group variables may appear in any order
    6. -
    7. -
        -
      1. public
      2. -
      3. protected
      4. -
      5. package
      6. -
      7. private
      8. -
      -
    8. -
    9. constructors
    10. -
    11. methods may be specified in the following order but may appear in another order if it improves the - clarity of the program.
    12. -
    13. -
        -
      1. public
      2. -
      3. protected
      4. -
      5. package
      6. -
      7. private
      8. -
      -
    14. -
    -
    - -
    Overloads: never split
    -

    When a class has multiple constructors, or multiple methods with the same name, these appear - sequentially, with no intervening members.

    - -
    - -

    Terminology Note: block-like construct refers to - the body of a class, method or constructor. Note that, by - array initializers, any array initializer - may optionally be treated as if it were a block-like construct.

    - -

    Braces

    -
    -

    Braces are used where optional

    -

    Braces are used with - if, - else, - for, - do and - while statements, even when the - body is empty or contains only a single statement.

    -
    -

    Nonempty blocks: K & R style

    -

    Braces follow the Kernighan and Ritchie style - ("Egyptian brackets") - for nonempty blocks and block-like constructs:

    • No line break before the opening brace.
    • Line break after the opening brace.
    • Line break before the closing brace.
    • Line break after the closing brace if that brace terminates a statement or the body - of a method, constructor or named class. For example, there is no line break - after the brace if it is followed by else or a - comma.

    Example:

    -
    -      return new MyClass() {
    -          @Override public void method() {
    -              if (condition()) {
    -                  try {
    -                      something();
    -                  } catch (ProblemException e) {
    -                      recover();
    -                  }
    -              }
    -          }
    -      };
    -    

    A few exceptions for enum classes are given in Section 4.8.1, - Enum classes.

    - - -

    Empty blocks: may be concise

    -

    An empty block or block-like construct may be closed immediately after it is - opened, with no characters or line break in between - ({}), unless it is part of a - multi-block statement (one that directly contains multiple blocks: - if/else-if/else or - try/catch/finally).

    -

    Example:

    -      void doNothing() {}
    -    
    -

    Block indentation: +4 spaces

    -

    Each time a new block or block-like construct is opened, the indent increases by four - spaces. When the block ends, the indent returns to the previous indent level. The indent level - applies to both code and comments throughout the block. (See the example in Section 4.1.2, - Nonempty blocks: K & R Style.)

    - -

    One statement per line

    -

    Each statement is followed by a line-break.

    -
    - -

    Column limit: 120

    -

    - The column limit for Log4j is 120 characters. - - Except as noted below, any line that would exceed this limit must be line-wrapped, as explained in - Line-wrapping. -

    Exceptions:

    -
      -
    1. Lines where obeying the column limit is not possible (for example, a long URL in Javadoc, - or a long JSNI method reference).
    2. -
    3. package and import statements (see Package statement and - Import statements).
    4. -
    5. Command lines in a comment that may be cut-and-pasted into a shell.
    6. -
    -

    Line-wrapping

    -

    Terminology Note: When code that might otherwise legally - occupy a single line is divided into multiple lines, typically to avoid overflowing the column - limit, this activity is called - line-wrapping.

    -

    There is no comprehensive, deterministic formula showing exactly how to line-wrap in - every situation. Very often there are several valid ways to line-wrap the same piece of code.

    -

    Tip: Extracting a method or local variable may solve the problem - without the need to line-wrap.

    -
    -

    Where to break

    -

    The prime directive of line-wrapping is: prefer to break at a - higher syntactic level. Also:

    -
      -
    1. When a line is broken at a non-assignment operator the break comes before - the symbol. (Note that this is not the same practice used in Google style for other languages, - such as C++ and JavaScript.) -
        -
      • This also applies to the following "operator-like" symbols: the dot separator - (.), the ampersand in type bounds - (<T extends Foo & Bar>), and the pipe in - catch blocks - (catch (FooException | BarException e)).
      • -
      -
    2. -
    3. When a line is broken at an assignment operator the break typically comes - after the symbol, but either way is acceptable. -
        -
      • This also applies to the "assignment-operator-like" colon in an enhanced - for ("foreach") statement.
      • -
      -
    4. -
    5. A method or constructor name stays attached to the open parenthesis - (() that follows it.
    6. -
    7. A comma (,) stays attached to the token that - precedes it.
    8. -
    -
    - -

    Indent continuation lines at least +8 spaces

    -

    When line-wrapping, each line after the first (each continuation line) is indented - at least +8 from the original line.

    -

    When there are multiple continuation lines, indentation may be varied beyond +8 as - desired. In general, two continuation lines use the same indentation level if and only if they - begin with syntactically parallel elements.

    -

    The section on Horizontal alignment addresses - the discouraged practice of using a variable number of spaces to align certain tokens with - previous lines.

    - -

    Whitespace

    -
    -

    Vertical Whitespace

    -

    A single blank line appears:

    -
      -
    1. Between consecutive members (or initializers) of a class: fields, constructors, - methods, nested classes, static initializers, instance initializers. -
        -
      • Exception: A blank line between two consecutive - fields (having no other code between them) is optional. Such blank lines are used as needed to - create logical groupings of fields.
      • -
      -
    2. -
    3. Within method bodies, as needed to create logical groupings of statements.
    4. Optionally before the first member or after the last member of the class (neither - encouraged nor discouraged).
    5. -
    6. As required by other sections of this document (such as - Import statements).
    7. -
    -

    Multiple consecutive blank lines are permitted, but never required (or encouraged).

    - -

    Horizontal whitespace

    -

    Beyond where required by the language or other style rules, and apart from literals, comments and - Javadoc, a single ASCII space also appears in the following places only.

    -
      -
    1. Separating any reserved word, such as - if, - for or - catch, from an open parenthesis - (() - that follows it on that line
    2. -
    3. Separating any reserved word, such as - else or - catch, from a closing curly brace - (}) that precedes it on that line
    4. -
    5. Before any open curly brace - ({), with two exceptions: -
        -
      • String[][] x = {{"foo"}}; (no space is required - between {{, by item 8 below)
      • -
      -
    6. -
    7. On both sides of any binary or ternary operator. This also applies to the following - "operator-like" symbols: -
        -
      • the ampersand in a conjunctive type bound: - <T extends Foo & Bar>
      • -
      • the pipe for a catch block that handles multiple exceptions: - catch (FooException | BarException e)
      • -
      • the colon (:) in an enhanced - for ("foreach") statement
      • -
      -
    8. -
    9. After ,:; or the closing parenthesis - ()) of a cast
    10. -
    11. On both sides of the double slash (//) that - begins an end-of-line comment. Here, multiple spaces are allowed, but not required.
    12. -
    13. Between the type and variable of a declaration: - List<String> list
    14. -
    15. Optional just inside both braces of an array initializer -
        -
      • new int[] {5, 6} and - new int[] { 5, 6 } are both valid
      • -
      -
    16. -
    -

    Note: This rule never requires or forbids additional space at the - start or end of a line, only interior space.

    -
    -

    Horizontal alignment: never required

    -

    Terminology Note: Horizontal alignment is the - practice of adding a variable number of additional spaces in your code with the goal of making - certain tokens appear directly below certain other tokens on previous lines.

    -

    This practice is permitted, but is never required by Google Style. It is not - even required to maintain horizontal alignment in places where it was already used.

    -

    Here is an example without alignment, then using alignment:

    -
    -      private int x; // this is fine
    -      private Color color; // this too
    -
    -      private int   x;      // permitted, but future edits
    -      private Color color;  // may leave it unaligned
    -    
    -

    Tip: Alignment can aid readability, but it creates problems for - future maintenance. Consider a future change that needs to touch just one line. This change may - leave the formerly-pleasing formatting mangled, and that is allowed. More often - it prompts the coder (perhaps you) to adjust whitespace on nearby lines as well, possibly - triggering a cascading series of reformattings. That one-line change now has a "blast radius." - This can at worst result in pointless busywork, but at best it still corrupts version history - information, slows down reviewers and exacerbates merge conflicts.

    -
    - -

    Grouping parentheses: recommended

    -

    Optional grouping parentheses are omitted only when author and reviewer agree that there is no - reasonable chance the code will be misinterpreted without them, nor would they have made the code - easier to read. It is not reasonable to assume that every reader has the entire Java - operator precedence table memorized.

    -
    -

    Specific constructs

    -
    -

    Enum classes

    -

    After each comma that follows an enum constant, a line-break is optional.

    An enum class with no methods - and no documentation on its constants may optionally be formatted - as if it were an array initializer (see - array initializers).

    -      private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
    -    
    -

    Since enum classes are classes, all other rules for formatting classes apply.

    - - -

    Variable declarations

    -
    -
    One variable per declaration
    -

    Every variable declaration (field or local) declares only one variable: declarations such as - int a, b; are not used.

    -
    -
    Declared when needed, initialized as soon as possible
    -

    Local variables are not habitually declared at the start of their containing - block or block-like construct. Instead, local variables are declared close to the point they are - first used (within reason), to minimize their scope. Local variable declarations typically have - initializers, or are initialized immediately after declaration.

    -

    Arrays

    -
    -
    Array initializers: can be "block-like"
    -

    Any array initializer may optionally be formatted as if it were a "block-like - construct." For example, the following are all valid (not an exhaustive - list):

    -      new int[] {           new int[] {
    -        0, 1, 2, 3            0,
    -      }                       1,
    -                              2,
    -      new int[] {             3,
    -        0, 1,               }
    -        2, 3
    -      }                     new int[]
    -                                {0, 1, 2, 3}
    -    
    -
    No C-style array declarations
    -

    The square brackets form a part of the type, not the variable: - String[] args, not - String args[].

    -
    -

    Switch statements

    -

    Terminology Note: Inside the braces of a - switch block are one or more statement groups. Each statement group consists of - one or more switch labels (either case FOO: or - default:), followed by one or more statements.

    -
    -
    Indentation
    -

    As with any other block, the contents of a switch block are indented +2.

    -

    After a switch label, a newline appears, and the indentation level is increased +2, exactly as - if a block were being opened. The following switch label returns to the previous indentation - level, as if a block had been closed.

    -
    - -
    Fall-through: commented
    -

    Within a switch block, each statement group either terminates abruptly (with a - break, - continue, - return or thrown exception), or is marked with a comment - to indicate that execution will or might continue into the next statement group. Any - comment that communicates the idea of fall-through is sufficient (typically - // fall through). This special comment is not required in - the last statement group of the switch block. Example:

    -      switch (input) {
    -        case 1:
    -        case 2:
    -          prepareOneOrTwo();
    -          // fall through
    -        case 3:
    -          handleOneTwoOrThree();
    -          break;
    -      default:
    -          handleLargeNumber(input);
    -      }
    -    
    -
    The default case is present
    -

    Each switch statement includes a default statement - group, even if it contains no code.

    -
    -

    Annotations

    -

    Annotations applying to a class, method or constructor appear immediately after the - documentation block, and each annotation is listed on a line of its own (that is, one annotation - per line). These line breaks do not constitute line-wrapping (Section - 4.5, Line-wrapping), so the indentation level is not - increased. Example:

    -      @Override
    -      @Nullable
    -      public String getNameIfPresent() { ... }
    -    

    Exception: A single parameterless annotation - may instead appear together with the first line of the signature, for example:

    -      @Override public int hashCode() { ... }
    -    

    Annotations applying to a field also appear immediately after the documentation block, but in - this case, multiple annotations (possibly parameterized) may be listed on the same line; - for example:

    -      @Partial @Mock DataLoader loader;
    -    

    There are no specific rules for formatting parameter and local variable annotations.

    - -

    Comments

    -
    -
    Block comment style
    -

    Block comments are indented at the same level as the surrounding code. They may be in - /* ... */ style or - // ... style. For multi-line - /* ... */ comments, subsequent lines must start with - * aligned with the * on the previous line.

    -      /*
    -       * This is          // And so           /* Or you can
    -       * okay.            // is this.          * even do this. */
    -       */
    -    
    -

    Comments are not enclosed in boxes drawn with asterisks or other characters.

    -

    Tip: When writing multi-line comments, use the - /* ... */ style if you want automatic code formatters to - re-wrap the lines when necessary (paragraph-style). Most formatters don't re-wrap lines in - // ... style comment blocks.

    -
    -

    Modifiers

    -

    Class and member modifiers, when present, appear in the order - recommended by the Java Language Specification: -

    -      public protected private abstract static final transient volatile synchronized native strictfp
    -    
    -
    -

    Numeric Literals

    -

    long-valued integer literals use an uppercase L suffix, never - lowercase (to avoid confusion with the digit 1). For example, 3000000000L - rather than 3000000000l.

    - -
    - - -

    Rules common to all identifiers

    -

    Identifiers use only ASCII letters and digits, and in two cases noted below, underscores. Thus - each valid identifier name is matched by the regular expression \w+ .

    -

    In Google Style special prefixes or - suffixes, like those seen in the examples name_, - mName, s_name and - kName, are not used.

    -
    -

    Rules by identifier type

    -
    -

    Package names

    -

    Package names are all lowercase, with consecutive words simply concatenated together (no - underscores). For example, com.example.deepspace, not - com.example.deepSpace or - com.example.deep_space.

    -
    -

    Class names

    -

    Class names are written in UpperCamelCase.

    -

    Class names are typically nouns or noun phrases. For example, - Character or - ImmutableList. Interface names may also be nouns or - noun phrases (for example, List), but may sometimes be - adjectives or adjective phrases instead (for example, - Readable).

    There are no specific rules or even well-established conventions for naming annotation types.

    Test classes are named starting with the name of the class they are testing, and ending - with Test. For example, - HashTest or - HashIntegrationTest.

    - -

    Method names

    -

    Method names are written in lowerCamelCase.

    -

    Method names are typically verbs or verb phrases. For example, - sendMessage or - stop.

    Underscores may appear in JUnit test method names to separate logical components of the - name. One typical pattern is test<MethodUnderTest>_<state>, - for example testPop_emptyStack. There is no One Correct - Way to name test methods.

    - - -

    Constant names

    -

    Constant names use CONSTANT_CASE: all uppercase - letters, with words separated by underscores. But what is a constant, exactly?

    -

    Every constant is a static final field, but not all static final fields are constants. Before - choosing constant case, consider whether the field really feels like a constant. For - example, if any of that instance's observable state can change, it is almost certainly not a - constant. Merely intending to never mutate the object is generally not - enough. Examples:

    -      // Constants
    -      static final int NUMBER = 5;
    -      static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
    -      static final Joiner COMMA_JOINER = Joiner.on(',');  // because Joiner is immutable
    -      static final SomeMutableType[] EMPTY_ARRAY = {};
    -      enum SomeEnum { ENUM_CONSTANT }
    -
    -      // Not constants
    -      static String nonFinal = "non-final";
    -      final String nonStatic = "non-static";
    -      static final Set<String> mutableCollection = new HashSet<String>();
    -      static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);
    -      static final Logger logger = Logger.getLogger(MyClass.getName());
    -      static final String[] nonEmptyArray = {"these", "can", "change"};
    -    
    -

    These names are typically nouns or noun phrases.

    -
    -

    Non-constant field names

    -

    Non-constant field names (static or otherwise) are written - in lowerCamelCase.

    -

    These names are typically nouns or noun phrases. For example, - computedValues or - index.

    - -

    Parameter names

    -

    Parameter names are written in lowerCamelCase.

    -

    One-character parameter names should be avoided.

    - -

    Local variable names

    -

    Local variable names are written in lowerCamelCase, and can be - abbreviated more liberally than other types of names.

    However, one-character names should be avoided, except for temporary and looping variables.

    Even when final and immutable, local variables are not considered to be constants, and should not - be styled as constants.

    - -

    Type variable names

    -

    Each type variable is named in one of two styles:

    - - -

    Camel case: defined

    -

    Sometimes there is more than one reasonable way to convert an English phrase into camel case, - such as when acronyms or unusual constructs like "IPv6" or "iOS" are present. To improve - predictability, Google Style specifies the following (nearly) deterministic scheme.

    -

    Beginning with the prose form of the name:

    -
      -
    1. Convert the phrase to plain ASCII and remove any apostrophes. For example, "Müller's - algorithm" might become "Muellers algorithm".
    2. -
    3. Divide this result into words, splitting on spaces and any remaining punctuation (typically - hyphens). - -
        -
      • Recommended: if any word already has a conventional camel-case appearance in common - usage, split this into its constituent parts (e.g., "AdWords" becomes "ad words"). Note - that a word such as "iOS" is not really in camel case per se; it defies any - convention, so this recommendation does not apply.
      • -
      -
    4. -
    5. Now lowercase everything (including acronyms), then uppercase only the first - character of: -
      • ... each word, to yield upper camel case, or
      • -
      • ... each word except the first, to yield lower camel case
      • -
      -
    6. -
    7. Finally, join all the words into a single identifier.
    8. -
    -

    Note that the casing of the original words is almost entirely disregarded. Examples:

    - - - - - - - -
    Prose formCorrectIncorrect
    "XML HTTP request"XmlHttpRequestXMLHTTPRequest
    "new customer ID"newCustomerIdnewCustomerID
    "inner stopwatch"innerStopwatchinnerStopWatch
    "supports IPv6 on iOS?"supportsIpv6OnIossupportsIPv6OnIOS
    "YouTube importer"YouTubeImporter
    YoutubeImporter*
    -

    *Acceptable, but not recommended.

    -

    Note: Some words are ambiguously hyphenated in the English - language: for example "nonempty" and "non-empty" are both correct, so the method names - checkNonempty and - checkNonEmpty are likewise both correct.

    - - -
    - -

    @Override: always used

    -

    A method is marked with the @Override annotation - whenever it is legal. This includes a class method overriding a superclass method, a class method - implementing an interface method, and an interface method respecifying a superinterface - method.

    -

    Exception:@Override may be omitted when the parent method is - @Deprecated.

    -
    - -

    Caught exceptions: not ignored

    -

    Except as noted below, it is very rarely correct to do nothing in response to a caught - exception. (Typical responses are to log it, or if it is considered "impossible", rethrow it as an - AssertionError.)

    -

    When it truly is appropriate to take no action whatsoever in a catch block, the reason this is - justified is explained in a comment.

    -      try {
    -          int i = Integer.parseInt(response);
    -          return handleNumericResponse(i);
    -      } catch (NumberFormatException ok) {
    -          // it's not numeric; that's fine, just continue
    -      }
    -      return handleTextResponse(response);
    -    

    Exception: In tests, a caught exception may be ignored - without comment if it is named expected. The - following is a very common idiom for ensuring that the method under test does throw an - exception of the expected type, so a comment is unnecessary here.

    -      try {
    -          emptyStack.pop();
    -          fail();
    -      } catch (NoSuchElementException expected) {
    -      }
    -    
    -

    Static members: qualified using class

    -

    When a reference to a static class member must be qualified, it is qualified with that class's - name, not with a reference or expression of that class's type.

    -      Foo aFoo = ...;
    -      Foo.aStaticMethod(); // good
    -      aFoo.aStaticMethod(); // bad
    -      somethingThatYieldsAFoo().aStaticMethod(); // very bad
    -    
    -
    -

    Finalizers: not used

    -

    It is extremely rare to override Object.finalize.

    -

    Tip: Don't do it. If you absolutely must, first read and understand - Effective Java - Item 7, "Avoid Finalizers," very carefully, and then don't do it.

    - - - - -

    Formatting

    -
    -

    General form

    -

    The basic formatting of Javadoc blocks is as seen in this example:

    -      /**
    -       * Multiple lines of Javadoc text are written here,
    -       * wrapped normally...
    -       */
    -      public int method(String p1) { ... }
    -    

    ... or in this single-line example:

    -      /** An especially short bit of Javadoc. */
    -    

    The basic form is always acceptable. The single-line form may be substituted when there are no - at-clauses present, and the entirety of the Javadoc block (including comment markers) can fit on a - single line.

    -
    -

    Paragraphs

    -

    One blank line—that is, a line containing only the aligned leading asterisk - (*)—appears between paragraphs, and before the group of "at-clauses" if - present. Each paragraph but the first has <p> immediately before the first word, - with no space after.

    -
    -

    At-clauses

    -

    Any of the standard "at-clauses" that are used appear in the order @param, - @return, @throws, @deprecated, and these four types never - appear with an empty description. When an at-clause doesn't fit on a single line, continuation lines - are indented four (or more) spaces from the position of the @. -

    -
    -

    The summary fragment

    -

    The Javadoc for each class and member begins with a brief summary fragment. This - fragment is very important: it is the only part of the text that appears in certain contexts such as - class and method indexes.

    This is a fragment—a noun phrase or verb phrase, not a complete sentence. It does - not begin with A {@code Foo} is a..., or - This method returns..., nor does it form a complete imperative sentence - like Save the record.. However, the fragment is capitalized and - punctuated as if it were a complete sentence.

    Tip: A common mistake is to write simple Javadoc in the form - /** @return the customer ID */. This is incorrect, and should be - changed to /** Returns the customer ID. */.

    -
    - -

    Where Javadoc is used

    -

    At the minimum, Javadoc is present for every - public class, and every - public or - protected member of such a class, with a few exceptions - noted below.

    Other classes and members still have Javadoc as needed. Whenever an implementation - comment would be used to define the overall purpose or behavior of a class, method or field, that - comment is written as Javadoc instead. (It's more uniform, and more tool-friendly.)

    -
    -

    Exception: self-explanatory methods

    -

    Javadoc is optional for "simple, obvious" methods like - getFoo, in cases where there really and truly is - nothing else worthwhile to say but "Returns the foo".

    -

    Important: it is not appropriate to cite this exception to justify - omitting relevant information that a typical reader might need to know. For example, for a method - named getCanonicalName, don't omit its documentation - (with the rationale that it would say only - /** Returns the canonical name. */) if a typical reader may have no idea - what the term "canonical name" means!

    -
    -

    Exception: overrides

    -

    Javadoc is not always present on a method that overrides a supertype method. -

    - - - - \ No newline at end of file From ea311fe638fa89a21255e00625642eea262a6f76 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 14:50:58 -0500 Subject: [PATCH 0113/2347] LOG4J2-1802: Convert guidelines page to asciidoc --- src/site/asciidoc/guidelines.adoc | 392 ++++++++++++++++++++++++++++++ src/site/xdoc/guidelines.xml | 361 --------------------------- 2 files changed, 392 insertions(+), 361 deletions(-) create mode 100644 src/site/asciidoc/guidelines.adoc delete mode 100644 src/site/xdoc/guidelines.xml diff --git a/src/site/asciidoc/guidelines.adoc b/src/site/asciidoc/guidelines.adoc new file mode 100644 index 00000000000..8f4dc7258f2 --- /dev/null +++ b/src/site/asciidoc/guidelines.adoc @@ -0,0 +1,392 @@ +//// + 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 + + https://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. +//// += Apache Log4j Project Guidelines + +This document defines the guidelines for the +https://logging.apache.org/log4j/2.x[Apache Log4j Project]. It includes +definitions of how conflict is resolved by voting, who is able to vote, +the procedures to follow for proposing and making changes as well as +guidelines for changing code. + +The objective here is to avoid unnecessary conflict over changes and +continue to produce a quality system in a timely manner. Not all +conflict can be avoided, but at least we can agree on the procedures for +conflict to be resolved. + +[#people-places-and-things] +== People, Places, and Things + +Apache Logging Project Management Committee:: +The group of volunteers who are responsible for managing the Apache +Logging Projects, including Log4j. This includes deciding what is +distributed as products of the Apache Logging Project, maintaining the +Project's shared resources, speaking on behalf of the Project, +resolving license disputes regarding Apache products, nominating new +PMC members or committers, and establishing these guidelines. ++ +Membership in the Apache Logging PMC is by invitation only and must be +approved by consensus of the active Logging PMC members. A PMC member is +considered inactive by their own declaration or by not contributing in +any form to the project for over six months. An inactive member can +become active again by reversing whichever condition made them inactive +( _i.e._ , by reversing their earlier declaration or by once again +contributing toward the project's work). Membership can be revoked by a +unanimous vote of all the active PMC members other than the member in +question. + +Apache Logging Committers:: +The group of volunteers who are responsible for the technical aspects +of the Apache Logging Projects. This group has write access to the +appropriate source repositories and these volunteers may cast binding +votes on any technical discussion. Although a committer usually joins +due to their activity on one of the Logging projects, they will have +commit access to all Logging projects. ++ +Membership as a Committer is by invitation only and must be approved by +consensus of the active Logging PMC members. A Committer is considered +inactive by their own declaration or by not contributing in any form to +the project for over six months. An inactive member can become active +again by reversing whichever condition made them inactive ( _i.e._ , by +reversing their earlier declaration or by once again contributing toward +the project's work). Membership can be revoked by a unanimous vote of +all the active PMC members (except the member in question if they are a +PMC member). + +Log4j Developers:: +All of the volunteers who are contributing time, code, documentation, +or resources to the Log4j Project. A developer that makes sustained, +welcome contributions to the project for over six months is usually +invited to become a Committer, though the exact timing of such +invitations depends on many factors. + +mailing list:: +The Log4j developers' primary mailing list for discussion of issues +and changes related to the project ( _dev@logging.apache.org_ ). +Subscription to the list is open, but only subscribers can post +directly to the list. + +private list:: +The Logging PMC's private mailing list for discussion of issues that +are inappropriate for public discussion, such as legal, personal, or +security issues prior to a published fix. Subscription to the list is +only open (actually: mandatory) to Apache Logging's Project Management +Committee. + +Git:: +All of the Apache products are maintained in information repositories +using either Subversion or Git; Log4j uses +link:source-repository.html[Git]. Only some of the Apache developers +have write access to the Apache Logging repositories; everyone has +https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=summary[read +access]. + +[#issues] +== Issue Management + +The Log4j project uses the +https://issues.apache.org/JIRA/browse/LOG4J2[JIRA] bug tracking system +hosted and maintained by the Apache Software Foundation for tracking +bugs and enhancements. The project roadmap may be maintained in JIRA +through its RoadMap feature and through the use of Story or Epic issues. + +Many issues will be encountered by the project, each resulting in zero +or more proposed action items. Issues should be raised on the mailing +list as soon as they are identified. Action items *must* be raised on +the mailing list and added to JIRA using the appropriate issue type. All +action items may be voted on, but not all of them will require a formal +vote. + +[#voting] +== Voting + +Any of the Log4j Developers may vote on any issue or action item. +However, the only binding votes are those cast by active members of the +Apache Logging PMC; if the vote is about a change to source code or +documentation, the primary author of what is being changed may also cast +a binding vote on that issue. All other votes are non-binding. All +developers are encouraged to participate in decisions, but the decision +itself is made by those who have been long-time contributors to the +project. In other words, the Apache Log4j Project is a minimum-threshold +meritocracy. + +The act of voting carries certain obligations -- voting members are not +only stating their opinion, they are agreeing to help do the work of the +Log4j Project. Since we are all volunteers, members often become +inactive for periods of time in order to take care of their "real jobs" +or devote more time to other projects. It is therefore unlikely that the +entire group membership will vote on every issue. To account for this, +all voting decisions are based on a minimum quorum. + +Each vote can be made in one of three flavors: + ++1:: +Yes, agree, or the action should be performed. On some issues, this +vote is only binding if the voter has tested the action on their own +system(s). +±0:: +Abstain, no opinion, or I am happy to let the other group members +decide this issue. An abstention may have detrimental effects if too +many people abstain. +-1:: +No. On issues where consensus is required, this vote counts as a +*veto*. All vetoes must include an explanation of why the veto is +appropriate. A veto with no explanation is void. No veto can be +overruled. If you disagree with the veto, you should lobby the person +who cast the veto. Voters intending to veto an action item should make +their opinions known to the group immediately, so that the problem can +be remedied as early as possible. + +An action item requiring _consensus approval_ must receive at least *3 +binding +1* votes and *no vetoes*. An action item requiring _majority +approval_ must receive at least *3 binding +1* votes and more *+1* votes +than *-1* votes ( _i.e._ , a majority with a minimum quorum of three +positive votes). All other action items are considered to have _lazy +approval_ until someone votes *-1* , after which point they are decided +by either consensus or a majority vote, depending upon the type of +action item. + +When appropriate, votes should be tallied in the JIRA issue. All votes +must be either sent to the mailing list or added directly to the JIRA +issue. + +[#types-of-action-items] +== Types of Action Items + +Long Term Plans:: +Long term plans are simply announcements that group members are +working on particular issues related to the Log4j software. These are +not voted on, but group members who do not agree with a particular +plan, or think an alternate plan would be better, are obligated to +inform the group of their feelings. In general, it is always better to +hear about alternate plans *prior* to spending time on less adequate +solutions. +Short Term Plans:: +Short term plans are announcements that a developer is working on a +particular set of documentation or code files, with the implication +that other developers should avoid them or try to coordinate their +changes. This is a good way to proactively avoid conflict and possible +duplication of work. +Release Plan:: +A release plan is used to keep all the developers aware of when a +release is desired, who will be the release manager, when the +repository will be frozen in order to create the release, and assorted +other trivia to keep us from tripping over ourselves during the final +moments. Lazy majority (at least 3 x +1 and more +1 than -1) decides +each issue in the release plan. +Release Testing:: +After a new release is built it must be tested before being released +to the public. Majority approval is required before the distribution +can be publicly released. +Showstoppers/Blockers:: +Showstoppers are issues that require a fix be in place before the next +public release. They are listed in JIRA in order to focus special +attention on the problem. An issue becomes a showstopper when it is +listed as such in JIRA and remains so by lazy consensus. + +All product changes to the currently active repository are subject to +lazy consensus. All product changes to a prior-branch (old version) +repository require consensus before the change is committed. + +[#when-to-commit-a-change] +== When to Commit a Change + +Ideas must be review-then-commit; patches can be commit-then-review. +With a commit-then-review process, we trust that the developer doing the +commit has a high degree of confidence in the change. Doubtful changes, +new features, and large-scale overhauls need to be discussed before +being committed to a repository. Any change that affects the semantics +of arguments to configurable directives, significantly adds to the +runtime size of the program, or changes the semantics of an existing API +function must receive consensus approval on the mailing list before +being committed. + +Each developer is responsible for notifying the mailing list and adding +an action item to JIRA when they have an idea for a new feature or major +change to propose for the product. The distributed nature of the Log4j +project requires an advance notice of 48 hours in order to properly +review a major change -- consensus approval of either the concept or a +specific patch is required before the change can be committed. Note that +a member might veto the concept (with an adequate explanation), but +later rescind that veto if a specific patch satisfies their objections. +No advance notice is required to commit singular bug fixes. + +Related changes should be committed as a group, or very closely +together. Half-completed projects should not be committed unless doing +so is necessary to pass the baton to another developer who has agreed to +complete the project in short order. All code changes must be +successfully compiled and unit tests pass on the developer's platform +before being committed. + +The current source code tree should be capable of complete compilation +at all times. However, it is sometimes impossible for a developer on one +platform to avoid breaking some other platform when a change is +committed, particularly when completing the change requires access to a +special development tool on that other platform. If it is anticipated +that a given change will break some other platform, the committer must +indicate that in the commit log. + +The committer is responsible for the quality of any third-party code or +documentation they commit to the repository. All software committed to +the repository must be covered by the Apache LICENSE or contain a +copyright and license that allows redistribution under the same +conditions as the Apache LICENSE. + +A committed change must be reversed if it is vetoed by one of the voting +members and the veto conditions cannot be immediately satisfied by the +equivalent of a "bug fix" commit. The veto must be rescinded before the +change can be included in any public release. + +[#changelogs] +== changes.xml and Git logs + +Many code changes should be noted in the changes.xml file, and all +should be documented in Git commit messages. Often the text of the Git +log and the changes.xml entry are the same, but the distinct +requirements sometimes result in different information. + +[#subversion-log] +=== Git log + +The Git commit log message contains any information needed by + +* fellow developers or other people researching source code +changes/fixes +* end users (at least point out what the implications are for end users; +it doesn't have to be in the most user friendly wording) + +If the code change was provided by a non-committer, attribute it using +Submitted-by. If the change was committed verbatim, identify the +committer(s) who reviewed it with Reviewed-by. If the change was +committed with modifications, use the appropriate wording to document +that, perhaps "committed with changes" if the person making the commit +made the changes, or "committed with contributions from xxxx" if others +made contributions to the code committed. + +Example log message: + +.... +LOG4J2-9999 +Check the return code from parsing the content length, to avoid a +crash if requests contain an invalid content length. +Submitted by: Jane Doe +Reviewed by: susiecommitter +.... + +[#changes] +=== changes.xml + +changes.xml is the subset of the information that end users need to see +when they upgrade from one release to the next: + +* what can I now do that I couldn't do before +* what problems that we anticipate a user could have suffered from are +now fixed +* all security fixes included, with CVE number. (If not available at the +time of the commit, add later.) + +All entries in changes.xml should include the appropriate JIRA issue +number and should credit contributions made by non-committers by +referencing them in the due-to attribute even if modifications needed to +be made to the contribution. + +The attribution for the change is anyone responsible for the code +changes. + +[#committing-security-fixes] +== Committing Security Fixes + +Open source projects, ASF or otherwise, have varying procedures for +commits of vulnerability fixes. One important aspect of these procedures +is whether or not fixes to vulnerabilities can be committed to a +repository with commit logs and possibly CHANGES entries which +purposefully obscure the vulnerability and omit any available +vulnerability tracking information. The Apache HTTP Server project has +decided that it is in the best interest of our users that the initial +commit of such code changes to any branch will provide the best +description available at that time as well as any available tracking +information such as CVE number. Committing of the fix will be delayed +until the project determines that all of the information about the issue +can be shared. + +In some cases there are very real benefits to sharing code early even if +full information about the issue cannot, including the potential for +broader review, testing, and distribution of the fix. This is outweighed +by the concern that sharing only the code changes allows skilled +analysts to determine the impact and exploit mechanisms but does not +allow the general user community to determine if preventative measures +should be taken. + +If a vulnerability is partially disclosed by committing a fix before the +bug is determined to be exploitable, the httpd security team will decide +on a case by case basis when to document the security implications and +tracking number. + +[#patch] +== Patch Format + +When a specific change to the software is proposed for discussion or +voting on the mailing list, it should be presented in the form of input +to the patch command. When sent to the mailing list, the message should +contain a Subject beginning with `[PATCH]` and a distinctive one-line +summary corresponding to the action item for that patch. Afterwords, the +patch summary in the STATUS file should be updated to point to the +Message-ID of that message. + +The patch should be created by using the diff -u command from the +original software file(s) to the modified software file(s). E.g., +`diff -u http_main.c.orig http_main.c >> patchfile.txt` or +`svn diff http_main.c >> patchfile.txt` All patches necessary to address +an action item should be concatenated within a single patch message. If +later modification of the patch proves necessary, the entire new patch +should be posted and not just the difference between two patches. The +STATUS file entry should then be updated to point to the new patch +message. + +The completed patchfile should produce no errors or prompts when the +command, `patch -s < patchfile` is issued in the target repository. + +[#teamwork] +== Teamwork + +Open source projects function best when everyone is aware of the "rules +of the road" and abide by them. + +1. Error on the side of caution. If you don’t understand it, don’t +touch it and ask on the list. If you think you understand it read it +again or ask until you are sure you do. Nobody will blame you for asking +questions. +2. Don’t break the build - if there is the slightest chance the change +you are making could cause unit test failures, run all unit tests. +Better yet, get in the habit of always running the unit tests before +doing the commit. +3. If the build breaks and you have made recent changes then assume you +broke it and try to fix it. Although it might not have been something +you did it will make others feel a lot better than having to fix the +mistake for you. Everyone makes mistakes. Taking responsibility for them +is a good thing. +4. Don’t change things to match your personal preference - the project +has link:javastyle.html[style guidelines] that are validated with +checkstyle, PMD, and other tools. If you aren't fixing a bug, fixing a +problem identified by the tools, or fixing something specifically called +out in these guidelines then start a discussion to see if the change is +something the project wants before starting to work on it. We try to +discuss things first and then implement the consensus reached in the +discussion. +5. Along the same lines, do not commit automatic changes made by your +IDE without reviewing them. There are a few places in the code that +cannot conform to style guidelines without causing errors in some +environments. These are clearly marked and must be left as is. diff --git a/src/site/xdoc/guidelines.xml b/src/site/xdoc/guidelines.xml deleted file mode 100644 index 3c188616e48..00000000000 --- a/src/site/xdoc/guidelines.xml +++ /dev/null @@ -1,361 +0,0 @@ - - - - - - Project Guidelines - - - -
    - -

    This document defines the guidelines for the Apache Log4j - Project. It includes definitions of how conflict - is resolved by voting, who is able to vote, the procedures to follow - for proposing and making changes as well as guidelines for changing code.

    -

    The objective here is to avoid unnecessary conflict over changes and - continue to produce a quality system in a timely manner. Not all conflict - can be avoided, but at least we can agree on the procedures for conflict to - be resolved.

    - - -
    -
    Apache Logging Project Management Committee
    -
    The group of volunteers who are responsible for managing the Apache - Logging Projects, including Log4j. This includes deciding what is distributed as - products of the Apache Logging Project, maintaining the Project's - shared resources, speaking on behalf of the Project, resolving license - disputes regarding Apache products, nominating new PMC members or - committers, and establishing these guidelines.
    -
    -

    Membership in the Apache Logging PMC is by invitation only and must be approved by - consensus of the active Logging PMC members. A PMC member is considered - inactive by their own declaration or by not contributing in any form to the - project for over six months. An inactive member can become active again by - reversing whichever condition made them inactive ( i.e. , by reversing - their earlier declaration or by once again contributing toward the - project's work). Membership can be revoked by a unanimous vote of all the - active PMC members other than the member in question.

    -
    -
    Apache Logging Committers
    -
    The group of volunteers who are responsible for the technical aspects - of the Apache Logging Projects. This group has write access to the - appropriate source repositories and these volunteers may cast binding - votes on any technical discussion. Although a committer usually joins due to - their activity on one of the Logging projects, they will have commit access to - all Logging projects.
    -
    -

    Membership as a Committer is by invitation only and must be approved by - consensus of the active Logging PMC members. A Committer is considered - inactive by their own declaration or by not contributing in any form to the - project for over six months. An inactive member can become active again by - reversing whichever condition made them inactive ( i.e. , by reversing - their earlier declaration or by once again contributing toward the - project's work). Membership can be revoked by a unanimous vote of all the - active PMC members (except the member in question if they are a PMC - member).

    -
    -
    Log4j Developers
    -
    All of the volunteers who are contributing time, code, documentation, - or resources to the Log4j Project. A developer that makes sustained, - welcome contributions to the project for over six months is usually - invited to become a Committer, though the exact timing of such - invitations depends on many factors.
    -
    mailing list
    -
    The Log4j developers' primary mailing list for discussion of issues - and changes related to the project ( dev@logging.apache.org ). - Subscription to the list is open, but only subscribers can post - directly to the list.
    -
    private list
    -
    The Logging PMC's private mailing list for discussion of issues that - are inappropriate for public discussion, such as legal, personal, or - security issues prior to a published fix. Subscription to the list is - only open (actually: mandatory) to Apache Logging's Project Management - Committee.
    -
    Git
    -
    All of the Apache products are maintained in information - repositories using either Subversion or Git; Log4j uses Git. Only some of the - Apache developers have write access to the Apache Logging repositories; everyone - has read access.
    -
    - - - -

    The Log4j project uses the Jira bug tracking - system hosted and maintained by the Apache Software Foundation for tracking bugs and enhancements. The - project roadmap may be maintained in JIRA through its RoadMap feature and through the use of - Story or Epic issues.

    -

    Many issues will be encountered by the project, each resulting in zero or - more proposed action items. Issues should be raised on the mailing list as - soon as they are identified. Action items must be raised on the mailing - list and added to JIRA using the appropriate issue type. All action items may be voted - on, but not all of them will require a formal vote.

    - - - -

    Any of the Log4j Developers may vote on any issue or action item. However, - the only binding votes are those cast by active members of the Apache Logging - PMC; if the vote is about a change to source code or documentation, the - primary author of what is being changed may also cast a binding vote on - that issue. All other votes are non-binding. All developers are encouraged - to participate in decisions, but the decision itself is made by those who - have been long-time contributors to the project. In other words, the Apache - Log4j Project is a minimum-threshold meritocracy.

    -

    The act of voting carries certain obligations -- voting members are not - only stating their opinion, they are agreeing to help do the work of the - Log4j Project. Since we are all volunteers, members often become inactive - for periods of time in order to take care of their "real jobs" or devote - more time to other projects. It is therefore unlikely that the entire group - membership will vote on every issue. To account for this, all voting - decisions are based on a minimum quorum.

    -

    Each vote can be made in one of three flavors:

    -
    -
    +1
    -
    Yes, agree, or the action should be performed. On some issues, this - vote is only binding if the voter has tested the action on their own - system(s).
    -
    ±0
    -
    Abstain, no opinion, or I am happy to let the other group members - decide this issue. An abstention may have detrimental effects if too - many people abstain.
    -
    -1
    -
    No. On issues where consensus is required, this vote counts as a - veto. All vetoes must include an explanation of why the veto is - appropriate. A veto with no explanation is void. No veto can be - overruled. If you disagree with the veto, you should lobby the person - who cast the veto. Voters intending to veto an action item should make - their opinions known to the group immediately, so that the problem can - be remedied as early as possible.
    -
    -

    An action item requiring consensus approval must receive at least 3 - binding +1 votes and no vetoes. An action item requiring majority - approval must receive at least 3 binding +1 votes and more +1 - votes than -1 votes ( i.e. , a majority with a minimum quorum of - three positive votes). All other action items are considered to have lazy - approval until someone votes -1 , after which point they are decided - by either consensus or a majority vote, depending upon the type of action - item.

    -

    When appropriate, votes should be tallied in the JIRA issue. All votes must be either sent to - the mailing list or added directly to the JIRA issue.

    -
    -
    - -
    -
    Long Term Plans
    -
    Long term plans are simply announcements that group members are - working on particular issues related to the Log4j software. These are - not voted on, but group members who do not agree with a particular - plan, or think an alternate plan would be better, are obligated to - inform the group of their feelings. In general, it is always better to - hear about alternate plans prior to spending time on less adequate - solutions.
    -
    Short Term Plans
    -
    Short term plans are announcements that a developer is working on a - particular set of documentation or code files, with the implication - that other developers should avoid them or try to coordinate their - changes. This is a good way to proactively avoid conflict and possible - duplication of work.
    -
    Release Plan
    -
    A release plan is used to keep all the developers aware of when a - release is desired, who will be the release manager, when the - repository will be frozen in order to create the release, and assorted - other trivia to keep us from tripping over ourselves during the final - moments. Lazy majority (at least 3 x +1 and more +1 than -1) decides - each issue in the release plan.
    -
    Release Testing
    -
    After a new release is built it must be tested before being released to the public. - Majority approval is required before the distribution can be publicly released.
    -
    Showstoppers/Blockers
    -
    Showstoppers are issues that require a fix be in place before the next - public release. They are listed in Jira in order to focus - special attention on the problem. An issue becomes a showstopper when - it is listed as such in Jira and remains so by lazy consensus.
    -
    -

    All product changes to the currently active repository are subject to lazy - consensus. All product changes to a prior-branch (old version) repository - require consensus before the change is committed.

    -
    -
    - -

    Ideas must be review-then-commit; patches can be commit-then-review. With a - commit-then-review process, we trust that the developer doing the commit - has a high degree of confidence in the change. Doubtful changes, new - features, and large-scale overhauls need to be discussed before being - committed to a repository. Any change that affects the semantics of - arguments to configurable directives, significantly adds to the runtime - size of the program, or changes the semantics of an existing API function - must receive consensus approval on the mailing list before being committed.

    -

    Each developer is responsible for notifying the mailing list and adding an - action item to Jira when they have an idea for a new feature or major - change to propose for the product. The distributed nature of the Log4j - project requires an advance notice of 48 hours in order to properly review - a major change -- consensus approval of either the concept or a specific - patch is required before the change can be committed. Note that a member - might veto the concept (with an adequate explanation), but later rescind - that veto if a specific patch satisfies their objections. No advance notice - is required to commit singular bug fixes.

    -

    Related changes should be committed as a group, or very closely together. - Half-completed projects should not be committed unless doing so is - necessary to pass the baton to another developer who has agreed to complete - the project in short order. All code changes must be successfully compiled - and unit tests pass on the developer's platform before being committed.

    -

    The current source code tree should be capable of complete compilation at - all times. However, it is sometimes impossible for a developer on one - platform to avoid breaking some other platform when a change is committed, - particularly when completing the change requires access to a special - development tool on that other platform. If it is anticipated that a given - change will break some other platform, the committer must indicate that in - the commit log.

    -

    The committer is responsible for the quality of any third-party code or - documentation they commit to the repository. All software committed to the - repository must be covered by the Apache LICENSE or contain a copyright and - license that allows redistribution under the same conditions as the Apache - LICENSE.

    -

    A committed change must be reversed if it is vetoed by one of the voting - members and the veto conditions cannot be immediately satisfied by the - equivalent of a "bug fix" commit. The veto must be rescinded before the - change can be included in any public release.

    -
    -
    - -

    Many code changes should be noted in the changes.xml file, and all should be - documented in Git commit messages. Often the text of the Git - log and the changes.xml entry are the same, but the distinct requirements - sometimes result in different information.

    -

    Git log

    -

    The Git commit log message contains any information needed by

    -
      -
    • -

      fellow developers or other people researching source code changes/fixes

      -
    • -
    • -

      end users (at least point out what the implications are for end users; it - doesn't have to be in the most user friendly wording)

      -
    • -
    -

    If the code change was provided by a non-committer, attribute it using - Submitted-by. If the change was committed verbatim, identify the - committer(s) who reviewed it with Reviewed-by. If the change was committed - with modifications, use the appropriate wording to document that, perhaps - "committed with changes" if the person making the commit made the changes, - or "committed with contributions from xxxx" if others made contributions to - the code committed.

    -

    Example log message:

    -
    
    -Reviewed by: susiecommitter
    -        ]]>
    -

    changes.xml

    -

    changes.xml is the subset of the information that end users need to see when - they upgrade from one release to the next:

    -
      -
    • -

      what can I now do that I couldn't do before

      -
    • -
    • -

      what problems that we anticipate a user could have suffered from are now - fixed

      -
    • -
    • -

      all security fixes included, with CVE number. (If not available at the - time of the commit, add later.)

      -
    • -
    -

    All entries in changes.xml should include the appropriate Jira issue number and should - credit contributions made by non-committers by referencing them in the due-to attribute - even if modifications needed to be made to the contribution.

    -

    The attribution for the change is anyone responsible for the code changes.

    -
    -
    - -

    Open source projects, ASF or otherwise, have varying procedures for - commits of vulnerability fixes. One important aspect of these procedures - is whether or not fixes to vulnerabilities can be committed to a - repository with commit logs and possibly CHANGES entries which - purposefully obscure the vulnerability and omit any available - vulnerability tracking information. The Apache HTTP Server project has - decided that it is in the best interest of our users that the initial - commit of such code changes to any branch will provide the best - description available at that time as well as any available tracking - information such as CVE number. Committing of the fix will be delayed - until the project determines that all of the information about the issue - can be shared.

    -

    In some cases there are very real benefits to sharing code early even if - full information about the issue cannot, including the potential for - broader review, testing, and distribution of the fix. This is outweighed - by the concern that sharing only the code changes allows skilled analysts - to determine the impact and exploit mechanisms but does not allow the - general user community to determine if preventative measures should be - taken.

    -

    If a vulnerability is partially disclosed by committing a fix before the - bug is determined to be exploitable, the httpd security team will decide - on a case by case basis when to document the security implications and - tracking number.

    -
    -
    - -

    When a specific change to the software is proposed for discussion or voting - on the mailing list, it should be presented in the form of input to the - patch command. When sent to the mailing list, the message should contain a - Subject beginning with [PATCH] and a distinctive one-line summary - corresponding to the action item for that patch. Afterwords, the patch - summary in the STATUS file should be updated to point to the Message-ID of - that message.

    -

    The patch should be created by using the diff -u command from - the original software file(s) to the modified software file(s). E.g., - diff -u http_main.c.orig http_main.c >> patchfile.txt - or - svn diff http_main.c >> patchfile.txt - All patches necessary to address an action item should be concatenated - within a single patch message. If later modification of the patch proves - necessary, the entire new patch should be posted and not just the - difference between two patches. The STATUS file entry should then be - updated to point to the new patch message.

    -

    The completed patchfile should produce no errors or prompts when the - command, - patch -s < patchfile - is issued in the target repository.

    -
    -
    - -

    Open source projects function best when everyone is aware of the "rules of the road" and abide by them.

    -
      -
    1. Error on the side of caution. If you don’t understand it, don’t touch it and ask on the list. If you think you - understand it read it again or ask until you are sure you do. Nobody will blame you for asking questions.
    2. -
    3. Don’t break the build - if there is the slightest chance the change you are making could cause unit test - failures, run all unit tests. Better yet, get in the habit of always running the unit tests before doing the commit.
    4. -
    5. If the build breaks and you have made recent changes then assume you broke it and try to fix it. Although it - might not have been something you did it will make others feel a lot better than having to fix the mistake for - you. Everyone makes mistakes. Taking responsibility for them is a good thing.
    6. -
    7. Don’t change things to match your personal preference - the project has style guidelines - that are validated with checkstyle, PMD, and other tools. If you aren’t fixing a bug, - fixing a problem identified by the tools, or fixing something specifically called out in these guidelines then - start a discussion to see if the change is something the project wants before starting to work on it. We try to - discuss things first and then implement the consensus reached in the discussion.
    8. -
    9. Along the same lines, do not commit automatic changes made by your IDE without reviewing them. There - are a few places in the code that cannot conform to style guidelines without causing errors in some environments. - These are clearly marked and must be left as is.
    10. -
    - -
    - - From e4733bac28d176a933834658f908af5d4f0fd63b Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 16:13:07 -0500 Subject: [PATCH 0114/2347] LOG4J2-1802: Convert thanks page to asciidoc --- src/site/asciidoc/thanks.adoc | 52 +++++++++++++ src/site/xdoc/thanks.xml | 136 ---------------------------------- 2 files changed, 52 insertions(+), 136 deletions(-) create mode 100644 src/site/asciidoc/thanks.adoc delete mode 100644 src/site/xdoc/thanks.xml diff --git a/src/site/asciidoc/thanks.adoc b/src/site/asciidoc/thanks.adoc new file mode 100644 index 00000000000..4c94cd27e2b --- /dev/null +++ b/src/site/asciidoc/thanks.adoc @@ -0,0 +1,52 @@ +//// + 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 + + https://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. +//// += Log4j 2 Project Thanks + +Log4j 2 is a successful project because of the large and diverse +community that contributes to it. + +There are a handful of tools that developers in the community use; some +are open-source and some are commercial. We'd like to extend a special +thanks to these communities/companies: + +|=== +|Who |What + +|image:images/YourKitLogo.png["YourKit", link="https://www.yourkit.com/features/"] +|YourKit supports the Log4j 2 project with its full-featured Java Profiler. +YourKit, LLC is the creator of innovative and intelligent tools for profiling Java and .NET applications. +See https://www.yourkit.com/features/[YourKit's leading software products]. + +|image:images/IntelliJ-IDEA-logo.png["IntelliJ IDEA", link="https://www.jetbrains.com/idea/"] +|JetBrains supports the Log4j 2 project with https://www.jetbrains.com/idea/[IntelliJ IDEA]. + +|image:https://www.jclarity.com/wp-content/uploads/2015/02/JClarity_logo_tagline3.png["jClarity", link="https://www.jclarity.com/"] +|jClarity supports the Log4j 2 project with its https://www.jclarity.com/censum/[Censum] GC log parsing tool. + +|image:https://www.apache.org/images/feather-small.gif["Apache Feather Logo", link="https://www.apache.org/foundation/thanks.html"] +|All of the Platinum/Gold/Silver/Bronze sponsors of the ASF. +|=== + +== Individual Donations to the Apache Software Foundation + +The Apache Software Foundation receives many smaller donations from +individuals via our PayPal and Amazon Payments services (details +https://www.apache.org/foundation/contributing.html[here]). + +We would like to thank all of our individual donors for their support of +our work, and for their willingness to contribute with only this as +recognition for their generosity. diff --git a/src/site/xdoc/thanks.xml b/src/site/xdoc/thanks.xml deleted file mode 100644 index 9278415f22a..00000000000 --- a/src/site/xdoc/thanks.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - -]> - - - Log4j 2 Project Thanks - - - - -
    -

    - Log4j 2 is a successful project because of the large and diverse community that contributes - to it. -

    -

    - There are a handful of tools that developers in the community use; - some are open-source and - some are commercial. - We'd like to extend a special thanks to these communities/companies: -

    -

    -

    -
    - - - - - - - - - - - - - - - - - - - -
    - - - YourKit Logo - - - - YourKit supports the Log4j 2 project with its full-featured Java - Profiler. -
    - YourKit, LLC is the creator of innovative and intelligent tools - for profiling -
    - - Java and .NET applications. See - YourKit's leading - software products. - -
    - - - IntelliJ IDEA logo - - - - JetBrains supports the Log4j 2 project with its - IntelliJ IDEA Java* IDE -
    -
    - * Actually, much more than just Java. -
    - - - jClarity - - - -
    - jClarity supports the Log4j 2 project with its - Censum - GC log parsing tool. - -
    - - Apache Feather Logo - - - All of the - Platinum/Gold/Silver/Bronze sponsors of - the ASF -
    -
    - -

     

    -

     

    -

     

    -

     

    -

     

    - - -

    - The Apache Software Foundation receives many smaller donations from individuals via our - PayPal and Amazon Payments - services (details - here - ). -

    -

    We would like to thank all of our individual donors for their support of our work, - and for their willingness to contribute with only this as recognition for their generosity. -

    -
    -
    - -
    From 7bd1c4646e0d9b81580478361443baca50c47c38 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 16:41:17 -0500 Subject: [PATCH 0115/2347] LOG4J2-1802: Add prettyprint support for asciidoc output --- src/site/resources/js/site.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/site/resources/js/site.js b/src/site/resources/js/site.js index 72a0f8cc6cf..50bff12a158 100644 --- a/src/site/resources/js/site.js +++ b/src/site/resources/js/site.js @@ -52,6 +52,12 @@ $(document).ready(function() { $(this).addClass('linenums'); } }); + + // decorator for prettyprint support in asciidoc + $('pre.highlight > code').each(function() { + var parent = $(this).parent(); + parent.addClass('prettyprint') + }); // Hack to add default visuals to tables $('table').each(function() { From 3323831043ddb2b0612f134380acbe8e02a1c76c Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 16:41:55 -0500 Subject: [PATCH 0116/2347] LOG4J2-1802: Convert api manual page to asciidoc --- src/site/asciidoc/manual/api.adoc | 184 ++++++++++++++++++++++++++++++ src/site/xdoc/manual/api.xml | 168 --------------------------- 2 files changed, 184 insertions(+), 168 deletions(-) create mode 100644 src/site/asciidoc/manual/api.adoc delete mode 100644 src/site/xdoc/manual/api.xml diff --git a/src/site/asciidoc/manual/api.adoc b/src/site/asciidoc/manual/api.adoc new file mode 100644 index 00000000000..d708aa166d2 --- /dev/null +++ b/src/site/asciidoc/manual/api.adoc @@ -0,0 +1,184 @@ += Log4j 2 API + +== Overview + +The Log4j 2 API provides the interface that applications should code to +and provides the adapter components required for implementers to create +a logging implementation. Although Log4j 2 is broken up between an API +and an implementation, the primary purpose of doing so was not to allow +multiple implementations, although that is certainly possible, but to +clearly define what classes and methods are safe to use in "normal" +application code. + +=== Hello World! + +No introduction would be complete without the customary Hello, World +example. Here is ours. First, a Logger with the name "HelloWorld" is +obtained from the +link:../log4j-api/apidocs/org/apache/logging/log4j/LogManager.html[`LogManager`]. +Next, the logger is used to write the "Hello, World!" message, however +the message will be written only if the Logger is configured to allow +informational messages. + +[source,java] +---- +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class HelloWorld { + private static final Logger logger = LogManager.getLogger("HelloWorld"); + public static void main(String[] args) { + logger.info("Hello, World!"); + } +} +---- + +The output from the call to `logger.info()` will vary significantly +depending on the configuration used. See the +link:configuration.html[Configuration] section for more details. + +=== Substituting Parameters + +Frequently the purpose of logging is to provide information about what +is happening in the system, which requires including information about +the objects being manipulated. In Log4j 1.x this could be accomplished +by doing: + +[source,java] +---- +if (logger.isDebugEnabled()) { + logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar()); +} +---- + +Doing this repeatedly has the effect of making the code feel like it is +more about logging than the actual task at hand. In addition, it results +in the logging level being checked twice; once on the call to +isDebugEnabled and once on the debug method. A better alternative would +be: + +[source,java] +---- +logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar()); +---- + +With the code above the logging level will only be checked once and the +String construction will only occur when debug logging is enabled. + +=== Formatting Parameters + +Formatter Loggers leave formatting up to you if `toString()` is not what +you want. To facilitate formatting, you can use the same format strings +as Java's +http://docs.oracle.com/javase/6/docs/api/java/util/Formatter.html#syntax[`Formatter`]. +For example: + +[source,java] +---- +public static Logger logger = LogManager.getFormatterLogger("Foo"); + +logger.debug("Logging in user %s with birthday %s", user.getName(), user.getBirthdayCalendar()); +logger.debug("Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar()); +logger.debug("Integer.MAX_VALUE = %,d", Integer.MAX_VALUE); +logger.debug("Long.MAX_VALUE = %,d", Long.MAX_VALUE); +---- + +To use a formatter Logger, you must call one of the `LogManager` +link:../log4j-api/apidocs/org/apache/logging/log4j/LogManager.html#getFormatterLogger(java.lang.Class)[`getFormatterLogger`] +methods. The output for this example shows that `Calendar::toString` is +verbose compared to custom formatting: + +[source,java] +---- +2012-12-12 11:56:19,633 [main] DEBUG: User John Smith with birthday java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=1995,MONTH=4,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=23,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?] +2012-12-12 11:56:19,643 [main] DEBUG: User John Smith with birthday 05 23, 1995 +2012-12-12 11:56:19,643 [main] DEBUG: Integer.MAX_VALUE = 2,147,483,647 +2012-12-12 11:56:19,643 [main] DEBUG: Long.MAX_VALUE = 9,223,372,036,854,775,807 +---- + +=== Mixing Loggers with Formatter Loggers + +Formatter loggers give fine-grained control over the output format, but +have the drawback that the correct type must be specified (for example, +passing anything other than a decimal integer for a %d format parameter +gives an exception). + +If your main usage is to use \{}-style parameters, but occasionally you +need fine-grained control over the output format, you can use the +`printf` method: + +[source,java] +---- +public static Logger logger = LogManager.getLogger("Foo"); + +logger.debug("Opening connection to {}...", someDataSource); +logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar()); +---- + +[#LambdaSupport] +=== Java 8 lambda support for lazy logging + +In release 2.4, the `Logger` interface added support for lambda +expressions. This allows client code to lazily log messages without +explicitly checking if the requested log level is enabled. For example, +previously you would write: + +[source,java] +---- +// pre-Java 8 style optimization: explicitly check the log level +// to make sure the expensiveOperation() method is only called if necessary +if (logger.isTraceEnabled()) { + logger.trace("Some long-running operation returned {}", expensiveOperation()); +} +---- + +With Java 8 you can achieve the same effect with a lambda expression. +You no longer need to explicitly check the log level: + +[source,java] +---- +// Java-8 style optimization: no need to explicitly check the log level: +// the lambda expression is not evaluated if the TRACE level is not enabled +logger.trace("Some long-running operation returned {}", () -> expensiveOperation()); +---- + +=== Logger Names + +Most logging implementations use a hierarchical scheme for matching +logger names with logging configuration. In this scheme, the logger name +hierarchy is represented by `'.'` characters in the logger name, in a +fashion very similar to the hierarchy used for Java package names. For +example, `org.apache.logging.appender` and `org.apache.logging.filter` +both have `org.apache.logging` as their parent. In most cases, +applications name their loggers by passing the current class's name to +`LogManager.getLogger(...)`. Because this usage is so common, Log4j 2 +provides that as the default when the logger name parameter is either +omitted or is null. For example, in all examples below the Logger will +have a name of `"org.apache.test.MyTest"`. + +[source,java] +---- +package org.apache.test; + +public class MyTest { + private static final Logger logger = LogManager.getLogger(MyTest.class); +} +---- + +[source,java] +---- +package org.apache.test; + +public class MyTest { + private static final Logger logger = LogManager.getLogger(MyTest.class.getName()); +} +---- + +[source,java] +---- +package org.apache.test; + +public class MyTest { + private static final Logger logger = LogManager.getLogger(); +} +---- diff --git a/src/site/xdoc/manual/api.xml b/src/site/xdoc/manual/api.xml deleted file mode 100644 index 84d7b51ae10..00000000000 --- a/src/site/xdoc/manual/api.xml +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - Log4j 2 API - Ralph Goers - Gary Gregory - - - -
    - - -

    - The Log4j 2 API provides the interface that applications should code to and provides the - adapter components required for implementers to create a logging implementation. Although Log4j 2 - is broken up between an API and an implementation, the primary purpose of doing so was not to - allow multiple implementations, although that is certainly possible, but to clearly define - what classes and methods are safe to use in "normal" application code. -

    -

    Hello World!

    -

    - No introduction would be complete without the customary Hello, World example. Here is ours. First, - a Logger with the name "HelloWorld" is obtained from the - LogManager. - Next, the logger is used to write the "Hello, World!" message, however the message will be written - only if the Logger is configured to allow informational messages. -

    -
    import org.apache.logging.log4j.LogManager;
    -import org.apache.logging.log4j.Logger;
    -
    -public class HelloWorld {
    -    private static final Logger logger = LogManager.getLogger("HelloWorld");
    -    public static void main(String[] args) {
    -        logger.info("Hello, World!");
    -    }
    -}
    -

    - The output from the call to logger.info() will vary significantly depending on the configuration - used. See the Configuration section for more details. -

    -

    Substituting Parameters

    -

    - Frequently the purpose of logging is to provide information about what is happening in the system, - which requires including information about the objects being manipulated. In Log4j 1.x this could - be accomplished by doing: -

    -
    if (logger.isDebugEnabled()) {
    -    logger.debug("Logging in user " + user.getName() + " with birthday " + user.getBirthdayCalendar());
    -}
    -

    - Doing this repeatedly has the effect of making the code feel like it is more about logging than the - actual task at hand. In addition, it results in the logging level being checked twice; once on the - call to isDebugEnabled and once on the debug method. A better alternative would be: -

    -
    logger.debug("Logging in user {} with birthday {}", user.getName(), user.getBirthdayCalendar());
    -

    - With the code above the logging level will only be checked once and the String construction will - only occur when debug logging is enabled. -

    -

    Formatting Parameters

    -

    - Formatter Loggers leave formatting up to you if toString() is not what you want. - To facilitate formatting, you can use the same format strings as Java's - Formatter. - For example: -

    -
    public static Logger logger = LogManager.getFormatterLogger("Foo");
    -
    -logger.debug("Logging in user %s with birthday %s", user.getName(), user.getBirthdayCalendar());
    -logger.debug("Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());
    -logger.debug("Integer.MAX_VALUE = %,d", Integer.MAX_VALUE);
    -logger.debug("Long.MAX_VALUE = %,d", Long.MAX_VALUE);
    -
    -

    - To use a formatter Logger, you must call one of the LogManager - getFormatterLogger - methods. The output for this example shows that Calendar toString() is verbose compared to custom formatting: -

    -
    2012-12-12 11:56:19,633 [main] DEBUG: User John Smith with birthday java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=1995,MONTH=4,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=23,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
    -2012-12-12 11:56:19,643 [main] DEBUG: User John Smith with birthday 05 23, 1995
    -2012-12-12 11:56:19,643 [main] DEBUG: Integer.MAX_VALUE = 2,147,483,647
    -2012-12-12 11:56:19,643 [main] DEBUG: Long.MAX_VALUE = 9,223,372,036,854,775,807
    -
    -

    Mixing Loggers with Formatter Loggers

    -

    - Formatter loggers give fine-grained control over the output format, but have the drawback - that the correct type must be specified (for example, passing anything other than a decimal integer - for a %d format parameter gives an exception). -

    -

    - If your main usage is to use {}-style parameters, but occasionally you need fine-grained - control over the output format, you can use the printf method:

    -
    public static Logger logger = LogManager.getLogger("Foo");
    -
    -logger.debug("Opening connection to {}...", someDataSource);
    -logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());
    -
    - - -

    Java 8 lambda support for lazy logging

    -

    - In release 2.4, the Logger interface added support for lambda expressions. - This allows client code to lazily log messages without explicitly checking if the requested log - level is enabled. For example, previously you would write: -

    -
    // pre-Java 8 style optimization: explicitly check the log level
    -// to make sure the expensiveOperation() method is only called if necessary
    -if (logger.isTraceEnabled()) {
    -    logger.trace("Some long-running operation returned {}", expensiveOperation());
    -}
    -

    - With Java 8 you can achieve the same effect with a lambda expression. - You no longer need to explicitly check the log level: -

    -
    // Java-8 style optimization: no need to explicitly check the log level:
    -// the lambda expression is not evaluated if the TRACE level is not enabled
    -logger.trace("Some long-running operation returned {}", () -> expensiveOperation());
    - -

    Logger Names

    -

    - Most logging implementations use a hierarchical scheme for matching logger names with logging - configuration. In this scheme, the logger name hierarchy is represented by '.' characters - in the logger name, in a fashion very similar to the hierarchy used for Java package names. For example, - org.apache.logging.appender and org.apache.logging.filter both have - org.apache.logging as their parent. In most cases, applications name their loggers by - passing the current class's name to LogManager.getLogger(...). Because this usage is so - common, Log4j 2 provides that as the default when the logger name parameter is either omitted or is - null. For example, in all examples below the Logger will have a name of - "org.apache.test.MyTest". -

    -
    package org.apache.test;
    -
    -public class MyTest {
    -    private static final Logger logger = LogManager.getLogger(MyTest.class);
    -}
    -
    package org.apache.test;
    -
    -public class MyTest {
    -    private static final Logger logger = LogManager.getLogger(MyTest.class.getName());
    -}
    -
    package org.apache.test;
    -
    -public class MyTest {
    -    private static final Logger logger = LogManager.getLogger();
    -}
    - -
    - -
    From 1b85a525c5b806c5e0ecdbf17445aa3c91dbfe67 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 16:43:55 -0500 Subject: [PATCH 0117/2347] Use more consistent page titles --- src/site/asciidoc/thanks.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/asciidoc/thanks.adoc b/src/site/asciidoc/thanks.adoc index 4c94cd27e2b..a254e44f5ab 100644 --- a/src/site/asciidoc/thanks.adoc +++ b/src/site/asciidoc/thanks.adoc @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. //// -= Log4j 2 Project Thanks += Project Thanks Log4j 2 is a successful project because of the large and diverse community that contributes to it. From 8af36c9d10a1bd17f1267f2d2f198c5bcf66f052 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 17:19:18 -0500 Subject: [PATCH 0118/2347] Add asciidoc tables to striped table hack --- src/site/resources/js/site.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/resources/js/site.js b/src/site/resources/js/site.js index 50bff12a158..902a0dda928 100644 --- a/src/site/resources/js/site.js +++ b/src/site/resources/js/site.js @@ -61,7 +61,7 @@ $(document).ready(function() { // Hack to add default visuals to tables $('table').each(function() { - if ($(this).hasClass('bodyTable')) { + if ($(this).hasClass('bodyTable') || $(this).hasClass('tableblock')) { // Remove border="1" which is added by maven this.border = 0; From 0c47af7f22b4ab7b720d857fc482ef1fc6fabf4e Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 17:19:43 -0500 Subject: [PATCH 0119/2347] LOG4J2-1802: Convert appenders manual to asciidoc --- src/site/asciidoc/manual/appenders.adoc | 4483 +++++++++++++++++++ src/site/xdoc/manual/appenders.xml | 5400 ----------------------- 2 files changed, 4483 insertions(+), 5400 deletions(-) create mode 100644 src/site/asciidoc/manual/appenders.adoc delete mode 100644 src/site/xdoc/manual/appenders.xml diff --git a/src/site/asciidoc/manual/appenders.adoc b/src/site/asciidoc/manual/appenders.adoc new file mode 100644 index 00000000000..b37af239ed3 --- /dev/null +++ b/src/site/asciidoc/manual/appenders.adoc @@ -0,0 +1,4483 @@ += Appenders +Ralph Goers; Gary Gregory; Nick Williams; Matt Sicker + +Appenders are responsible for delivering LogEvents to their destination. +Every Appender must implement the +link:../log4j-core/apidocs/org/apache/logging/log4j/core/Appender.html[`Appender`] +interface. Most Appenders will extend +link:../log4j-core/apidocs/org/apache/logging/log4j/core/appender/AbstractAppender.html[`AbstractAppender`] +which adds +link:../log4j-core/apidocs/org/apache/logging/log4j/core/LifeCycle.html[`Lifecycle`] +and +link:../log4j-core/apidocs/org/apache/logging/log4j/core/filter/Filterable.html[`Filterable`] +support. `Lifecycle` allows components to finish initialization after +configuration has completed and to perform cleanup during shutdown. +`Filterable` allows the component to have `Filter`s attached to it which are +evaluated during event processing. + +Appenders usually are only responsible for writing the event data to the +target destination. In most cases they delegate responsibility for +formatting the event to a link:layouts.html[layout]. Some appenders wrap +other appenders so that they can modify the `LogEvent`, handle a failure +in an `Appender`, route the event to a subordinate `Appender` based on +advanced `Filter` criteria or provide similar functionality that does not +directly format the event for viewing. + +Appenders always have a name so that they can be referenced from +Loggers. + +In the tables below, the "Type" column corresponds to the Java type +expected. For non-JDK classes, these should usually be in +link:../log4j-core/apidocs/index.html[Log4j Core] unless otherwise +noted. + +[#AsyncAppender] +== AsyncAppender + +The AsyncAppender accepts references to other Appenders and causes +LogEvents to be written to them on a separate Thread. Note that +exceptions while writing to those Appenders will be hidden from the +application. The AsyncAppender should be configured after the appenders +it references to allow it to shut down properly. + +By default, AsyncAppender uses +https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ArrayBlockingQueue.html[`java.util.concurrent.ArrayBlockingQueue`] +which does not require any external libraries. Note that multi-threaded +applications should exercise care when using this appender as such: the +blocking queue is susceptible to lock contention and our +link:../performance.html#asyncLogging[tests showed] performance may +become worse when more threads are logging concurrently. Consider using +link:async.html[lock-free Async Loggers] for optimal performance. + +.AsyncAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|AppenderRef |String |The name of the Appenders to invoke +asynchronously. Multiple AppenderRef elements can be configured. + +|blocking |boolean |If true, the appender will wait until there are free +slots in the queue. If false, the event will be written to the error +appender if the queue is full. The default is true. + +|shutdownTimeout |integer |How many milliseconds the Appender should +wait to flush outstanding log events in the queue on shutdown. The +default is zero which means to wait forever. + +|bufferSize |integer a| +Specifies the maximum number of events that can be queued. The default +is 1024. Note that when using a disruptor-style `BlockingQueue`, this +buffer size must be a power of 2. + +When the application is logging faster than the underlying appender can +keep up with for a long enough time to fill up the queue, the behavious +is determined by the +link:../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncQueueFullPolicy.html[`AsyncQueueFullPolicy`]. + +|errorRef |String |The name of the Appender to invoke if none of the +appenders can be called, either due to errors in the appenders or +because the queue is full. If not specified then errors will be ignored. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|includeLocation |boolean |Extracting location is an expensive operation +(it can make logging 5 - 20 times slower). To improve performance, +location is not included by default when adding a log event to the +queue. You can change this by setting includeLocation="true". + +|BlockingQueueFactory |BlockingQueueFactory |This element overrides what +type of `BlockingQueue` to use. See link:#BlockingQueueFactory[below +documentation] for more details. +|======================================================================= + +There are also a few system properties that can be used to maintain +application throughput even when the underlying appender cannot keep up +with the logging rate and the queue is filling up. See the details for +system properties +link:configuration.html#log4j2.AsyncQueueFullPolicy[`log4j2.AsyncQueueFullPolicy` +and `log4j2.DiscardThreshold`]. + +A typical AsyncAppender configuration might look like: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + +---- + +[[BlockingQueueFactory]] Starting in Log4j 2.7, a custom implementation +of `BlockingQueue` or `TransferQueue` can be specified using a +link:../log4j-core/apidocs/org/apache/logging/log4j/core/async/BlockingQueueFactory.html[`BlockingQueueFactory`] +plugin. To override the default `BlockingQueueFactory`, specify the +plugin inside an `` element like so: + +[source,xml] +---- + + + + + + + + + + + + + + +---- + +Log4j ships with the following implementations: + +.BlockingQueueFactory Implementations +[cols=",",options="header",] +|======================================================================= +|Plugin Name |Description +|ArrayBlockingQueue |This is the default implementation that uses +https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ArrayBlockingQueue.html[`ArrayBlockingQueue`]. + +|DisruptorBlockingQueue |This uses the +https://github.com/conversant/disruptor[Conversant Disruptor] +implementation of `BlockingQueue`. This plugin takes a single optional +attribute, `spinPolicy`, which corresponds to the `SpinPolicy` enum. + +|JCToolsBlockingQueue |This uses +https://jctools.github.io/JCTools/[JCTools], specifically the MPSC +bounded lock-free queue. + +|LinkedTransferQueue |This uses the new in Java 7 implementation +https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/LinkedTransferQueue.html[`LinkedTransferQueue`]. +Note that this queue does not use the `bufferSize` configuration +attribute from AsyncAppender as `LinkedTransferQueue` does not support a +maximum capacity. +|======================================================================= + +[#CassandraAppender] +== CassandraAppender + +The CassandraAppender writes its output to an +https://cassandra.apache.org/[Apache Cassandra] database. A keyspace and +table must be configured ahead of time, and the columns of that table +are mapped in a configuration file. Each column can specify either a +link:layouts.html[StringLayout] (e.g., a +link:layouts.html#PatternLayout[PatternLayout]) along with an optional +conversion type, or only a conversion type for +`org.apache.logging.log4j.spi.ThreadContextMap` or +`org.apache.logging.log4j.spi.ThreadContextStack` to store the +link:thread-context.html[MDC or NDC] in a map or list column +respectively. A conversion type compatible with `java.util.Date` will +use the log event timestamp converted to that type (e.g., use +`java.util.Date` to fill a `timestamp` column type in Cassandra). + +.CassandraAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|batched |boolean |Whether or not to use batch statements to write log +messages to Cassandra. By default, this is `false`. + +|batchType +|http://docs.datastax.com/en/drivers/java/3.0/com/datastax/driver/core/BatchStatement.Type.html[`BatchStatement.Type`] +|The batch type to use when using batched writes. By default, this is +`LOGGED`. + +|bufferSize |int |The number of log messages to buffer or batch before +writing. By default, no buffering is done. + +|clusterName |String |The name of the Cassandra cluster to connect to. + +|columns |ColumnMapping[] |A list of column mapping configurations. Each +column must specify a column name. Each column can have a conversion +type specified by its fully qualified class name. By default, the +conversion type is `String`. If the configured type is +assignment-compatible with +link:../log4j-api/apidocs/org/apache/logging/log4j/util/ReadOnlyStringMap.html[`ReadOnlyStringMap`] +/ +link:../log4j-api/apidocs/org/apache/logging/log4j/spi/ThreadContextMap.html[`ThreadContextMap`] +or +link:../log4j-api/apidocs/org/apache/logging/log4j/spi/ThreadContextStack.html[`ThreadContextStack`], +then that column will be populated with the MDC or NDC respectively. If +the configured type is assignment-compatible with `java.util.Date`, then +the log timestamp will be converted to that configured date type. If a +`literal` attribute is given, then its value will be used as is in the +`INSERT` query without any escaping. Otherwise, the layout or pattern +specified will be converted into the configured type and stored in that +column. + +|contactPoints |SocketAddress[] |A list of hosts and ports of Cassandra +nodes to connect to. These must be valid hostnames or IP addresses. By +default, if a port is not specified for a host or it is set to 0, then +the default Cassandra port of 9042 will be used. By default, +`localhost:9042` will be used. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|keyspace |String |The name of the keyspace containing the table that +log messages will be written to. + +|name |String |The name of the Appender. + +|password |String |The password to use (along with the username) to +connect to Cassandra. + +|table |String |The name of the table to write log messages to. + +|useClockForTimestampGenerator |boolean |Whether or not to use the +configured `org.apache.logging.log4j.core.time.Clock` as a +http://docs.datastax.com/en/drivers/java/3.0/com/datastax/driver/core/TimestampGenerator.html[`TimestampGenerator`]. +By default, this is `false`. + +|username |String |The username to use to connect to Cassandra. By +default, no username or password is used. + +|useTls |boolean |Whether or not to use TLS/SSL to connect to Cassandra. +This is `false` by default. +|======================================================================= + +Here is an example CassandraAppender configuration: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + + +---- + +This example configuration uses the following table schema: + +[source,sql] +---- +CREATE TABLE logs ( + id timeuuid PRIMARY KEY, + timeid timeuuid, + message text, + level text, + marker text, + logger text, + timestamp timestamp, + mdc map, + ndc list +); +---- + +[#ConsoleAppender] +== ConsoleAppender + +As one might expect, the ConsoleAppender writes its output to either +System.out or System.err with System.out being the default target. A +Layout must be provided to format the LogEvent. + +.ConsoleAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|follow |boolean |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`. + +|direct |boolean |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 will not respect +`java.lang.System.setOut()/.setErr()` and may get intertwined with other +output to `java.lang.System.out/.err` in a multi-threaded application. +_New since 2.6.2. Be aware that this is a new addition, and it has only +been tested with Oracle JVM on Linux and Windows so far._ + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|target |String |Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is +"SYSTEM_OUT". +|======================================================================= + +A typical Console configuration might look like: + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + +---- + +[#FailoverAppender] +== FailoverAppender + +The FailoverAppender wraps a set of appenders. If the primary Appender +fails the secondary appenders will be tried in order until one succeeds +or there are no more secondaries to try. + +.FailoverAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|primary |String |The name of the primary Appender to use. + +|failovers |String[] |The names of the secondary Appenders to use. + +|name |String |The name of the Appender. + +|retryIntervalSeconds |integer |The number of seconds that should pass +before retrying the primary Appender. The default is 60. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. + +|target |String |Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is +"SYSTEM_ERR". +|======================================================================= + +A Failover configuration might look like: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + + + + +---- + +[#FileAppender] +== FileAppender + +The FileAppender is an OutputStreamAppender that writes to the File +named in the fileName parameter. The FileAppender uses a FileManager +(which extends OutputStreamManager) to actually perform the file I/O. +While FileAppenders from different Configurations cannot be shared, the +FileManagers can be if the Manager is accessible. For example, two web +applications in a servlet container can have their own configuration and +safely write to the same file if Log4j is in a ClassLoader that is +common to both of them. + +.FileAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|bufferedIO |boolean |When true - the default, records will be written +to a buffer and the data will be written to disk when the buffer is full +or, if immediateFlush is set, when the record is written. File locking +cannot be used with bufferedIO. Performance tests have shown that using +buffered I/O significantly improves performance, even if immediateFlush +is enabled. + +|bufferSize |int |When bufferedIO is true, this is the buffer size, the +default is 8192 bytes. + +|createOnDemand |boolean |The appender creates the file on-demand. The +appender only creates the file when a log event passes all filters and +is routed to this appender. Defaults to false. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee the data is written to disk but could impact +performance. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is written +to disk but is more efficient. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|locking |boolean |When set to true, I/O operations will occur only +while the file lock is held allowing FileAppenders in multiple JVMs and +potentially multiple hosts to write to the same file simultaneously. +This will significantly impact performance so should be used carefully. +Furthermore, on many systems the file lock is "advisory" meaning that +other applications can perform operations on the file without acquiring +a lock. The default value is false. + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|filePermissions |String a| +File attribute permissions in POSIX format to apply whenever the file is +created. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +Examples: `rw-------` or `rw-rw-rw-` etc... + +|fileOwner |String a| +File owner to define whenever the file is created. + +Changing file's owner may be restricted for security reason and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +Underlying files system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[owner] +attribute view. + +|fileGroup |String a| +File group to define whenever the file is created. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +|======================================================================= + +Here is a sample File configuration: + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + +---- + +[#FlumeAppender] +== FlumeAppender + +_This is an optional component supplied in a separate jar._ + +http://flume.apache.org/index.html[Apache Flume] is a distributed, +reliable, and available system for efficiently collecting, aggregating, +and moving large amounts of log data from many different sources to a +centralized data store. The FlumeAppender takes LogEvents and sends them +to a Flume agent as serialized Avro events for consumption. + +The Flume Appender supports three modes of operation. + +1. It can act as a remote Flume client which sends Flume events via +Avro to a Flume Agent configured with an Avro Source. +2. It can act as an embedded Flume Agent where Flume events pass +directly into Flume for processing. +3. It can persist events to a local BerkeleyDB data store and then +asynchronously send the events to Flume, similar to the embedded Flume +Agent but without most of the Flume dependencies. + +Usage as an embedded agent will cause the messages to be directly passed +to the Flume Channel and then control will be immediately returned to +the application. All interaction with remote agents will occur +asynchronously. Setting the "type" attribute to "Embedded" will force +the use of the embedded agent. In addition, configuring agent properties +in the appender configuration will also cause the embedded agent to be +used. + +.FlumeAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|agents |Agent[] |An array of Agents to which the logging events should +be sent. If more than one agent is specified the first Agent will be the +primary and subsequent Agents will be used in the order specified as +secondaries should the primary Agent fail. Each Agent definition +supplies the Agents host and port. The specification of agents and +properties are mutually exclusive. If both are configured an error will +result. + +|agentRetries |integer |The number of times the agent should be retried +before failing to a secondary. This parameter is ignored when +type="persistent" is specified (agents are tried once before failing to +the next). + +|batchSize |integer |Specifies the number of events that should be sent +as a batch. The default is 1. _This parameter only applies to the Flume +Appender._ + +|compress |boolean |When set to true the message body will be compressed +using gzip + +|connectTimeoutMillis |integer |The number of milliseconds Flume will +wait before timing out the connection. + +|dataDir |String |Directory where the Flume write ahead log should be +written. Valid only when embedded is set to true and Agent elements are +used instead of Property elements. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|eventPrefix |String |The character string to prepend to each event +attribute in order to distinguish it from MDC attributes. The default is +an empty string. + +|flumeEventFactory |FlumeEventFactory |Factory that generates the Flume +events from Log4j events. The default factory is the FlumeAvroAppender +itself. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is specified RFC5424Layout will be used. + +|lockTimeoutRetries |integer |The number of times to retry if a +LockConflictException occurs while writing to Berkeley DB. The default +is 5. + +|maxDelayMillis |integer |The maximum number of milliseconds to wait for +batchSize events before publishing the batch. + +|mdcExcludes |String |A comma separated list of mdc keys that should be +excluded from the FlumeEvent. This is mutually exclusive with the +mdcIncludes attribute. + +|mdcIncludes |String |A comma separated list of mdc keys that should be +included in the FlumeEvent. Any keys in the MDC not found in the list +will be excluded. This option is mutually exclusive with the mdcExcludes +attribute. + +|mdcRequired |String |A comma separated list of mdc keys that must be +present in the MDC. If a key is not present a LoggingException will be +thrown. + +|mdcPrefix |String |A string that should be prepended to each MDC key in +order to distinguish it from event attributes. The default string is +"mdc:". + +|name |String |The name of the Appender. + +|properties |Property[] a| +One or more Property elements that are used to configure the Flume +Agent. The properties must be configured without the agent name (the +appender name is used for this) and no sources can be configured. +Interceptors can be specified for the source using +"sources.log4j-source.interceptors". All other Flume configuration +properties are allowed. Specifying both Agent and Property elements will +result in an error. + +When used to configure in Persistent mode the valid properties are: + +1. "keyProvider" to specify the name of the plugin to provide the +secret key for encryption. + +|requestTimeoutMillis |integer |The number of milliseconds Flume will +wait before timing out the request. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|type |enumeration |One of "Avro", "Embedded", or "Persistent" to +indicate which variation of the Appender is desired. +|======================================================================= + +A sample FlumeAppender configuration that is configured with a primary +and a secondary agent, compresses the body, and formats the body using +the RFC5424Layout: + +[source,xml] +---- + + + + + + + + + + + + + + + +---- + +A sample FlumeAppender configuration that is configured with a primary +and a secondary agent, compresses the body, formats the body using the +RFC5424Layout, and persists encrypted events to disk: + +[source,xml] +---- + + + + + + + + MySecretProvider + + + + + + + + +---- + +A sample FlumeAppender configuration that is configured with a primary +and a secondary agent, compresses the body, formats the body using +RFC5424Layout and passes the events to an embedded Flume Agent. + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + +---- + +A sample FlumeAppender configuration that is configured with a primary +and a secondary agent using Flume configuration properties, compresses +the body, formats the body using RFC5424Layout and passes the events to +an embedded Flume Agent. + +[source,xml] +---- + + + + + file + file + target/file-channel/checkpoint + target/file-channel/data + agent1 agent2 + file + avro + 192.168.10.101 + 8800 + 100 + file + avro + 192.168.10.102 + 8800 + 100 + group1 + agent1 agent2 + failover + 10 + 5 + + + + + + + + + + + + + + + +---- + +[#JDBCAppender] +== JDBCAppender + +As of Log4j 2.11.0, JDBC support has moved from the existing module +`logj-core` to the new module `log4j-jdbc`. + +The JDBCAppender writes log events to a relational database table using +standard JDBC. It can be configured to obtain JDBC connections using a +JNDI `DataSource` or a custom factory method. Whichever approach you +take, it *_must_* be backed by a connection pool. Otherwise, logging +performance will suffer greatly. If batch statements are supported by +the configured JDBC driver and a `bufferSize` is configured to be a +positive number, then log events will be batched. Note that as of Log4j +2.8, there are two ways to configure log event to column mappings: the +original `ColumnConfig` style that only allows strings and timestamps, +and the new `ColumnMapping` plugin that uses Log4j's built-in type +conversion to allow for more data types (this is the same plugin as in +the <>). + +To get off the ground quickly during development, an alternative to +using a connection source based on JNDI is to use the non-pooling +`DriverManager` connection source. This connection source uses a JDBC +connection string, a user name, and a password. Optionally, you can also +use properties. + +.JDBCAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|bufferSize |int |If an integer greater than 0, this causes the appender +to buffer log events and flush whenever the buffer reaches this size. + +|connectionSource |ConnectionSource |_Required._ The connections source +from which database connections should be retrieved. + +|tableName |String |_Required._ The name of the database table to insert +log events into. + +|columnConfigs |ColumnConfig[] |_Required (and/or columnMappings)._ +Information about the columns that log event data should be inserted +into and how to insert that data. This is represented with multiple +`` elements. + +|columnMappings |ColumnMapping[] |_Required (and/or columnConfigs)._ A +list of column mapping configurations. Each column must specify a column +name. Each column can have a conversion type specified by its fully +qualified class name. By default, the conversion type is `String`. If +the configured type is assignment-compatible with +link:../log4j-api/apidocs/org/apache/logging/log4j/util/ReadOnlyStringMap.html[`ReadOnlyStringMap`] +/ +link:../log4j-api/apidocs/org/apache/logging/log4j/spi/ThreadContextMap.html[`ThreadContextMap`] +or +link:../log4j-api/apidocs/org/apache/logging/log4j/spi/ThreadContextStack.html[`ThreadContextStack`], +then that column will be populated with the MDC or NDC respectively +(this is database-specific how they handle inserting a `Map` or `List` +value). If the configured type is assignment-compatible with +`java.util.Date`, then the log timestamp will be converted to that +configured date type. If the configured type is assignment-compatible +with `java.sql.Clob` or `java.sql.NClob`, then the formatted event will +be set as a Clob or NClob respectively (similar to the traditional +ColumnConfig plugin). If a `literal` attribute is given, then its value +will be used as is in the `INSERT` query without any escaping. +Otherwise, the layout or pattern specified will be converted into the +configured type and stored in that column. +|======================================================================= + +When configuring the JDBCAppender, you must specify a `ConnectionSource` +implementation from which the Appender gets JDBC connections. You must +use exactly one of the following nested elements: + +* link:#JDBCDataSource[``]: Uses JNDI. +* link:#JDBCConnectionFactory[``]: Points to a +class-method pair to provide JDBC connections. +* link:#JDBCDriverManager[``]: A quick and dirty way to +get off the ground, no connection pooling. +* link:#JDBCPoolingDriver[``]: Uses Apache Commons DBCP +to provide connection pooling. + +[#JDBCDataSource] +.DataSource Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|jndiName |String |_Required._ The full, prefixed JNDI name that the +`javax.sql.DataSource` is bound to, such as +`java:/comp/env/jdbc/LoggingDatabase`. The `DataSource` must be backed +by a connection pool; otherwise, logging will be very slow. +|======================================================================= + +[#JDBCConnectionFactory] +.ConnectionFactory Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|class |Class |_Required._ The fully qualified name of a class +containing a static factory method for obtaining JDBC connections. + +|method |Method |_Required._ The name of a static factory method for +obtaining JDBC connections. This method must have no parameters and its +return type must be either `java.sql.Connection` or `DataSource`. If the +method returns `Connection`s, it must obtain them from a connection pool +(and they will be returned to the pool when Log4j is done with them); +otherwise, logging will be very slow. If the method returns a +`DataSource`, the `DataSource` will only be retrieved once, and it must +be backed by a connection pool for the same reasons. +|======================================================================= + +[#JDBCDriverManager] +.DriverManager Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|connectionString |String |_Required._ The driver-specific JDBC +connection string. + +|userName |String |The database user name. You cannot specify both +properties and a user name or password. + +|password |String |The database password. You cannot specify both +properties and a user name or password. + +|driverClassName |String |The JDBC driver class name. Some old JDBC +Driver can only be discovered by explicitly loading them by class name. + +|properties |Property[] |A list of properties. You cannot specify both +properties and a user name or password. +|======================================================================= + +[#JDBCPoolingDriver] +.PoolingDriver Parameters (Apache Commons DBCP) +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|DriverManager parameters |DriverManager parameters |This connection +source inherits all parameter from the DriverManager connection source. + +|poolName |String |The pool name used to pool JDBC Connections. Defaults +to `example`. You can use the JDBC connection string prefix +`jdbc:apache:commons:dbcp:` followed by the pool name if you want to use +a pooled connection elsewhere. For example: +`jdbc:apache:commons:dbcp:example`. +|======================================================================= + +When configuring the JDBCAppender, use the nested `` elements to +specify which columns in the table should be written to and how to write +to them. The JDBCAppender uses this information to formulate a +`PreparedStatement` to insert records without SQL injection +vulnerability. + +.Column Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the database column. + +|pattern |String |Use this attribute to insert a value or values from +the log event in this column using a `PatternLayout` pattern. Simply +specify any legal pattern in this attribute. Either this attribute, +`literal`, or `isEventTimestamp="true"` must be specified, but not more +than one of these. + +|literal |String |Use this attribute to insert a literal value in this +column. The value will be included directly in the insert SQL, without +any quoting (which means that if you want this to be a string, your +value should contain single quotes around it like this: +`literal="'Literal String'"`). This is especially useful for databases +that don't support identity columns. For example, if you are using +Oracle you could specify `literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL"` to +insert a unique ID in an ID column. Either this attribute, `pattern`, or +`isEventTimestamp="true"` must be specified, but not more than one of +these. + +|parameter |String a| +Use this attribute to insert an expression with a parameter marker '?' +in this column. The value will be included directly in the insert SQL, +without any quoting (which means that if you want this to be a string, +your value should contain single quotes around it like this: + +`` + +You can only specify one of `literal` or `parameter`. + +|isEventTimestamp |boolean |Use this attribute to insert the event +timestamp in this column, which should be a SQL datetime. The value will +be inserted as a `java.sql.Types.TIMESTAMP`. Either this attribute +(equal to `true`), `pattern`, or `isEventTimestamp` must be specified, +but not more than one of these. + +|isUnicode |boolean |This attribute is ignored unless `pattern` is +specified. If `true` or omitted (default), the value will be inserted as +unicode (`setNString` or `setNClob`). Otherwise, the value will be +inserted non-unicode (`setString` or `setClob`). + +|isClob |boolean |This attribute is ignored unless `pattern` is +specified. Use this attribute to indicate that the column stores +Character Large Objects (CLOBs). If `true`, the value will be inserted +as a CLOB (`setClob` or `setNClob`). If `false` or omitted (default), +the value will be inserted as a VARCHAR or NVARCHAR (`setString` or +`setNString`). +|======================================================================= + +.ColumnMapping Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the database column. + +|pattern |String |Use this attribute to insert a value or values from +the log event in this column using a `PatternLayout` pattern. Simply +specify any legal pattern in this attribute. Either this attribute, +`literal`, or `isEventTimestamp="true"` must be specified, but not more +than one of these. + +|literal |String |Use this attribute to insert a literal value in this +column. The value will be included directly in the insert SQL, without +any quoting (which means that if you want this to be a string, your +value should contain single quotes around it like this: +`literal="'Literal String'"`). This is especially useful for databases +that don't support identity columns. For example, if you are using +Oracle you could specify `literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL"` to +insert a unique ID in an ID column. Either this attribute, `pattern`, or +`isEventTimestamp="true"` must be specified, but not more than one of +these. + +|layout |Layout |The Layout to format the LogEvent. + +|type |String |Conversion type name, a fully-qualified class name. +|======================================================================= + +Here are a couple sample configurations for the JDBCAppender, as well as +a sample factory implementation that uses Commons Pooling and Commons +DBCP to pool database connections: + +[source,xml] +---- + + + + + + + + + + + + + + + + + + +---- + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + +---- + +[source,java] +---- +package net.example.db; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +import javax.sql.DataSource; + +import org.apache.commons.dbcp.DriverManagerConnectionFactory; +import org.apache.commons.dbcp.PoolableConnection; +import org.apache.commons.dbcp.PoolableConnectionFactory; +import org.apache.commons.dbcp.PoolingDataSource; +import org.apache.commons.pool.impl.GenericObjectPool; + +public class ConnectionFactory { + private static interface Singleton { + final ConnectionFactory INSTANCE = new ConnectionFactory(); + } + + private final DataSource dataSource; + + private ConnectionFactory() { + Properties properties = new Properties(); + properties.setProperty("user", "logging"); + properties.setProperty("password", "abc123"); // or get properties from some configuration file + + GenericObjectPool pool = new GenericObjectPool(); + DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory( + "jdbc:mysql://example.org:3306/exampleDb", properties + ); + new PoolableConnectionFactory( + connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED + ); + + this.dataSource = new PoolingDataSource(pool); + } + + public static Connection getDatabaseConnection() throws SQLException { + return Singleton.INSTANCE.dataSource.getConnection(); + } +} +---- + +This appender is link:messages.html#MapMessage[`MapMessage`]-aware. + +The following configuration uses a `MessageLayout` to indicate that the +Appender should match the keys of a `MapMessage` to the names of +`ColumnMapping`s when setting the values of the Appender's SQL INSERT +statement. This let you insert rows for custom values in a database +table based on a Log4j `MapMessage` instead of values from `LogEvent`s. + +[source,xml] +---- + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +[#JMSAppender] +== JMSAppender + +[[JMSQueueAppender]] [[JMSTopicAppender]] +As of Log4j 2.11.0, JPA support has moved from the existing module +`logj-core` to the new module `log4j-jms`. + +The JMS Appender sends the formatted log event to a JMS Destination. + +Note that in Log4j 2.0, this appender was split into a JMSQueueAppender +and a JMSTopicAppender. Starting in Log4j 2.1, these appenders were +combined into the JMS Appender which makes no distinction between queues +and topics. However, configurations written for 2.0 which use the +`` or `` elements will continue to work with the +new `` configuration element. + +.JMS Appender Parameters +[cols=",,,",options="header",] +|======================================================================= +|Parameter Name |Type |Default |Description +|factoryBindingName |String |_Required_ |The name to locate in the +Context that provides the +https://download.oracle.com/javaee/5/api/javax/jms/ConnectionFactory.html[`ConnectionFactory`]. +This can be any subinterface of `ConnectionFactory` as well. + +|factoryName |String |_Required_ |The fully qualified class name that +should be used to define the Initial Context Factory as defined in +https://download.oracle.com/javase/7/docs/api/javax/naming/Context.html#INITIAL_CONTEXT_FACTORY[`INITIAL_CONTEXT_FACTORY`]. +If a factoryName is specified without a providerURL a warning message +will be logged as this is likely to cause problems. + +|filter |Filter |null |A Filter to determine if the event should be +handled by this Appender. More than one Filter may be used by using a +CompositeFilter. + +|layout |Layout |_Required_ |The Layout to use to format the LogEvent. +_New since 2.9, in previous versions SerializedLayout was default._ + +|name |String |_Required_ |The name of the Appender. + +|password |String |null |The password to use to create the JMS +connection. + +|providerURL |String |_Required_ |The URL of the provider to use as +defined by +https://download.oracle.com/javase/7/docs/api/javax/naming/Context.html#PROVIDER_URL[`PROVIDER_URL`]. + +|destinationBindingName |String |_Required_ |The name to use to locate +the +https://download.oracle.com/javaee/5/api/javax/jms/Destination.html[`Destination`]. +This can be a `Queue` or `Topic`, and as such, the attribute names +`queueBindingName` and `topicBindingName` are aliases to maintain +compatibility with the Log4j 2.0 JMS appenders. + +|securityPrincipalName |String |null |The name of the identity of the +Principal as specified by +https://download.oracle.com/javase/7/docs/api/javax/naming/Context.html#SECURITY_PRINCIPAL[`SECURITY_PRINCIPAL`]. +If a securityPrincipalName is specified without securityCredentials a +warning message will be logged as this is likely to cause problems. + +|securityCredentials |String |null |The security credentials for the +principal as specified by +https://download.oracle.com/javase/7/docs/api/javax/naming/Context.html#SECURITY_CREDENTIALS[`SECURITY_CREDENTIALS`]. + +|ignoreExceptions |boolean |true |When `true`, exceptions caught while +appending events are internally logged and then ignored. When `false` +exceptions are propagated to the caller. You must set this to `false` +when wrapping this Appender in a +link:#FailoverAppender[FailoverAppender]. + +|immediateFail |boolean |false |When set to true, log events will not +wait to try to reconnect and will fail immediately if the JMS resources +are not available. New in 2.9. + +|reconnectIntervalMillis |long |5000 |If set to a value greater than 0, +after an error, the JMSManager will attempt to reconnect to the broker +after waiting the specified number of milliseconds. If the reconnect +fails then an exception will be thrown (which can be caught by the +application if `ignoreExceptions` is set to `false`). New in 2.9. + +|urlPkgPrefixes |String |null |A colon-separated list of package +prefixes for the class name of the factory class that will create a URL +context factory as defined by +https://download.oracle.com/javase/7/docs/api/javax/naming/Context.html#URL_PKG_PREFIXES[`URL_PKG_PREFIXES`]. + +|userName |String |null |The user id used to create the JMS connection. +|======================================================================= + +Here is a sample JMS Appender configuration: + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + +---- + +To map your Log4j `MapMessage`s to JMS `javax.jms.MapMessage`s, set the +layout of the appender to `MessageLayout` with `` +(Since 2.9.): + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + +---- + +[#JPAAppender] +== JPAAppender + +As of Log4j 2.11.0, JPA support has moved from the existing module +`logj-core` to the new module `log4j-jpa`. + +The JPAAppender writes log events to a relational database table using +the Java Persistence API 2.1. It requires the API and a provider +implementation be on the classpath. It also requires a decorated entity +configured to persist to the table desired. The entity should either +extend +`org.apache.logging.log4j.core.appender.db.jpa.BasicLogEventEntity` (if +you mostly want to use the default mappings) and provide at least an +`@Id` property, or +`org.apache.logging.log4j.core.appender.db.jpa.AbstractLogEventWrapperEntity` +(if you want to significantly customize the mappings). See the Javadoc +for these two classes for more information. You can also consult the +source code of these two classes as an example of how to implement the +entity. + +.JPAAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|bufferSize |int |If an integer greater than 0, this causes the appender +to buffer log events and flush whenever the buffer reaches this size. + +|entityClassName |String |_Required._ The fully qualified name of the +concrete LogEventWrapperEntity implementation that has JPA annotations +mapping it to a database table. + +|persistenceUnitName |String |_Required._ The name of the JPA +persistence unit that should be used for persisting log events. +|======================================================================= + +Here is a sample configuration for the JPAAppender. The first XML sample +is the Log4j configuration file, the second is the `persistence.xml` +file. EclipseLink is assumed here, but any JPA 2.1 or higher provider +will do. You should _always_ create a _separate_ persistence unit for +logging, for two reasons. First, `` _must_ be set to +"NONE," which is usually not desired in normal JPA usage. Also, for +performance reasons the logging entity should be isolated in its own +persistence unit away from all other entities and you should use a +non-JTA data source. Note that your persistence unit _must_ also contain +`` elements for all of the +`org.apache.logging.log4j.core.appender.db.jpa.converter` converter +classes. + +[source,prettyprint,linenums,lang-xml] +---- + + + + + + + + + + + +---- + +[source,prettyprint,linenums,lang-xml] +---- + + + + + org.eclipse.persistence.jpa.PersistenceProvider + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter + org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter + com.example.logging.JpaLogEntity + jdbc/LoggingDataSource + NONE + + + +---- + +[source,prettyprint,linenums,lang-java] +---- +package com.example.logging; +... +@Entity +@Table(name="application_log", schema="dbo") +public class JpaLogEntity extends BasicLogEventEntity { + private static final long serialVersionUID = 1L; + private long id = 0L; + + public TestEntity() { + super(null); + } + public TestEntity(LogEvent wrappedEvent) { + super(wrappedEvent); + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + public long getId() { + return this.id; + } + + public void setId(long id) { + this.id = id; + } + + // If you want to override the mapping of any properties mapped in BasicLogEventEntity, + // just override the getters and re-specify the annotations. +} +---- + +[source,prettyprint,linenums,lang-java] +---- +package com.example.logging; +... +@Entity +@Table(name="application_log", schema="dbo") +public class JpaLogEntity extends AbstractLogEventWrapperEntity { + private static final long serialVersionUID = 1L; + private long id = 0L; + + public TestEntity() { + super(null); + } + public TestEntity(LogEvent wrappedEvent) { + super(wrappedEvent); + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "logEventId") + public long getId() { + return this.id; + } + + public void setId(long id) { + this.id = id; + } + + @Override + @Enumerated(EnumType.STRING) + @Column(name = "level") + public Level getLevel() { + return this.getWrappedEvent().getLevel(); + } + + @Override + @Column(name = "logger") + public String getLoggerName() { + return this.getWrappedEvent().getLoggerName(); + } + + @Override + @Column(name = "message") + @Convert(converter = MyMessageConverter.class) + public Message getMessage() { + return this.getWrappedEvent().getMessage(); + } + ... +} +---- + +[#HttpAppender] +== HttpAppender + +The HttpAppender sends log events over HTTP. A Layout must be provided +to format the LogEvent. + +Will set the `Content-Type` header according to the layout. Additional +headers can be specified with embedded Property elements. + +Will wait for response from server, and throw error if no 2xx response +is received. + +Implemented with +https://docs.oracle.com/javase/7/docs/api/java/net/HttpURLConnection.html[HttpURLConnection]. + +.HttpAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |The name of the Appender. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|layout |Layout |The Layout to use to format the LogEvent. + +|Ssl |SslConfiguration |Contains the configuration for the KeyStore and +TrustStore for https. Optional, uses Java runtime defaults if not +specified. See link:#SSL[SSL] + +|verifyHostname |boolean |Whether to verify server hostname against +certificate. Only valid for https. Optional, defaults to true + +|url |string |The URL to use. The URL scheme must be "http" or "https". + +|method |string |The HTTP method to use. Optional, default is "POST". + +|connectTimeoutMillis |integer |The connect timeout in milliseconds. +Optional, default is 0 (infinite timeout). + +|readTimeoutMillis |integer |The socket read timeout in milliseconds. +Optional, default is 0 (infinite timeout). + +|headers |Property[] |Additional HTTP headers to use. The values support +link:lookups.html[lookups]. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. +|======================================================================= + +Here is a sample HttpAppender configuration snippet: + +[source,prettyprint,linenums] +---- + + ... + + + + + + + + + + +---- + +[#KafkaAppender] +== KafkaAppender + +As of Log4j 2.11.0, https://kafka.apache.org/[Apache Kafka] support has +moved from the existing module `logj-core` to the new module +`log4j-kafka`. + +The KafkaAppender logs events to an https://kafka.apache.org/[Apache +Kafka] topic. Each log event is sent as a Kafka record. + +.KafkaAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|topic |String |The Kafka topic to use. Required. + +|key |String |The key that will be sent to Kafka with every message. +Optional value defaulting to `null`. Any of the +link:./lookups.html[Lookups]) can be included. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|layout |Layout |The Layout to use to format the LogEvent. Required, +there is no default. _New since 2.9, in previous versions was default._ + +|name |String |The name of the Appender. Required. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|syncSend |boolean |The default is `true`, causing sends to block until +the record has been acknowledged by the Kafka server. When set to +`false` sends return immediately, allowing for lower latency and +significantly higher throughput. _New since 2.8. Be aware that this is a +new addition, and it has not been extensively tested. Any failure +sending to Kafka will be reported as error to StatusLogger and the log +event will be dropped (the ignoreExceptions parameter will not be +effective). Log events may arrive out of order to the Kafka server._ + +|properties |Property[] |You can set properties in +http://kafka.apache.org/documentation.html#producerconfigs[Kafka +producer properties]. You need to set the `bootstrap.servers` property, +there are sensible default values for the others. Do not set the +`value.serializer` nor `key.serializer` properties. +|======================================================================= + +Here is a sample KafkaAppender configuration snippet: + +[source,prettyprint,linenums] +---- + + ... + + + + localhost:9092 + + +---- + +This appender is synchronous by default and will block until the record +has been acknowledged by the Kafka server, timeout for this can be set +with the `timeout.ms` property (defaults to 30 seconds). Wrap with +http://logging.apache.org/log4j/2.x/manual/appenders.html#AsyncAppender[Async +appender] and/or set syncSend to `false` to log asynchronously. + +This appender requires the http://kafka.apache.org/[Kafka client +library]. Note that you need to use a version of the Kafka client +library matching the Kafka server used. + +__Note:__Make sure to not let `org.apache.kafka` log to a Kafka appender +on DEBUG level, since that will cause recursive logging: + +[source,prettyprint,linenums] +---- + + ... + + + + + + +---- + +[#MemoryMappedFileAppender] +== MemoryMappedFileAppender + +_New since 2.1. Be aware that this is a new addition, and although it +has been tested on several platforms, it does not have as much track +record as the other file appenders._ + +The MemoryMappedFileAppender maps a part of the specified file into +memory and writes log events to this memory, relying on the operating +system's virtual memory manager to synchronize the changes to the +storage device. The main benefit of using memory mapped files is I/O +performance. Instead of making system calls to write to disk, this +appender can simply change the program's local memory, which is orders +of magnitude faster. Also, in most operating systems the memory region +mapped actually is the kernel's +http://en.wikipedia.org/wiki/Page_cache[page cache] (file cache), +meaning that no copies need to be created in user space. (TODO: +performance tests that compare performance of this appender to +RandomAccessFileAppender and FileAppender.) + +There is some overhead with mapping a file region into memory, +especially very large regions (half a gigabyte or more). The default +region size is 32 MB, which should strike a reasonable balance between +the frequency and the duration of remap operations. (TODO: performance +test remapping various sizes.) + +Similar to the FileAppender and the RandomAccessFileAppender, +MemoryMappedFileAppender uses a MemoryMappedFileManager to actually +perform the file I/O. While MemoryMappedFileAppender from different +Configurations cannot be shared, the MemoryMappedFileManagers can be if +the Manager is accessible. For example, two web applications in a +servlet container can have their own configuration and safely write to +the same file if Log4j is in a ClassLoader that is common to both of +them. + +.MemoryMappedFileAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filters |Filter |A Filter to determine if the event should be handled +by this Appender. More than one Filter may be used by using a +CompositeFilter. + +|immediateFlush |boolean a| +When set to true, each write will be followed by a call to +http://docs.oracle.com/javase/7/docs/api/java/nio/MappedByteBuffer.html#force()[MappedByteBuffer.force()]. +This will guarantee the data is written to the storage device. + +The default for this parameter is `false`. This means that the data is +written to the storage device even if the Java process crashes, but +there may be data loss if the operating system crashes. + +Note that manually forcing a sync on every log event loses most of the +performance benefits of using a memory mapped file. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is written +to disk but is more efficient. + +|regionLength |int |The length of the mapped region, defaults to 32 MB +(32 * 1024 * 1024 bytes). This parameter must be a value between 256 and +1,073,741,824 (1 GB or 2^30); values outside this range will be adjusted +to the closest valid value. Log4j will round the specified value up to +the nearest power of two. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. +|======================================================================= + +Here is a sample MemoryMappedFile configuration: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + +---- + +[#NoSQLAppender] +== NoSQLAppender + +The NoSQLAppender writes log events to a NoSQL database using an +internal lightweight provider interface. Provider implementations +currently exist for MongoDB and Apache CouchDB, and writing a custom +provider is quite simple. + +.NoSQLAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |_Required._ The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|bufferSize |int |If an integer greater than 0, this causes the appender +to buffer log events and flush whenever the buffer reaches this size. + +|NoSqlProvider |NoSQLProvider>> |_Required._ The NoSQL provider that provides +connections to the chosen NoSQL database. +|======================================================================= + +You specify which NoSQL provider to use by specifying the appropriate +configuration element within the `` element. The types currently +supported are `` and ``. To create your own custom +provider, read the JavaDoc for the `NoSQLProvider`, `NoSQLConnection`, +and `NoSQLObject` classes and the documentation about creating Log4j +plugins. We recommend you review the source code for the MongoDB and +CouchDB providers as a guide for creating your own provider. + +The following example demonstrates how log events are persisted in NoSQL +databases if represented in a JSON format: + +[source,prettyprint,lang-javascript] +---- +{ + "level": "WARN", + "loggerName": "com.example.application.MyClass", + "message": "Something happened that you might want to know about.", + "source": { + "className": "com.example.application.MyClass", + "methodName": "exampleMethod", + "fileName": "MyClass.java", + "lineNumber": 81 + }, + "marker": { + "name": "SomeMarker", + "parent" { + "name": "SomeParentMarker" + } + }, + "threadName": "Thread-1", + "millis": 1368844166761, + "date": "2013-05-18T02:29:26.761Z", + "thrown": { + "type": "java.sql.SQLException", + "message": "Could not insert record. Connection lost.", + "stackTrace": [ + { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1049 }, + { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 }, + { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 }, + { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 } + ], + "cause": { + "type": "java.io.IOException", + "message": "Connection lost.", + "stackTrace": [ + { "className": "java.nio.channels.SocketChannel", "methodName": "write", "fileName": null, "lineNumber": -1 }, + { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1032 }, + { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 }, + { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 }, + { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 } + ] + } + }, + "contextMap": { + "ID": "86c3a497-4e67-4eed-9d6a-2e5797324d7b", + "username": "JohnDoe" + }, + "contextStack": [ + "topItem", + "anotherItem", + "bottomItem" + ] +} +---- + +[#NoSQLAppenderMongoDB] +== NoSQLAppenderMongoDB + +Starting with Log4 2.11.0, we provide two MongoDB modules: + +* `log4j-mongodb2` defines the configuration element +link:#NoSQLAppenderMongoDB2[`MongoDb2`] matching the MongoDB Driver +version 2. +* `log4j-mongodb3` defines the configuration element +link:#NoSQLAppenderMongoDB3[`MongoDb3`] matching the MongoDB Driver +version 3. + +We no longer provide the module `log4j-mongodb`. + +The module `log4j-mongodb2` aliases the old configuration element +`MongoDb` to link:#NoSQLAppenderMongoDB2[`MongoDb2`]. + +[#NoSQLAppenderMongoDB2] +== NoSQLAppenderMongoDB2 + +This section details specializations of the +link:#NoSQLAppender[NoSQLAppender] provider for MongoDB using the +MongoDB driver version 2. The NoSQLAppender Appender writes log events +to a NoSQL database using an internal lightweight provider interface. + +.MongoDB2 Provider Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|collectionName |String |_Required._ The name of the MongoDB collection +to insert the events into. + +|writeConcernConstant |Field |By default, the MongoDB provider inserts +records with the instructions `com.mongodb.WriteConcern.ACKNOWLEDGED`. +Use this optional attribute to specify the name of a constant other than +`ACKNOWLEDGED`. + +|writeConcernConstantClass |Class |If you specify +`writeConcernConstant`, you can use this attribute to specify a class +other than `com.mongodb.WriteConcern` to find the constant on (to create +your own custom instructions). + +|factoryClassName |Class |To provide a connection to the MongoDB +database, you can use this attribute and `factoryMethodName` to specify +a class and static method to get the connection from. The method must +return a `com.mongodb.DB` or a `com.mongodb.MongoClient`. If the `DB` is +not authenticated, you must also specify a `username` and `password`. If +you use the factory method for providing a connection, you must not +specify the `databaseName`, `server`, or `port` attributes. + +|factoryMethodName |Method |See the documentation for attribute +`factoryClassName`. + +|databaseName |String |If you do not specify a `factoryClassName` and +`factoryMethodName` for providing a MongoDB connection, you must specify +a MongoDB database name using this attribute. You must also specify a +`username` and `password`. You can optionally also specify a `server` +(defaults to localhost), and a `port` (defaults to the default MongoDB +port). + +|server |String |See the documentation for attribute `databaseName`. + +|port |int |See the documentation for attribute `databaseName`. + +|username |String |See the documentation for attributes `databaseName` +and `factoryClassName`. + +|password |String |See the documentation for attributes `databaseName` +and `factoryClassName`. + +|capped |boolean |Enable support for +https://docs.mongodb.com/manual/core/capped-collections/[capped +collections] + +|collectionSize |int |Specify the size in bytes of the capped collection +to use if enabled. The minimum size is 4096 bytes, and larger sizes will +be increased to the nearest integer multiple of 256. See the capped +collection documentation linked above for more information. +|======================================================================= + +This appender is link:messages.html#MapMessage[MapMessage]-aware. + +Here are a few sample configurations for the NoSQLAppender and MongoDB2 +provider: + +[source,xml] +---- + + + + + + + + + + + + + +---- + +[source,xml] +---- + + + + + + + + + + + + + +---- + +Starting in Log4j version 2.11.0, the provider element name is +`MongoDb2`. The name `MongoDb` is now a deprecated alias for `MongoDb2`. + +[#NoSQLAppenderMongoDB3] +== NoSQLAppenderMongoDB3 + +This section details specializations of the +link:#NoSQLAppender[NoSQLAppender] provider for MongoDB using the +MongoDB driver version 3. The NoSQLAppender Appender writes log events +to a NoSQL database using an internal lightweight provider interface. + +.MongoDB3 Provider Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|collectionName |String |_Required._ The name of the MongoDB collection +to insert the events into. + +|writeConcernConstant |Field |By default, the MongoDB provider inserts +records with the instructions `com.mongodb.WriteConcern.ACKNOWLEDGED`. +Use this optional attribute to specify the name of a constant other than +`ACKNOWLEDGED`. + +|writeConcernConstantClass |Class |If you specify +`writeConcernConstant`, you can use this attribute to specify a class +other than `com.mongodb.WriteConcern` to find the constant on (to create +your own custom instructions). + +|factoryClassName |Class |To provide a connection to the MongoDB +database, you can use this attribute and `factoryMethodName` to specify +a class and static method to get the connection from. The method must +return a `com.mongodb.client.MongoDatabase` or a +`com.mongodb.MongoClient`. If the `com.mongodb.client.MongoDatabase` is +not authenticated, you must also specify a `username` and `password`. If +you use the factory method for providing a connection, you must not +specify the `databaseName`, `server`, or `port` attributes. + +|factoryMethodName |Method |See the documentation for attribute +`factoryClassName`. + +|databaseName |String |If you do not specify a `factoryClassName` and +`factoryMethodName` for providing a MongoDB connection, you must specify +a MongoDB database name using this attribute. You must also specify a +`username` and `password`. You can optionally also specify a `server` +(defaults to localhost), and a `port` (defaults to the default MongoDB +port). + +|server |String |See the documentation for attribute `databaseName`. + +|port |int |See the documentation for attribute `databaseName`. + +|username |String |See the documentation for attributes `databaseName` +and `factoryClassName`. + +|password |String |See the documentation for attributes `databaseName` +and `factoryClassName`. + +|capped |boolean |Enable support for +https://docs.mongodb.com/manual/core/capped-collections/[capped +collections] + +|collectionSize |int |Specify the size in bytes of the capped collection +to use if enabled. The minimum size is 4096 bytes, and larger sizes will +be increased to the nearest integer multiple of 256. See the capped +collection documentation linked above for more information. +|======================================================================= + +This appender is link:messages.html#MapMessage[MapMessage]-aware. + +Here are a few sample configurations for the NoSQLAppender and MongoDB3 +provider: + +[source,xml] +---- + + + + + + + + + + + + + +---- + +[source,xml] +---- + + + + + + + + + + + + + +---- + +[#NoSQLAppenderCouchDB] +== NoSQLAppenderCouchDB + +This section details specializations of the +link:#NoSQLAppender[NoSQLAppender] provider for CouchDB. The +NoSQLAppender writes log events to a NoSQL database using an internal +lightweight provider interface. + +.CouchDB Provider Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|factoryClassName |Class |To provide a connection to the CouchDB +database, you can use this attribute and `factoryMethodName` to specify +a class and static method to get the connection from. The method must +return a `org.lightcouch.CouchDbClient` or a +`org.lightcouch.CouchDbProperties`. If you use the factory method for +providing a connection, you must not specify the `databaseName`, +`protocol`, `server`, `port`, `username`, or `password` attributes. + +|factoryMethodName |Method |See the documentation for attribute +`factoryClassName`. + +|databaseName |String |If you do not specify a `factoryClassName` and +`factoryMethodName` for providing a CouchDB connection, you must specify +a CouchDB database name using this attribute. You must also specify a +`username` and `password`. You can optionally also specify a `protocol` +(defaults to http), `server` (defaults to localhost), and a `port` +(defaults to 80 for http and 443 for https). + +|protocol |String |Must either be "http" or "https." See the +documentation for attribute `databaseName`. + +|server |String |See the documentation for attribute `databaseName`. + +|port |int |See the documentation for attribute `databaseName`. + +|username |String |See the documentation for attributes `databaseName`. + +|password |String |See the documentation for attributes `databaseName`. +|======================================================================= + +Here are a few sample configurations for the NoSQLAppender and CouchDB +provider: + +[source,prettyprint,linenums,lang-xml] +---- + + + + + + + + + + + + + +---- + +[#OutputStreamAppender] +== OutputStreamAppender + +The OutputStreamAppender provides the base for many of the other +Appenders such as the File and Socket appenders that write the event to +an Output Stream. It cannot be directly configured. Support for +immediateFlush and buffering is provided by the OutputStreamAppender. +The OutputStreamAppender uses an OutputStreamManager to handle the +actual I/O, allowing the stream to be shared by Appenders in multiple +configurations. + +[#RandomAccessFileAppender] +== RandomAccessFileAppender + +The RandomAccessFileAppender is similar to the standard +link:#FileAppender[FileAppender] except it is always buffered (this +cannot be switched off) and internally it uses a +`ByteBuffer + RandomAccessFile` instead of a `BufferedOutputStream`. We +saw a 20-200% performance improvement compared to FileAppender with +"bufferedIO=true" in our +link:../performance.html#whichAppender[measurements]. Similar to the +FileAppender, RandomAccessFileAppender uses a RandomAccessFileManager to +actually perform the file I/O. While RandomAccessFileAppender from +different Configurations cannot be shared, the RandomAccessFileManagers +can be if the Manager is accessible. For example, two web applications +in a servlet container can have their own configuration and safely write +to the same file if Log4j is in a ClassLoader that is common to both of +them. + +.RandomAccessFileAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filters |Filter |A Filter to determine if the event should be handled +by this Appender. More than one Filter may be used by using a +CompositeFilter. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee the data is written to disk but could impact +performance. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is written +to disk but is more efficient. + +|bufferSize |int |The buffer size, defaults to 262,144 bytes (256 * +1024). + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. +|======================================================================= + +Here is a sample RandomAccessFile configuration: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + +---- + +[#RewriteAppender] +== RewriteAppender + +The RewriteAppender allows the LogEvent to manipulated before it is +processed by another Appender. This can be used to mask sensitive +information such as passwords or to inject information into each event. +The RewriteAppender must be configured with a RewritePolicy. The +RewriteAppender should be configured after any Appenders it references +to allow it to shut down properly. + +.RewriteAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|AppenderRef |String |The name of the Appenders to call after the +LogEvent has been manipulated. Multiple AppenderRef elements can be +configured. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|name |String |The name of the Appender. + +|rewritePolicy |RewritePolicy |The RewritePolicy that will manipulate +the LogEvent. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. +|======================================================================= + +[#RewritePolicy] +===== RewritePolicy + +RewritePolicy is an interface that allows implementations to inspect and +possibly modify LogEvents before they are passed to Appender. +RewritePolicy declares a single method named rewrite that must be +implemented. The method is passed the LogEvent and can return the same +event or create a new one. + +MapRewritePolicy + +MapRewritePolicy will evaluate LogEvents that contain a MapMessage and +will add or update elements of the Map. + +[cols=",,",options="header",] +|================================================================ +|Parameter Name |Type |Description +|mode |String |"Add" or "Update" +|keyValuePair |KeyValuePair[] |An array of keys and their values. +|================================================================ + +The following configuration shows a RewriteAppender configured to add a +product key and its value to the MapMessage.: + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + + + + + + + +---- + +PropertiesRewritePolicy + +PropertiesRewritePolicy will add properties configured on the policy to +the ThreadContext Map being logged. The properties will not be added to +the actual ThreadContext Map. The property values may contain variables +that will be evaluated when the configuration is processed as well as +when the event is logged. + +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|properties |Property[] |One of more Property elements to define the +keys and values to be added to the ThreadContext Map. +|======================================================================= + +The following configuration shows a RewriteAppender configured to add a +product key and its value to the MapMessage: + +[source,prettyprint,linenums] +---- + + + + + + + + + + ${sys:user.name} + ${sys:environment} + + + + + + + + + +---- + +LoggerNameLevelRewritePolicy + +You can use this policy to make loggers in third party code less chatty +by changing event levels. The LoggerNameLevelRewritePolicy will rewrite +log event levels for a given logger name prefix. You configure a +LoggerNameLevelRewritePolicy with a logger name prefix and a pairs of +levels, where a pair defines a source level and a target level. + +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|logger |String |A logger name used as a prefix to test each event's +logger name. + +|LevelPair |KeyValuePair[] |An array of keys and their values, each key +is a source level, each value a target level. +|======================================================================= + +The following configuration shows a RewriteAppender configured to map +level INFO to DEBUG and level WARN to INFO for all loggers that start +with `com.foo.bar`. + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + + + + + + + + +---- + +[#RollingFileAppender] +== RollingFileAppender + +The RollingFileAppender is an OutputStreamAppender that writes to the +File named in the fileName parameter and rolls the file over according +the TriggeringPolicy and the RolloverPolicy. The RollingFileAppender +uses a RollingFileManager (which extends OutputStreamManager) to +actually perform the file I/O and perform the rollover. While +RolloverFileAppenders from different Configurations cannot be shared, +the RollingFileManagers can be if the Manager is accessible. For +example, two web applications in a servlet container can have their own +configuration and safely write to the same file if Log4j is in a +ClassLoader that is common to both of them. + +A RollingFileAppender requires a +link:#TriggeringPolicies[TriggeringPolicy] and a +link:#RolloverStrategies[RolloverStrategy]. The triggering policy +determines if a rollover should be performed while the RolloverStrategy +defines how the rollover should be done. If no RolloverStrategy is +configured, RollingFileAppender will use the +link:#DefaultRolloverStrategy[DefaultRolloverStrategy]. Since log4j-2.5, +a link:#CustomDeleteOnRollover[custom delete action] can be configured +in the DefaultRolloverStrategy to run at rollover. Since 2.8 if no file +name is configured then +link:#DirectWriteRolloverStrategy[DirectWriteRolloverStrategy] will be +used instead of DefaultRolloverStrategy. Since log4j-2.9, a +link:#CustomPosixViewAttributeOnRollover[custom POSIX file attribute +view action] can be configured in the DefaultRolloverStrategy to run at +rollover, if not defined, inherited POSIX file attribute view from the +RollingFileAppender will be applied. + +File locking is not supported by the RollingFileAppender. + +.RollingFileAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|bufferedIO |boolean |When true - the default, records will be written +to a buffer and the data will be written to disk when the buffer is full +or, if immediateFlush is set, when the record is written. File locking +cannot be used with bufferedIO. Performance tests have shown that using +buffered I/O significantly improves performance, even if immediateFlush +is enabled. + +|bufferSize |int |When bufferedIO is true, this is the buffer size, the +default is 8192 bytes. + +|createOnDemand |boolean |The appender creates the file on-demand. The +appender only creates the file when a log event passes all filters and +is routed to this appender. Defaults to false. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filePattern |String |The pattern of the file name of the archived log +file. The format of the pattern is dependent on the RolloverPolicy that +is used. The DefaultRolloverPolicy will accept both a date/time pattern +compatible with +https://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html[`SimpleDateFormat`] +and/or a %i which represents an integer counter. The pattern also +supports interpolation at runtime so any of the Lookups (such as the +link:./lookups.html#DateLookup[DateLookup]) can be included in the +pattern. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee the data is written to disk but could impact +performance. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is written +to disk but is more efficient. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|policy |TriggeringPolicy |The policy to use to determine if a rollover +should occur. + +|strategy |RolloverStrategy |The strategy to use to determine the name +and location of the archive file. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|filePermissions |String a| +File attribute permissions in POSIX format to apply whenever the file is +created. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +Examples: rw------- or rw-rw-rw- etc... + +|fileOwner |String a| +File owner to define whenever the file is created. + +Changing file's owner may be restricted for security reason and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +Underlying files system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[owner] +attribute view. + +|fileGroup |String a| +File group to define whenever the file is created. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +|======================================================================= + +[#TriggeringPolicies] +== TriggeringPolicies + +[#Triggering] +===== Triggering Policies + +Composite Triggering Policy + +The `CompositeTriggeringPolicy` combines multiple triggering policies +and returns true if any of the configured policies return true. The +`CompositeTriggeringPolicy` is configured simply by wrapping other +policies in a `Policies` element. + +For example, the following XML fragment defines policies that rollover +the log when the JVM starts, when the log size reaches twenty megabytes, +and when the current date no longer matches the log’s start date. + +[source,prettyprint,linenums] +---- + + + + + +---- + +Cron Triggering Policy + +The `CronTriggeringPolicy` triggers rollover based on a cron expression. + +.CronTriggeringPolicy Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|schedule |String |The cron expression. The expression is the same as +what is allowed in the Quartz scheduler. See +link:../log4j-core/apidocs/org/apache/logging/log4j/core/util/CronExpression.html[CronExpression] +for a full description of the expression. + +|evaluateOnStartup |boolean |On startup the cron expression will be +evaluated against the file's last modification timestamp. If the cron +expression indicates a rollover should have occurred between that time +and the current time the file will be immediately rolled over. +|======================================================================= + +OnStartup Triggering Policy + +The `OnStartupTriggeringPolicy` policy causes a rollover if the log file +is older than the current JVM's start time and the minimum file size is +met or exceeded. + +.OnStartupTriggeringPolicy Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|minSize |long |The minimum size the file must have to roll over. A size +of zero will cause a roll over no matter what the file size is. The +default value is 1, which will prevent rolling over an empty file. +|======================================================================= + +_Google App Engine note:_ + +When running in Google App Engine, the OnStartup policy causes a +rollover if the log file is older than _the time when Log4J +initialized_. (Google App Engine restricts access to certain classes so +Log4J cannot determine JVM start time with +`java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime()` +and falls back to Log4J initialization time instead.) + +SizeBased Triggering Policy + +The `SizeBasedTriggeringPolicy` causes a rollover once the file has +reached the specified size. The size can be specified in bytes, with the +suffix KB, MB or GB, for example `20MB`. + +TimeBased Triggering Policy + +The `TimeBasedTriggeringPolicy` causes a rollover once the date/time +pattern no longer applies to the active file. This policy accepts an +`interval` attribute which indicates how frequently the rollover should +occur based on the time pattern and a `modulate` boolean attribute. + +.TimeBasedTriggeringPolicy Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|interval |integer |How often a rollover should occur based on the most +specific time unit in the date pattern. For example, with a date pattern +with hours as the most specific item and and increment of 4 rollovers +would occur every 4 hours. The default value is 1. + +|modulate |boolean |Indicates whether the interval should be adjusted to +cause the next rollover to occur on the interval boundary. For example, +if the item is hours, the current hour is 3 am and the interval is 4 +then the first rollover will occur at 4 am and then next ones will occur +at 8 am, noon, 4pm, etc. + +|maxRandomDelay |integer |Indicates the maximum number of seconds to +randomly delay a rollover. By default, this is 0 which indicates no +delay. This setting is useful on servers where multiple applications are +configured to rollover log files at the same time and can spread the +load of doing so across time. +|======================================================================= + +[#RolloverStrategies] +== RolloverStrategies + +[#Rollover] +===== Rollover Strategies + +[#DefaultRolloverStrategy] +== DefaultRolloverStrategy + +Default Rollover Strategy + +The default rollover strategy accepts both a date/time pattern and an +integer from the filePattern attribute specified on the +RollingFileAppender itself. If the date/time pattern is present it will +be replaced with the current date and time values. If the pattern +contains an integer it will be incremented on each rollover. If the +pattern contains both a date/time and integer in the pattern the integer +will be incremented until the result of the date/time pattern changes. +If the file pattern ends with ".gz", ".zip", ".bz2", ".deflate", +".pack200", or ".xz" the resulting archive will be compressed using the +compression scheme that matches the suffix. The formats bzip2, Deflate, +Pack200 and XZ require +http://commons.apache.org/proper/commons-compress/[Apache Commons +Compress]. In addition, XZ requires http://tukaani.org/xz/java.html[XZ +for Java]. The pattern may also contain lookup references that can be +resolved at runtime such as is shown in the example below. + +The default rollover strategy supports three variations for incrementing +the counter. The first is the "fixed window" strategy. To illustrate how +it works, suppose that the min attribute is set to 1, the max attribute +is set to 3, the file name is "foo.log", and the file name pattern is +"foo-%i.log". + +[cols=",,,",options="header",] +|======================================================================= +|Number of rollovers |Active output target |Archived log files +|Description +|0 |foo.log |- |All logging is going to the initial file. + +|1 |foo.log |foo-1.log |During the first rollover foo.log is renamed to +foo-1.log. A new foo.log file is created and starts being written to. + +|2 |foo.log |foo-1.log, foo-2.log |During the second rollover foo-1.log +is renamed to foo-2.log and foo.log is renamed to foo-1.log. A new +foo.log file is created and starts being written to. + +|3 |foo.log |foo-1.log, foo-2.log, foo-3.log |During the third rollover +foo-2.log is renamed to foo-3.log, foo-1.log is renamed to foo-2.log and +foo.log is renamed to foo-1.log. A new foo.log file is created and +starts being written to. + +|4 |foo.log |foo-1.log, foo-2.log, foo-3.log |In the fourth and +subsequent rollovers, foo-3.log is deleted, foo-2.log is renamed to +foo-3.log, foo-1.log is renamed to foo-2.log and foo.log is renamed to +foo-1.log. A new foo.log file is created and starts being written to. +|======================================================================= + +By way of contrast, when the fileIndex attribute is set to "max" but all +the other settings are the same the following actions will be performed. + +[cols=",,,",options="header",] +|======================================================================= +|Number of rollovers |Active output target |Archived log files +|Description +|0 |foo.log |- |All logging is going to the initial file. + +|1 |foo.log |foo-1.log |During the first rollover foo.log is renamed to +foo-1.log. A new foo.log file is created and starts being written to. + +|2 |foo.log |foo-1.log, foo-2.log |During the second rollover foo.log is +renamed to foo-2.log. A new foo.log file is created and starts being +written to. + +|3 |foo.log |foo-1.log, foo-2.log, foo-3.log |During the third rollover +foo.log is renamed to foo-3.log. A new foo.log file is created and +starts being written to. + +|4 |foo.log |foo-1.log, foo-2.log, foo-3.log |In the fourth and +subsequent rollovers, foo-1.log is deleted, foo-2.log is renamed to +foo-1.log, foo-3.log is renamed to foo-2.log and foo.log is renamed to +foo-3.log. A new foo.log file is created and starts being written to. +|======================================================================= + +Finally, as of release 2.8, if the fileIndex attribute is set to "nomax" +then the min and max values will be ignored and file numbering will +increment by 1 and each rollover will have an incrementally higher value +with no maximum number of files. + +.DefaultRolloverStrategy Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|fileIndex |String |If set to "max" (the default), files with a higher +index will be newer than files with a smaller index. If set to "min", +file renaming and the counter will follow the Fixed Window strategy +described above. + +|min |integer |The minimum value of the counter. The default value is 1. + +|max |integer |The maximum value of the counter. Once this values is +reached older archives will be deleted on subsequent rollovers. The +default value is 7. + +|compressionLevel |integer |Sets the compression level, 0-9, where 0 = +none, 1 = best speed, through 9 = best compression. Only implemented for +ZIP files. + +|tempCompressedFilePattern |String |The pattern of the file name of the +archived log file during compression. +|======================================================================= + +[#DirectWriteRolloverStrategy] +== DirectWriteRolloverStrategy + +DirectWrite Rollover Strategy + +The DirectWriteRolloverStrategy causes log events to be written directly +to files represented by the file pattern. With this strategy file +renames are not performed. If the size-based triggering policy causes +multiple files to be written durring the specified time period they will +be numbered starting at one and continually incremented until a +time-based rollover occurs. + +Warning: If the file pattern has a suffix indicating compression should +take place the current file will not be compressed when the application +is shut down. Furthermore, if the time changes such that the file +pattern no longer matches the current file it will not be compressed at +startup either. + +.DirectWriteRolloverStrategy Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|maxFiles |String |The maximum number of files to allow in the time +period matching the file pattern. If the number of files is exceeded the +oldest file will be deleted. If specified, the value must be greater +than 1. If the value is less than zero or omitted then the number of +files will not be limited. + +|compressionLevel |integer |Sets the compression level, 0-9, where 0 = +none, 1 = best speed, through 9 = best compression. Only implemented for +ZIP files. + +|tempCompressedFilePattern |String |The pattern of the file name of the +archived log file during compression. +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender with +both the time and size based triggering policies, will create up to 7 +archives on the same day (1-7) that are stored in a directory based on +the current year and month, and will compress each archive using gzip: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This second example shows a rollover strategy that will keep up to 20 +files before removing them. + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + +---- + +Below is a sample configuration that uses a RollingFileAppender with +both the time and size based triggering policies, will create up to 7 +archives on the same day (1-7) that are stored in a directory based on +the current year and month, and will compress each archive using gzip +and will roll every 6 hours when the hour is divisible by 6: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This sample configuration uses a RollingFileAppender with both the cron +and size based triggering policies, and writes directly to an unlimited +number of archive files. The cron trigger causes a rollover every hour +while the file size is limited to 250MB: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This sample configuration is the same as the previous but limits the +number of files saved each hour to 10: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + +---- + +[#CustomDeleteOnRollover] +== CustomDeleteOnRollover + +Log Archive Retention Policy: Delete on Rollover + +Log4j-2.5 introduces a `Delete` action that gives users more control +over what files are deleted at rollover time than what was possible with +the DefaultRolloverStrategy `max` attribute. The Delete action lets +users configure one or more conditions that select the files to delete +relative to a base directory. + +Note that it is possible to delete any file, not just rolled over log +files, so use this action with care! With the `testMode` parameter you +can test your configuration without accidentally deleting the wrong +files. + +.Delete Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|basePath |String |_Required._ Base path from where to start scanning +for files to delete. + +|maxDepth |int |The maximum number of levels of directories to visit. A +value of 0 means that only the starting file (the base path itself) is +visited, unless denied by the security manager. A value of +Integer.MAX_VALUE indicates that all levels should be visited. The +default is 1, meaning only the files in the specified base directory. + +|followLinks |boolean |Whether to follow symbolic links. Default is +false. + +|testMode |boolean |If true, files are not deleted but instead a message +is printed to the link:configuration.html#StatusMessages[status logger] +at INFO level. Use this to do a dry run to test if the configuration +works as expected. Default is false. + +|pathSorter |PathSorter |A plugin implementing the +link:../log4j-core/apidocs/org/apache/logging/log4j/core/appender/rolling/action/PathSorter.html[PathSorter] +interface to sort the files before selecting the files to delete. The +default is to sort most recently modified files first. + +|pathConditions [[DeletePathCondition]] |PathCondition[] a| +_Required if no ScriptCondition is specified._ One or more PathCondition +elements. + +If more than one condition is specified, they all need to accept a path +before it is deleted. Conditions can be nested, in which case the inner +condition(s) are evaluated only if the outer condition accepts the path. +If conditions are not nested they may be evaluated in any order. + +Conditions can also be combined with the logical operators AND, OR and +NOT by using the `IfAll`, `IfAny` and `IfNot` composite conditions. + +Users can create custom conditions or use the built-in conditions: + +* link:#DeleteIfFileName[IfFileName] - accepts files whose path +(relative to the base path) matches a +https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[regular +expression] or a +https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)[glob]. +* link:#DeleteIfLastModified[IfLastModified] - accepts files that are as +old as or older than the specified +link:../log4j-core/apidocs/org/apache/logging/log4j/core/appender/rolling/action/Duration.html#parse(CharSequence)[duration]. +* link:#DeleteIfAccumulatedFileCount[IfAccumulatedFileCount] - accepts +paths after some count threshold is exceeded during the file tree walk. +* link:#DeleteIfAccumulatedFileSize[IfAccumulatedFileSize] - accepts +paths after the accumulated file size threshold is exceeded during the +file tree walk. +* IfAll - accepts a path if all nested conditions accept it (logical +AND). Nested conditions may be evaluated in any order. +* IfAny - accepts a path if one of the nested conditions accept it +(logical OR). Nested conditions may be evaluated in any order. +* IfNot - accepts a path if the nested condition does not accept it +(logical NOT). + +|scriptCondition [[DeleteScriptCondition]] |ScriptCondition a| +_Required if no PathConditions are specified._ A ScriptCondition element +specifying a script. + +The ScriptCondition should contain a link:#ScriptCondition[Script, +ScriptRef or ScriptFile] element that specifies the logic to be +executed. (See also the link:filters.html#Script[ScriptFilter] +documentation for more examples of configuring ScriptFiles and +ScriptRefs.) + +The script is passed a number of link:#ScriptParameters[parameters], +including a list of paths found under the base path (up to `maxDepth`) +and must return a list with the paths to delete. + +|======================================================================= + +[#DeleteIfFileName] +== DeleteIfFileName + +.IfFileName Condition Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|glob |String |_Required if regex not specified._ Matches the relative +path (relative to the base path) using a limited pattern language that +resembles regular expressions but with a +https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)[simpler +syntax]. + +|regex |String |_Required if glob not specified._ Matches the relative +path (relative to the base path) using a regular expression as defined +by the +https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[Pattern] +class. + +|nestedConditions |PathCondition[] |An optional set of nested +link:#DeletePathCondition[PathConditions]. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the path name matches). +|======================================================================= + +[#DeleteIfLastModified] +== DeleteIfLastModified + +.IfLastModified Condition Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|age |String |_Required._ Specifies a +link:../log4j-core/apidocs/org/apache/logging/log4j/core/appender/rolling/action/Duration.html#parse(CharSequence)[duration]. +The condition accepts files that are as old or older than the specified +duration. + +|nestedConditions |PathCondition[] |An optional set of nested +link:#DeletePathCondition[PathConditions]. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the file is old enough). +|======================================================================= + +[#DeleteIfAccumulatedFileCount] +== DeleteIfAccumulatedFileCount + +.IfAccumulatedFileCount Condition Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|exceeds |int |_Required._ The threshold count from which files will be +deleted. + +|nestedConditions |PathCondition[] |An optional set of nested +link:#DeletePathCondition[PathConditions]. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the threshold count has been exceeded). +|======================================================================= + +[#DeleteIfAccumulatedFileSize] +== DeleteIfAccumulatedFileSize + +.IfAccumulatedFileSize Condition Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|exceeds |String |_Required._ The threshold accumulated file size from +which files will be deleted. The size can be specified in bytes, with +the suffix KB, MB or GB, for example `20MB`. + +|nestedConditions |PathCondition[] |An optional set of nested +link:#DeletePathCondition[PathConditions]. If any nested conditions +exist they all need to accept the file before it is deleted. Nested +conditions are only evaluated if the outer condition accepts a file (if +the threshold accumulated file size has been exceeded). +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender with the +cron triggering policy configured to trigger every day at midnight. +Archives are stored in a directory based on the current year and month. +All files under the base directory that match the "*/app-*.log.gz" glob +and are 60 days old or older are deleted at rollover time. + +[source,prettyprint,linenums] +---- + + + + logs + + + + + + + + + + + + + + + + + + + +---- + +Below is a sample configuration that uses a RollingFileAppender with +both the time and size based triggering policies, will create up to 100 +archives on the same day (1-100) that are stored in a directory based on +the current year and month, and will compress each archive using gzip +and will roll every hour. During every rollover, this configuration will +delete files that match "*/app-*.log.gz" and are 30 days old or older, +but keep the most recent 100 GB or the most recent 10 files, whichever +comes first. + +[source,prettyprint,linenums] +---- + + + + logs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +[#ScriptCondition] +== ScriptCondition + +.ScriptCondition Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|script |Script, ScriptFile or ScriptRef |The Script element that +specifies the logic to be executed. The script is passed a list of paths +found under the base path and must return the paths to delete as a +`java.util.List`. See also the +link:filters.html#Script[ScriptFilter] documentation for an example of +how ScriptFiles and ScriptRefs can be configured. +|======================================================================= + +[#ScriptParameters] +== ScriptParameters + +.Script Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|basePath |`java.nio.file.Path` |The directory from where the Delete +action started scanning for files to delete. Can be used to relativize +the paths in the pathList. + +|pathList |`java.util.List` |The list of paths found +under the base path up to the specified max depth, sorted most recently +modified files first. The script is free to modify and return this list. + +|statusLogger |StatusLogger |The StatusLogger that can be used to log +internal events during script execution. + +|configuration |Configuration |The Configuration that owns this +ScriptCondition. + +|substitutor |StrSubstitutor |The StrSubstitutor used to replace lookup +variables. + +|? |String |Any properties declared in the configuration. +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender with the +cron triggering policy configured to trigger every day at midnight. +Archives are stored in a directory based on the current year and month. +The script returns a list of rolled over files under the base directory +dated Friday the 13th. The Delete action will delete all files returned +by the script. + +[source,prettyprint,linenums] +---- + + + + logs + + + + + + + + + + + + + + + + + + + + +---- + +[#CustomPosixViewAttributeOnRollover] +== CustomPosixViewAttributeOnRollover + +Log Archive File Attribute View Policy: Custom file attribute on +Rollover + +Log4j-2.9 introduces a `PosixViewAttribute` action that gives users more +control over which file attribute permissions, owner and group should be +applied. The PosixViewAttribute action lets users configure one or more +conditions that select the eligible files relative to a base directory. + +.PosixViewAttribute Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|basePath |String |_Required._ Base path from where to start scanning +for files to apply attributes. + +|maxDepth |int |The maximum number of levels of directories to visit. A +value of 0 means that only the starting file (the base path itself) is +visited, unless denied by the security manager. A value of +Integer.MAX_VALUE indicates that all levels should be visited. The +default is 1, meaning only the files in the specified base directory. + +|followLinks |boolean |Whether to follow symbolic links. Default is +false. + +|pathConditions |PathCondition[] |see +link:#DeletePathCondition[DeletePathCondition] + +|filePermissions |String a| +File attribute permissions in POSIX format to apply when action is +executed. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +Examples: rw------- or rw-rw-rw- etc... + +|fileOwner |String a| +File owner to define when action is executed. + +Changing file's owner may be restricted for security reason and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +Underlying files system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[owner] +attribute view. + +|fileGroup |String a| +File group to define whene action is executed. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +|======================================================================= + +Below is a sample configuration that uses a RollingFileAppender and +defines different POSIX file attribute view for current and rolled log +files. + +[source,prettyprint,linenums] +---- + + + + logs + + + + + + + + + + + + + + + + + + + + +---- + +[#RollingRandomAccessFileAppender] +== RollingRandomAccessFileAppender + +The RollingRandomAccessFileAppender is similar to the standard +link:#RollingFileAppender[RollingFileAppender] except it is always +buffered (this cannot be switched off) and internally it uses a +`ByteBuffer + RandomAccessFile` instead of a `BufferedOutputStream`. We +saw a 20-200% performance improvement compared to RollingFileAppender +with "bufferedIO=true" in our +link:../performance.html#whichAppender[measurements]. The +RollingRandomAccessFileAppender writes to the File named in the fileName +parameter and rolls the file over according the TriggeringPolicy and the +RolloverPolicy. Similar to the RollingFileAppender, +RollingRandomAccessFileAppender uses a RollingRandomAccessFileManager to +actually perform the file I/O and perform the rollover. While +RollingRandomAccessFileAppender from different Configurations cannot be +shared, the RollingRandomAccessFileManagers can be if the Manager is +accessible. For example, two web applications in a servlet container can +have their own configuration and safely write to the same file if Log4j +is in a ClassLoader that is common to both of them. + +A RollingRandomAccessFileAppender requires a +link:#TriggeringPolicies[TriggeringPolicy] and a +link:#RolloverStrategies[RolloverStrategy]. The triggering policy +determines if a rollover should be performed while the RolloverStrategy +defines how the rollover should be done. If no RolloverStrategy is +configured, RollingRandomAccessFileAppender will use the +link:#DefaultRolloverStrategy[DefaultRolloverStrategy]. Since log4j-2.5, +a link:#CustomDeleteOnRollover[custom delete action] can be configured +in the DefaultRolloverStrategy to run at rollover. + +File locking is not supported by the RollingRandomAccessFileAppender. + +.RollingRandomAccessFileAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|append |boolean |When true - the default, records will be appended to +the end of the file. When set to false, the file will be cleared before +new records are written. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|fileName |String |The name of the file to write to. If the file, or any +of its parent directories, do not exist, they will be created. + +|filePattern |String |The pattern of the file name of the archived log +file. The format of the pattern should is dependent on the +RolloverPolicy that is used. The DefaultRolloverPolicy will accept both +a date/time pattern compatible with +https://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html[`SimpleDateFormat`] +and/or a %i which represents an integer counter. The pattern also +supports interpolation at runtime so any of the Lookups (such as the +link:./lookups.html#DateLookup[DateLookup] can be included in the +pattern. + +|immediateFlush |boolean a| +When set to true - the default, each write will be followed by a flush. +This will guarantee the data is written to disk but could impact +performance. + +Flushing after every write is only useful when using this appender with +synchronous loggers. Asynchronous loggers and appenders will +automatically flush at the end of a batch of events, even if +immediateFlush is set to false. This also guarantees the data is written +to disk but is more efficient. + +|bufferSize |int |The buffer size, defaults to 262,144 bytes (256 * +1024). + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|name |String |The name of the Appender. + +|policy |TriggeringPolicy |The policy to use to determine if a rollover +should occur. + +|strategy |RolloverStrategy |The strategy to use to determine the name +and location of the archive file. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|filePermissions |String a| +File attribute permissions in POSIX format to apply whenever the file is +created. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +Examples: `rw-------` or `rw-rw-rw-` etc... + +|fileOwner |String a| +File owner to define whenever the file is created. + +Changing file's owner may be restricted for security reason and +Operation not permitted IOException thrown. Only processes with an +effective user ID equal to the user ID of the file or with appropriate +privileges may change the ownership of a file if +http://www.gnu.org/software/libc/manual/html_node/Options-for-Files.html[_POSIX_CHOWN_RESTRICTED] +is in effect for path. + +Underlying files system shall support file +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/FileOwnerAttributeView.html[owner] +attribute view. + +|fileGroup |String a| +File group to define whenever the file is created. + +Underlying files system shall support +https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/PosixFileAttributeView.html[POSIX] +file attribute view. + +|======================================================================= + +[#FRFA_TriggeringPolicies] +== FRFA_TriggeringPolicies + +[#Triggering] +===== Triggering Policies + +See link:#TriggeringPolicies[RollingFileAppender Triggering Policies]. + +[#FRFA_RolloverStrategies] +== FRFA_RolloverStrategies + +[#Rollover] +===== Rollover Strategies + +See link:#RolloverStrategies[RollingFileAppender Rollover Strategies]. + +Below is a sample configuration that uses a +RollingRandomAccessFileAppender with both the time and size based +triggering policies, will create up to 7 archives on the same day (1-7) +that are stored in a directory based on the current year and month, and +will compress each archive using gzip: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +This second example shows a rollover strategy that will keep up to 20 +files before removing them. + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + +---- + +Below is a sample configuration that uses a +RollingRandomAccessFileAppender with both the time and size based +triggering policies, will create up to 7 archives on the same day (1-7) +that are stored in a directory based on the current year and month, and +will compress each archive using gzip and will roll every 6 hours when +the hour is divisible by 6: + +[source,prettyprint,linenums] +---- + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + +---- + +[#RoutingAppender] +== RoutingAppender + +The RoutingAppender evaluates LogEvents and then routes them to a +subordinate Appender. The target Appender may be an appender previously +configured and may be referenced by its name or the Appender can be +dynamically created as needed. The RoutingAppender should be configured +after any Appenders it references to allow it to shut down properly. + +You can also configure a RoutingAppender with scripts: you can run a +script when the appender starts and when a route is chosen for an log +event. + +.RoutingAppender Parameters +[width="100%",cols="34%,33%,33%",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|Filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|name |String |The name of the Appender. + +|RewritePolicy |RewritePolicy |The RewritePolicy that will manipulate +the LogEvent. + +|Routes |Routes |Contains one or more Route declarations to identify the +criteria for choosing Appenders. + +|Script |Script a| +This Script runs when Log4j starts the RoutingAppender and returns a +String Route key to determine the default Route. + +This script is passed the following variables: + +.RoutingAppender Script Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|configuration |Configuration |The active Configuration. + +|staticVariables |Map |A Map shared between all script invocations for +this appender instance. This is the same map passed to the Routes +Script. +|======================================================================= + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. +|======================================================================= + +In this example, the script causes the "ServiceWindows" route to be the +default route on Windows and "ServiceOther" on all other operating +systems. Note that the List Appender is one of our test appenders, any +appender can be used, it is only used as a shorthand. + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + + + + + + + + + +---- + +[#Routes] +===== Routes + +The Routes element accepts a single attribute named "pattern". The +pattern is evaluated against all the registered Lookups and the result +is used to select a Route. Each Route may be configured with a key. If +the key matches the result of evaluating the pattern then that Route +will be selected. If no key is specified on a Route then that Route is +the default. Only one Route can be configured as the default. + +The Routes element may contain a Script child element. If specified, the +Script is run for each log event and returns the String Route key to +use. + +You must specify either the pattern attribute or the Script element, but +not both. + +Each Route must reference an Appender. If the Route contains a ref +attribute then the Route will reference an Appender that was defined in +the configuration. If the Route contains an Appender definition then an +Appender will be created within the context of the RoutingAppender and +will be reused each time a matching Appender name is referenced through +a Route. + +This script is passed the following variables: + +.RoutingAppender Routes Script Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|configuration |Configuration |The active Configuration. + +|staticVariables |Map |A Map shared between all script invocations for +this appender instance. This is the same map passed to the Routes +Script. + +|logEvent |LogEvent |The log event. +|======================================================================= + +In this example, the script runs for each log event and picks a route +based on the presence of a Marker named "AUDIT". + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + + +---- + +[#Purge] +===== Purge Policy + +The RoutingAppender can be configured with a PurgePolicy whose purpose +is to stop and remove dormant Appenders that have been dynamically +created by the RoutingAppender. Log4j currently provides the +IdlePurgePolicy as the only PurgePolicy available for cleaning up the +Appenders. The IdlePurgePolicy accepts 2 attributes; timeToLive, which +is the number of timeUnits the Appender should survive without having +any events sent to it, and timeUnit, the String representation of +java.util.concurrent.TimeUnit which is used with the timeToLive +attribute. + +Below is a sample configuration that uses a RoutingAppender to route all +Audit events to a FlumeAppender and all other events will be routed to a +RollingFileAppender that captures only the specific event type. Note +that the AuditAppender was predefined while the RollingFileAppenders are +created as needed. + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + + %d %p %c{1.} [%t] %m%n + + + + + + + + + + + + + + + +---- + +[#SMTPAppender] +== SMTPAppender + +As of Log4j 2.11.0, Simple Mail Transfer Protocol (SMTP) support has +moved from the existing module `logj-core` to the new module +`log4j-smtp`. + +Sends an e-mail when a specific logging event occurs, typically on +errors or fatal errors. + +The number of logging events delivered in this e-mail depend on the +value of *BufferSize* option. The `SMTPAppender` keeps only the last +`BufferSize` logging events in its cyclic buffer. This keeps memory +requirements at a reasonable level while still delivering useful +application context. All events in the buffer are included in the email. +The buffer will contain the most recent events of level TRACE to WARN +preceding the event that triggered the email. + +The default behavior is to trigger sending an email whenever an ERROR or +higher severity event is logged and to format it as HTML. The +circumstances on when the email is sent can be controlled by setting one +or more filters on the Appender. As with other Appenders, the formatting +can be controlled by specifying a Layout for the Appender. + +.SMTPAppender Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |The name of the Appender. + +|from |String |The email address of the sender. + +|replyTo |String |The comma-separated list of reply-to email addresses. + +|to |String |The comma-separated list of recipient email addresses. + +|cc |String |The comma-separated list of CC email addresses. + +|bcc |String |The comma-separated list of BCC email addresses. + +|subject |String |The subject of the email message. + +|bufferSize |integer |The maximum number of log events to be buffered +for inclusion in the message. Defaults to 512. + +|layout |Layout |The Layout to use to format the LogEvent. If no layout +is supplied link:layouts.html#HTMLLayout[HTML layout] will be used. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|smtpDebug |boolean |When set to true enables session debugging on +STDOUT. Defaults to false. + +|smtpHost |String |The SMTP hostname to send to. This parameter is +required. + +|smtpPassword |String |The password required to authenticate against the +SMTP server. + +|smtpPort |integer |The SMTP port to send to. + +|smtpProtocol |String |The SMTP transport protocol (such as "smtps", +defaults to "smtp"). + +|smtpUsername |String |The username required to authenticate against the +SMTP server. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. +|======================================================================= + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + +---- + +[#ScriptAppenderSelector] +== ScriptAppenderSelector + +When the configuration is built, the `ScriptAppenderSelector` appender +calls a `Script` to compute an appender name. Log4j then creates one of +the appender named listed under `AppenderSet` using the name of the +`ScriptAppenderSelector`. After configuration, Log4j ignores the +`ScriptAppenderSelector`. Log4j only builds the one selected appender +from the configuration tree, and ignores other `AppenderSet` child +nodes. + +In the following example, the script returns the name "List2". The +appender name is recorded under the name of the +`ScriptAppenderSelector`, not the name of the selected appender, in this +example, "SelectIt". + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + + + + +---- + +[#SocketAppender] +== SocketAppender + +The `SocketAppender` is an OutputStreamAppender that writes its output +to a remote destination specified by a host and port. The data can be +sent over either TCP or UDP and can be sent in any format. You can +optionally secure communication with link:#SSL[SSL]. + +.`SocketAppender` Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |The name of the Appender. + +|host |String |The name or address of the system that is listening for +log events. This parameter is required. + +|port |integer |The port on the host that is listening for log events. +This parameter must be specified. + +|protocol |String |"TCP" (default), "SSL" or "UDP". + +|SSL |SslConfiguration |Contains the configuration for the KeyStore and +TrustStore. See link:#SSL[SSL]. + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|immediateFail |boolean |When set to true, log events will not wait to +try to reconnect and will fail immediately if the socket is not +available. + +|immediateFlush |boolean |When set to true - the default, each write +will be followed by a flush. This will guarantee the data is written to +disk but could impact performance. + +|bufferedIO |boolean |When true - the default, events are written to a +buffer and the data will be written to the socket when the buffer is +full or, if immediateFlush is set, when the record is written. + +|bufferSize |int |When bufferedIO is true, this is the buffer size, the +default is 8192 bytes. + +|layout |Layout |The Layout to use to format the LogEvent. Required, +there is no default. _New since 2.9, in previous versions +SerializedLayout was default._ + +|reconnectionDelayMillis |integer |If set to a value greater than 0, +after an error the SocketManager will attempt to reconnect to the server +after waiting the specified number of milliseconds. If the reconnect +fails then an exception will be thrown (which can be caught by the +application if `ignoreExceptions` is set to `false`). + +|connectTimeoutMillis |integer |The connect timeout in milliseconds. The +default is 0 (infinite timeout, like Socket.connect() methods). + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. +|======================================================================= + +This is an unsecured TCP configuration: + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + +---- + +This is a secured link:#SSL[SSL] configuration: + +[source,prettyprint,linenums] +---- + + + + + + + + + + + + + + + + + +---- + +[#SSL] +== SSL + +Several appenders can be configured to use either a plain network +connection or a Secure Socket Layer (SSL) connection. This section +documents the parameters available for SSL configuration. + +.SSL Configuration Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|protocol |String |`SSL` if omitted. See also +http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext[Standard +names]. + +|KeyStore |KeyStore |Contains your private keys and certificates, and +determines which authentication credentials to send to the remote host. + +|TrustStore |TrustStore |Contains the CA certificates of the remote +counterparty. Determines whether the remote authentication credentials +(and thus the connection) should be trusted. +|======================================================================= + +[#KeyStore] +===== KeyStore + +The keystore is meant to contain your private keys and certificates, and +determines which authentication credentials to send to the remote host. + +.KeyStore Configuration Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|location |String |Path to the keystore file. + +|password |char[] |Plain text password to access the keystore. Cannot be +combined with either `passwordEnvironmentVariable` or `passwordFile`. + +|passwordEnvironmentVariable |String |Name of an environment variable +that holds the password. Cannot be combined with either `password` or +`passwordFile`. + +|passwordFile |String |Path to a file that holds the password. Cannot be +combined with either `password` or `passwordEnvironmentVariable`. + +|type |String |Optional KeyStore type, e.g. `JKS`, `PKCS12`, `PKCS11`, +`BKS`, `Windows-MY/Windows-ROOT`, `KeychainStore`, etc. The default is +JKS. See also +http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore[Standard +types]. + +|keyManagerFactoryAlgorithm |String |Optional KeyManagerFactory +algorithm. The default is `SunX509`. See also +http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyManagerFactory[Standard +algorithms]. +|======================================================================= + +[#TrustStore] +===== TrustStore + +The trust store is meant to contain the CA certificates you are willing +to trust when a remote party presents its certificate. Determines +whether the remote authentication credentials (and thus the connection) +should be trusted. + +In some cases, they can be one and the same store, although it is often +better practice to use distinct stores (especially when they are +file-based). + +.TrustStore Configuration Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|location |String |Path to the keystore file. + +|password |char[] |Plain text password to access the keystore. Cannot be +combined with either `passwordEnvironmentVariable` or `passwordFile`. + +|passwordEnvironmentVariable |String |Name of an environment variable +that holds the password. Cannot be combined with either `password` or +`passwordFile`. + +|passwordFile |String |Path to a file that holds the password. Cannot be +combined with either `password` or `passwordEnvironmentVariable`. + +|type |String |Optional KeyStore type, e.g. `JKS`, `PKCS12`, `PKCS11`, +`BKS`, `Windows-MY/Windows-ROOT`, `KeychainStore`, etc. The default is +JKS. See also +http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore[Standard +types]. + +|trustManagerFactoryAlgorithm |String |Optional TrustManagerFactory +algorithm. The default is `SunX509`. See also +http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#TrustManagerFactory[Standard +algorithms]. +|======================================================================= + +[#Example] +===== Example + +[source,prettyprint,linenums] +---- + ... + + + + + ... +---- + +[#SyslogAppender] +== SyslogAppender + +The `SyslogAppender` is a `SocketAppender` that writes its output to a +remote destination specified by a host and port in a format that +conforms with either the BSD Syslog format or the RFC 5424 format. The +data can be sent over either TCP or UDP. + +.`SyslogAppender` Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|advertise |boolean |Indicates whether the appender should be +advertised. + +|appName |String |The value to use as the APP-NAME in the RFC 5424 +syslog record. + +|charset |String |The character set to use when converting the syslog +String to a byte array. The String must be a valid +https://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html[`Charset`]. +If not specified, the default system Charset will be used. + +|connectTimeoutMillis |integer |The connect timeout in milliseconds. The +default is 0 (infinite timeout, like Socket.connect() methods). + +|enterpriseNumber |integer |The IANA enterprise number as described in +http://tools.ietf.org/html/rfc5424#section-7.2.2[RFC 5424] + +|filter |Filter |A Filter to determine if the event should be handled by +this Appender. More than one Filter may be used by using a +CompositeFilter. + +|facility |String |The facility is used to try to classify the message. +The facility option must be set to one of "KERN", "USER", "MAIL", +"DAEMON", "AUTH", "SYSLOG", "LPR", "NEWS", "UUCP", "CRON", "AUTHPRIV", +"FTP", "NTP", "AUDIT", "ALERT", "CLOCK", "LOCAL0", "LOCAL1", "LOCAL2", +"LOCAL3", "LOCAL4", "LOCAL5", "LOCAL6", or "LOCAL7". These values may be +specified as upper or lower case characters. + +|format |String |If set to "RFC5424" the data will be formatted in +accordance with RFC 5424. Otherwise, it will be formatted as a BSD +Syslog record. Note that although BSD Syslog records are required to be +1024 bytes or shorter the SyslogLayout does not truncate them. The +RFC5424Layout also does not truncate records since the receiver must +accept records of up to 2048 bytes and may accept records that are +longer. + +|host |String |The name or address of the system that is listening for +log events. This parameter is required. + +|id |String |The default structured data id to use when formatting +according to RFC 5424. If the LogEvent contains a StructuredDataMessage +the id from the Message will be used instead of this value. + +|ignoreExceptions |boolean |The default is `true`, causing exceptions +encountered while appending events to be internally logged and then +ignored. When set to `false` exceptions will be propagated to the +caller, instead. You must set this to `false` when wrapping this +Appender in a link:#FailoverAppender[FailoverAppender]. + +|immediateFail |boolean |When set to true, log events will not wait to +try to reconnect and will fail immediately if the socket is not +available. + +|immediateFlush |boolean |When set to true - the default, each write +will be followed by a flush. This will guarantee the data is written to +disk but could impact performance. + +|includeMDC |boolean |Indicates whether data from the ThreadContextMap +will be included in the RFC 5424 Syslog record. Defaults to true. + +|Layout |Layout |A custom layout which overrides the `format` setting. + +|loggerFields |List of KeyValuePairs |Allows arbitrary PatternLayout +patterns to be included as specified ThreadContext fields; no default +specified. To use, include a >LoggerFields< nested element, containing +one or more >KeyValuePair< elements. Each >KeyValuePair< must have a key +attribute, which specifies the key name which will be used to identify +the field within the MDC Structured Data element, and a value attribute, +which specifies the PatternLayout pattern to use as the value. + +|mdcExcludes |String |A comma separated list of mdc keys that should be +excluded from the LogEvent. This is mutually exclusive with the +mdcIncludes attribute. This attribute only applies to RFC 5424 syslog +records. + +|mdcIncludes |String |A comma separated list of mdc keys that should be +included in the FlumeEvent. Any keys in the MDC not found in the list +will be excluded. This option is mutually exclusive with the mdcExcludes +attribute. This attribute only applies to RFC 5424 syslog records. + +|mdcRequired |String |A comma separated list of mdc keys that must be +present in the MDC. If a key is not present a LoggingException will be +thrown. This attribute only applies to RFC 5424 syslog records. + +|mdcPrefix |String |A string that should be prepended to each MDC key in +order to distinguish it from event attributes. The default string is +"mdc:". This attribute only applies to RFC 5424 syslog records. + +|messageId |String |The default value to be used in the MSGID field of +RFC 5424 syslog records. + +|name |String |The name of the Appender. + +|newLine |boolean |If true, a newline will be appended to the end of the +syslog record. The default is false. + +|port |integer |The port on the host that is listening for log events. +This parameter must be specified. + +|protocol |String |"TCP" or "UDP". This parameter is required. + +|SSL |SslConfiguration |Contains the configuration for the KeyStore and +TrustStore. See link:#SSL[SSL]. + +|reconnectionDelayMillis |integer |If set to a value greater than 0, +after an error the SocketManager will attempt to reconnect to the server +after waiting the specified number of milliseconds. If the reconnect +fails then an exception will be thrown (which can be caught by the +application if `ignoreExceptions` is set to `false`). +|======================================================================= + +A sample syslogAppender configuration that is configured with two +`SyslogAppender`s, one using the BSD format and one using RFC 5424. + +[source,xml] +---- + + + + + + + + + + + + + + + +---- + +For link:#SSL[SSL] this appender writes its output to a remote +destination specified by a host and port over SSL in a format that +conforms with either the BSD Syslog format or the RFC 5424 format. + +[source,xml] +---- + + + + + + + + + + + + + + + + +---- + +[#JeroMQAppender] +== JeroMQAppender + +As of Log4j 2.11.0, ZeroMQ/JeroMQ support has moved from the existing +module `logj-core` to the new module `log4j-jeromq`. + +The ZeroMQ appender uses the https://github.com/zeromq/jeromq[JeroMQ] +library to send log events to one or more ZeroMQ endpoints. + +This is a simple JeroMQ configuration: + +[source,xml] +---- + + + + + tcp://*:5556 + ipc://info-topic + + + + + + + + +---- + +The table below describes all options. Please consult the JeroMQ and +ZeroMQ documentation for details. + +.JeroMQ Parameters +[cols=",,",options="header",] +|======================================================================= +|Parameter Name |Type |Description +|name |String |The name of the Appender. Required. + +|Layout |layout |The Layout to use to format the LogEvent. If no layout +is supplied the default pattern layout of "%m%n" will be used. + +|Filters |Filter |The Filter(s) of the Appender. + +|Properties |Property[] |One or more Property elements, named +`endpoint`. + +|ignoreExceptions |boolean |If true, exceptions will be logged and +suppressed. If false errors will be logged and then passed to the +application. + +|affinity |long |The ZMQ_AFFINITY option. Defaults to 0. + +|backlog |long |The ZMQ_BACKLOG option. Defaults to 100. + +|delayAttachOnConnect |boolean |The ZMQ_DELAY_ATTACH_ON_CONNECT option. +Defaults to false. + +|identity |byte[] |The ZMQ_IDENTITY option. Defaults to none. + +|ipv4Only |boolean |The ZMQ_IPV4ONLY option. Defaults to true. + +|linger |long |The ZMQ_LINGER option. Defaults to -1. + +|maxMsgSize |long |The ZMQ_MAXMSGSIZE option. Defaults to -1. + +|rcvHwm |long |The ZMQ_RCVHWM option. Defaults to 1000. + +|receiveBufferSize |long |The ZMQ_RCVBUF option. Defaults to 0. + +|receiveTimeOut |int |The ZMQ_RCVTIMEO option. Defaults to -1. + +|reconnectIVL |long |The ZMQ_RECONNECT_IVL option. Defaults to 100. + +|reconnectIVLMax |long |The ZMQ_RECONNECT_IVL_MAX option. Defaults to 0. + +|sendBufferSize |long |The ZMQ_SNDBUF option. Defaults to 0. + +|sendTimeOut |int |The ZMQ_SNDTIMEO option. Defaults to -1. + +|sndHwm |long |The ZMQ_SNDHWM option. Defaults to 1000. + +|tcpKeepAlive |int |The ZMQ_TCP_KEEPALIVE option. Defaults to -1. + +|tcpKeepAliveCount |long |The ZMQ_TCP_KEEPALIVE_CNT option. Defaults to +-1. + +|tcpKeepAliveIdle |long |The ZMQ_TCP_KEEPALIVE_IDLE option. Defaults to +-1. + +|tcpKeepAliveInterval |long |The ZMQ_TCP_KEEPALIVE_INTVL option. +Defaults to -1. + +|xpubVerbose |boolean |The ZMQ_XPUB_VERBOSE option. Defaults to false. +|======================================================================= diff --git a/src/site/xdoc/manual/appenders.xml b/src/site/xdoc/manual/appenders.xml deleted file mode 100644 index caabe2dc6e7..00000000000 --- a/src/site/xdoc/manual/appenders.xml +++ /dev/null @@ -1,5400 +0,0 @@ - - - - - - Log4j 2 Appenders - Ralph Goers - Gary Gregory - Nick Williams - Matt SIcker - - - -
    -

    - Appenders are responsible for delivering LogEvents to their destination. Every Appender must - implement the Appender - interface. Most Appenders will extend - AbstractAppender - which adds Lifecycle - and Filterable - support. Lifecycle allows components to finish initialization after configuration has completed and to - perform cleanup during shutdown. Filterable allows the component to have Filters attached to it which are - evaluated during event processing. -

    -

    - Appenders usually are only responsible for writing the event data to the target destination. In most cases - they delegate responsibility for formatting the event to a layout. Some - appenders wrap other appenders so that they can modify the LogEvent, handle a failure in an Appender, - route the event to a subordinate Appender based on advanced Filter criteria or provide similar functionality - that does not directly format the event for viewing. -

    -

    - Appenders always have a name so that they can be referenced from Loggers. -

    -

    - In the tables below, the "Type" column corresponds to the Java type expected. For non-JDK classes, these - should usually be in Log4j Core unless otherwise noted. -

    - - -

    The AsyncAppender accepts references to other Appenders and causes LogEvents to be written to them - on a separate Thread. Note that exceptions while writing to those Appenders will be hidden from - the application. The AsyncAppender should be configured after the appenders it references to allow it - to shut down properly.

    -

    - By default, AsyncAppender uses - java.util.concurrent.ArrayBlockingQueue - which does not require any external libraries. Note that multi-threaded applications should exercise care - when using this appender as such: the blocking queue is susceptible to lock contention and our - tests showed - performance may become worse when more threads are logging concurrently. - Consider using lock-free Async Loggers for optimal performance. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AsyncAppender Parameters
    Parameter NameTypeDescription
    AppenderRefStringThe name of the Appenders to invoke asynchronously. Multiple AppenderRef - elements can be configured.
    blockingbooleanIf true, the appender will wait until there are free slots in the queue. If false, the event - will be written to the error appender if the queue is full. The default is true.
    shutdownTimeoutintegerHow many milliseconds the Appender should wait to flush outstanding log events in the queue - on shutdown. The default is zero which means to wait forever.
    bufferSizeintegerSpecifies the maximum number of events that can be queued. The default is 1024. Note that when using a - disruptor-style BlockingQueue, this buffer size must be a power of 2. -

    - When the application is logging faster than the underlying appender can keep up with - for a long enough time to fill up the queue, the behavious is determined by the - AsyncQueueFullPolicy. -

    -
    errorRefStringThe name of the Appender to invoke if none of the appenders can be called, either due to errors - in the appenders or because the queue is full. If not specified then errors will be ignored.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    nameStringThe name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    includeLocationbooleanExtracting location is an expensive operation (it can make - logging 5 - 20 times slower). To improve performance, location is - not included by default when adding a log event to the queue. - You can change this by setting includeLocation="true".
    BlockingQueueFactoryBlockingQueueFactoryThis element overrides what type of BlockingQueue to use. See - below documentation for more details.
    -

    - There are also a few system properties that can be used to maintain application throughput even when - the underlying appender cannot keep up with the logging rate and the queue is filling up. - See the details for system properties - log4j2.AsyncQueueFullPolicy and - log4j2.DiscardThreshold. -

    -

    - A typical AsyncAppender configuration might look like: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -    
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - - Starting in Log4j 2.7, a custom implementation of BlockingQueue or TransferQueue can be - specified using a - BlockingQueueFactory - plugin. To override the default BlockingQueueFactory, specify the plugin inside an - ]]> element like so: -

    -
    
    -  
    -    
    -    
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - Log4j ships with the following implementations: -

    - - - - - - - - - - - - - - - - - - - - - - -
    BlockingQueueFactory Implementations
    Plugin NameDescription
    ArrayBlockingQueue - This is the default implementation that uses - ArrayBlockingQueue. -
    DisruptorBlockingQueue - This uses the Conversant Disruptor implementation - of BlockingQueue. This plugin takes a single optional attribute, spinPolicy, which - corresponds to - -
    JCToolsBlockingQueue - This uses JCTools, specifically the - MPSC bounded lock-free queue. - -
    LinkedTransferQueue - This uses the new in Java 7 implementation - LinkedTransferQueue. - Note that this queue does not use the bufferSize configuration attribute from AsyncAppender as - LinkedTransferQueue does not support a maximum capacity. - -
    - - - -

    - The CassandraAppender writes its output to an Apache Cassandra - database. A keyspace and table must be configured ahead of time, and the columns of that table are mapped - in a configuration file. Each column can specify either a StringLayout (e.g., a - PatternLayout) along with an optional conversion type, or only - a conversion type for org.apache.logging.log4j.spi.ThreadContextMap or - org.apache.logging.log4j.spi.ThreadContextStack to store the MDC or NDC - in a map or list column respectively. A conversion type compatible with java.util.Date will - use the log event timestamp converted to that type (e.g., use java.util.Date to fill a - timestamp column type in Cassandra). -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CassandraAppender Parameters
    Parameter NameTypeDescription
    batchedbooleanWhether or not to use batch statements to write log messages to Cassandra. By default, this is false.
    batchTypeBatchStatement.TypeThe batch type to use when using batched writes. By default, this is LOGGED.
    bufferSizeintThe number of log messages to buffer or batch before writing. By default, no buffering is done.
    clusterNameStringThe name of the Cassandra cluster to connect to.
    columnsColumnMapping[]A list of column mapping configurations. Each column must specify a column name. Each column can - have a conversion type specified by its fully qualified class name. By default, the conversion type is - String. If the configured type is assignment-compatible with - ReadOnlyStringMap - / - ThreadContextMap - or - ThreadContextStack, - then that column will be populated with the MDC or NDC respectively. If the configured type is - assignment-compatible with java.util.Date, then the log timestamp will be converted to - that configured date type. If a literal attribute is given, then its value will be used as - is in the INSERT query without any escaping. Otherwise, the layout or pattern specified - will be converted into the configured type and stored in that column. -
    contactPointsSocketAddress[]A list of hosts and ports of Cassandra nodes to connect to. These must be valid hostnames or IP - addresses. By default, if a port is not specified for a host or it is set to 0, then the default - Cassandra port of 9042 will be used. By default, localhost:9042 will be used.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter may be used - by using a CompositeFilter.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    keyspaceStringThe name of the keyspace containing the table that log messages will be written to.
    nameStringThe name of the Appender.
    passwordStringThe password to use (along with the username) to connect to Cassandra.
    tableStringThe name of the table to write log messages to.
    useClockForTimestampGeneratorbooleanWhether or not to use the configured org.apache.logging.log4j.core.time.Clock as a - TimestampGenerator. - By default, this is false.
    usernameStringThe username to use to connect to Cassandra. By default, no username or password is used.
    useTlsbooleanWhether or not to use TLS/SSL to connect to Cassandra. This is false by default.
    -

    - Here is an example CassandraAppender configuration: -

    -
    
    -  
    -    
    -      
    -      
    -      
    -      
    -      
    -      
    -      
    -      
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -    
    -  
    -
    -]]>
    -

    - This example configuration uses the following table schema: -

    -
    ,
    -    ndc list
    -);
    -]]>
    - - - -

    - As one might expect, the ConsoleAppender writes its output to either System.out or System.err with System.out - being the default target. A Layout must be provided to format the LogEvent. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ConsoleAppender Parameters
    Parameter NameTypeDescription
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is supplied the default pattern layout - of "%m%n" will be used.
    followbooleanIdentifies 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.
    directbooleanWrite 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 will not respect - java.lang.System.setOut()/.setErr() and may get intertwined with other output to - java.lang.System.out/.err in a multi-threaded application. - New since 2.6.2. Be aware that this is a new addition, and it has only been tested with Oracle JVM - on Linux and Windows so far.
    nameStringThe name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    targetStringEither "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_OUT".
    -

    - A typical Console configuration might look like: -

    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    -
    - -

    The FailoverAppender wraps a set of appenders. If the primary Appender fails the secondary appenders will be - tried in order until one succeeds or there are no more secondaries to try.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FailoverAppender Parameters
    Parameter NameTypeDescription
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    primaryStringThe name of the primary Appender to use.
    failoversString[]The names of the secondary Appenders to use.
    nameStringThe name of the Appender.
    retryIntervalSecondsintegerThe number of seconds that should pass before retrying the primary Appender. The default is 60.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead.
    targetStringEither "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_ERR".
    -

    - A Failover configuration might look like: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -    
    -    
    -      
    -    
    -    
    -      
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    -
    - -

    The FileAppender is an OutputStreamAppender that writes to the File named in the fileName parameter. The - FileAppender uses a FileManager (which extends OutputStreamManager) to actually perform the file I/O. While - FileAppenders from different Configurations cannot be shared, the FileManagers can be if the Manager is - accessible. For example, two web applications in a servlet container can have their own configuration and - safely write to the same file if Log4j is in a ClassLoader that is common to both of them.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FileAppender Parameters
    Parameter NameTypeDescription
    appendbooleanWhen true - the default, records will be appended to the end of the file. When set to false, - the file will be cleared before new records are written.
    bufferedIObooleanWhen true - the default, records will be written to a buffer and the data will be written to - disk when the buffer is full or, if immediateFlush is set, when the record is written. - File locking cannot be used with bufferedIO. Performance tests have shown that using buffered I/O - significantly improves performance, even if immediateFlush is enabled.
    bufferSizeintWhen bufferedIO is true, this is the buffer size, the default is 8192 bytes.
    createOnDemandbooleanThe appender creates the file on-demand. The appender only creates the file when a log event - passes all filters and is routed to this appender. Defaults to false.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    fileNameStringThe name of the file to write to. If the file, or any of its parent directories, do not exist, - they will be created.
    immediateFlushboolean

    When set to true - the default, each write will be followed by a flush. - This will guarantee the data is written - to disk but could impact performance.

    -

    Flushing after every write is only useful when using this - appender with synchronous loggers. Asynchronous loggers and - appenders will automatically flush at the end of a batch of events, - even if immediateFlush is set to false. This also guarantees - the data is written to disk but is more efficient.

    -
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is supplied the default pattern layout - of "%m%n" will be used.
    lockingbooleanWhen set to true, I/O operations will occur only while the file lock is held allowing FileAppenders - in multiple JVMs and potentially multiple hosts to write to the same file simultaneously. This - will significantly impact performance so should be used carefully. Furthermore, on many systems - the file lock is "advisory" meaning that other applications can perform operations on the file - without acquiring a lock. The default value is false.
    nameStringThe name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    filePermissionsString

    File attribute permissions in POSIX format to apply whenever the file is created.

    -

    Underlying files system shall support POSIX file attribute view.

    -

    Examples: rw------- or rw-rw-rw- etc...

    fileOwnerString

    File owner to define whenever the file is created.

    -

    Changing file's owner may be restricted for security reason and Operation not permitted IOException thrown. - Only processes with an effective user ID equal to the user ID - of the file or with appropriate privileges may change the ownership of a file - if _POSIX_CHOWN_RESTRICTED is in effect for path.

    -

    Underlying files system shall support file owner attribute view.

    -
    fileGroupString

    File group to define whenever the file is created.

    -

    Underlying files system shall support POSIX file attribute view.

    -
    -

    - Here is a sample File configuration: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    -
    - -

    This is an optional component supplied in a separate jar.

    -

    Apache Flume is a distributed, reliable, - and available system for efficiently collecting, aggregating, and moving large amounts of log data - from many different sources to a centralized data store. The FlumeAppender takes LogEvents and sends - them to a Flume agent as serialized Avro events for consumption.

    -

    - The Flume Appender supports three modes of operation. -

    -
      -
    1. It can act as a remote Flume client which sends Flume events via Avro to a Flume Agent configured - with an Avro Source.
    2. -
    3. It can act as an embedded Flume Agent where Flume events pass directly into Flume for processing.
    4. -
    5. It can persist events to a local BerkeleyDB data store and then asynchronously send the events to - Flume, similar to the embedded Flume Agent but without most of the Flume dependencies.
    6. -
    -

    - Usage as an embedded agent will cause the messages to be directly passed to the Flume Channel and then - control will be immediately returned to the application. All interaction with remote agents will occur - asynchronously. Setting the "type" attribute to "Embedded" will force the use of the embedded agent. In - addition, configuring agent properties in the appender configuration will also cause the embedded agent - to be used. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FlumeAppender Parameters
    Parameter NameTypeDescription
    agentsAgent[]An array of Agents to which the logging events should be sent. If more than one agent is specified - the first Agent will be the primary and subsequent Agents will be used in the order specified as - secondaries should the primary Agent fail. Each Agent definition supplies the Agents host and port. - The specification of agents and properties are mutually exclusive. If both are configured an - error will result.
    agentRetriesintegerThe number of times the agent should be retried before failing to a secondary. This parameter is - ignored when type="persistent" is specified (agents are tried once before failing to the next).
    batchSizeintegerSpecifies the number of events that should be sent as a batch. The default is 1. This - parameter only applies to the Flume Appender.
    compressbooleanWhen set to true the message body will be compressed using gzip
    connectTimeoutMillisintegerThe number of milliseconds Flume will wait before timing out the connection.
    dataDirStringDirectory where the Flume write ahead log should be written. Valid only when embedded is set - to true and Agent elements are used instead of Property elements.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    eventPrefixStringThe character string to prepend to each event attribute in order to distinguish it from MDC attributes. - The default is an empty string.
    flumeEventFactoryFlumeEventFactoryFactory that generates the Flume events from Log4j events. The default factory is the - FlumeAvroAppender itself.
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is specified RFC5424Layout will be used.
    lockTimeoutRetriesintegerThe number of times to retry if a LockConflictException occurs while writing to Berkeley DB. The - default is 5.
    maxDelayMillisintegerThe maximum number of milliseconds to wait for batchSize events before publishing the batch.
    mdcExcludesStringA comma separated list of mdc keys that should be excluded from the FlumeEvent. This is mutually - exclusive with the mdcIncludes attribute.
    mdcIncludesStringA comma separated list of mdc keys that should be included in the FlumeEvent. Any keys in the MDC - not found in the list will be excluded. This option is mutually exclusive with the mdcExcludes - attribute.
    mdcRequiredStringA comma separated list of mdc keys that must be present in the MDC. If a key is not present a - LoggingException will be thrown.
    mdcPrefixStringA string that should be prepended to each MDC key in order to distinguish it from event attributes. - The default string is "mdc:".
    nameStringThe name of the Appender.
    propertiesProperty[]

    One or more Property elements that are used to configure the Flume Agent. The properties must be - configured without the agent name (the appender name is used for this) and no sources can be - configured. Interceptors can be specified for the source using "sources.log4j-source.interceptors". - All other Flume configuration properties are allowed. Specifying both Agent and Property - elements will result in an error.

    -

    When used to configure in Persistent mode the valid properties are:

    -
      -
    1. "keyProvider" to specify the name of the plugin to provide the secret key for encryption.
    2. -
    -
    requestTimeoutMillisintegerThe number of milliseconds Flume will wait before timing out the request.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    typeenumerationOne of "Avro", "Embedded", or "Persistent" to indicate which variation of the Appender is desired.
    -

    - A sample FlumeAppender configuration that is configured with a primary and a secondary agent, - compresses the body, and formats the body using the RFC5424Layout: -

    - -
    
    -
    -  
    -    
    -      
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - A sample FlumeAppender configuration that is configured with a primary and a secondary agent, - compresses the body, formats the body using the RFC5424Layout, and persists encrypted events to disk: -

    - -
    
    -
    -  
    -    
    -      
    -      
    -      
    -      MySecretProvider
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - A sample FlumeAppender configuration that is configured with a primary and a secondary agent, - compresses the body, formats the body using RFC5424Layout and passes the events to an embedded Flume - Agent. -

    -
    
    -
    -  
    -    
    -      
    -      
    -      
    -    
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -    
    -      
    -    
    -  
    -]]>
    -

    - A sample FlumeAppender configuration that is configured with a primary and a secondary agent using - Flume configuration properties, compresses the body, formats the body using RFC5424Layout and passes the - events to an embedded Flume Agent. -

    -
    
    -
    -  
    -    
    -      file
    -      file
    -      target/file-channel/checkpoint
    -      target/file-channel/data
    -      agent1 agent2
    -      file
    -      avro
    -      192.168.10.101
    -      8800
    -      100
    -      file
    -      avro
    -      192.168.10.102
    -      8800
    -      100
    -      group1
    -      agent1 agent2
    -      failover
    -      10
    -      5
    -      
    -    
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -    
    -      
    -    
    -  
    -]]>
    - - - -

    - As of Log4j 2.11.0, JDBC support has moved from the existing module logj-core to the new module log4j-jdbc. -

    -

    The JDBCAppender writes log events to a relational database table using standard JDBC. It can be configured - to obtain JDBC connections using a JNDI DataSource or a custom factory method. Whichever - approach you take, it must be backed by a connection pool. Otherwise, logging - performance will suffer greatly. If batch statements are supported by the configured JDBC driver and a - bufferSize is configured to be a positive number, then log events will be batched. Note that as - of Log4j 2.8, there are two ways to configure log event to column mappings: the original ColumnConfig - style that only allows strings and timestamps, and the new ColumnMapping plugin that uses Log4j's - built-in type conversion to allow for more data types (this is the same plugin as in the - Cassandra Appender).

    -

    - To get off the ground quickly during development, an alternative to using a connection source based on - JNDI is to use the non-pooling DriverManager connection source. This connection source uses - a JDBC connection string, a user name, and a password. Optionally, you can also use properties. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    JDBCAppender Parameters
    Parameter NameTypeDescription
    nameStringRequired. The name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter may be - used by using a CompositeFilter.
    bufferSizeintIf an integer greater than 0, this causes the appender to buffer log events and flush whenever the - buffer reaches this size.
    connectionSourceConnectionSourceRequired. The connections source from which database connections should be retrieved.
    tableNameStringRequired. The name of the database table to insert log events into.
    columnConfigsColumnConfig[]Required (and/or columnMappings). Information about the columns that log event data should be inserted into and how - to insert that data. This is represented with multiple <Column> elements.
    columnMappingsColumnMapping[]Required (and/or columnConfigs). A list of column mapping configurations. Each column must - specify a column name. Each column can have a conversion type specified by its fully qualified class - name. By default, the conversion type is String. If the configured type is - assignment-compatible with - ReadOnlyStringMap - / - ThreadContextMap - or - ThreadContextStack, - then that column will be populated with the MDC or NDC respectively (this is database-specific how they - handle inserting a Map or List value). If the configured type is - assignment-compatible with java.util.Date, then the log timestamp will be converted to - that configured date type. If the configured type is assignment-compatible with java.sql.Clob - or java.sql.NClob, then the formatted event will be set as a Clob or NClob respectively - (similar to the traditional ColumnConfig plugin). If a literal attribute is given, then its - value will be used as is in the INSERT query without any escaping. Otherwise, the layout or - pattern specified will be converted into the configured type and stored in that column. -
    -

    When configuring the JDBCAppender, you must specify a ConnectionSource implementation from - which the Appender gets JDBC connections. You must use exactly one of the following nested elements:

    - - - - - - - - - - - - - - -
    DataSource Parameters
    Parameter NameTypeDescription
    jndiNameStringRequired. The full, prefixed JNDI name that the javax.sql.DataSource is bound - to, such as java:/comp/env/jdbc/LoggingDatabase. The DataSource must be backed - by a connection pool; otherwise, logging will be very slow.
    -
    - - - - - - - - - - - - - - - - - -
    ConnectionFactory Parameters
    Parameter NameTypeDescription
    classClassRequired. The fully qualified name of a class containing a static factory method for - obtaining JDBC connections.
    methodMethodRequired. The name of a static factory method for obtaining JDBC connections. This method - must have no parameters and its return type must be either java.sql.Connection or - DataSource. If the method returns Connections, it must obtain them from a - connection pool (and they will be returned to the pool when Log4j is done with them); otherwise, logging - will be very slow. If the method returns a DataSource, the DataSource will - only be retrieved once, and it must be backed by a connection pool for the same reasons.
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    DriverManager Parameters
    Parameter NameTypeDescription
    connectionStringStringRequired. The driver-specific JDBC connection string.
    userNameStringThe database user name. You cannot specify both properties and a user name or password.
    passwordStringThe database password. You cannot specify both properties and a user name or password.
    driverClassNameStringThe JDBC driver class name. Some old JDBC Driver can only be discovered by explicitly loading them by class name.
    propertiesProperty[]A list of properties. You cannot specify both properties and a user name or password.
    -
    - - - - - - - - - - - - - - - - - -
    PoolingDriver Parameters (Apache Commons DBCP)
    Parameter NameTypeDescription
    DriverManager parametersDriverManager parametersThis connection source inherits all parameter from the DriverManager connection source.
    poolNameStringThe pool name used to pool JDBC Connections. Defaults to example. You can use the JDBC - connection string prefix jdbc:apache:commons:dbcp: followed by the pool name if you want - to use a pooled connection elsewhere. For example: jdbc:apache:commons:dbcp:example.
    -

    When configuring the JDBCAppender, use the nested <Column> elements to specify which - columns in the table should be written to and how to write to them. The JDBCAppender uses this information - to formulate a PreparedStatement to insert records without SQL injection vulnerability.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Column Parameters
    Parameter NameTypeDescription
    nameStringRequired. The name of the database column.
    patternStringUse this attribute to insert a value or values from the log event in this column using a - PatternLayout pattern. Simply specify any legal pattern in this attribute. Either this - attribute, literal, or isEventTimestamp="true" must be specified, but not more - than one of these.
    literalString -

    Use this attribute to insert a literal value in this column. The value will be included directly in - the insert SQL, without any quoting (which means that if you want this to be a string, your value should - contain single quotes around it like this: literal="'Literal String'"). This is especially - useful for databases that don't support identity columns. For example, if you are using Oracle you could - specify literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL" to insert a unique ID in an ID column. - Either this attribute, pattern, or isEventTimestamp="true" must be specified, - but not more than one of these. -

    -
    parameterString -

    Use this attribute to insert an expression with a parameter marker '?' in this column. The value will be included directly in - the insert SQL, without any quoting (which means that if you want this to be a string, your value should - contain single quotes around it like this: -

    -

    - <ColumnMapping name="instant" parameter="TIMESTAMPADD('MILLISECOND', ?, TIMESTAMP '1970-01-01')"/> -

    -

    - You can only specify one of literal or parameter. -

    -
    isEventTimestampbooleanUse this attribute to insert the event timestamp in this column, which should be a SQL datetime. The - value will be inserted as a java.sql.Types.TIMESTAMP. Either this attribute (equal to - true), pattern, or isEventTimestamp must be specified, but not - more than one of these.
    isUnicodebooleanThis attribute is ignored unless pattern is specified. If true or omitted - (default), the value will be inserted as unicode (setNString or setNClob). - Otherwise, the value will be inserted non-unicode (setString or setClob).
    isClobbooleanThis attribute is ignored unless pattern is specified. Use this attribute to indicate - that the column stores Character Large Objects (CLOBs). If true, the value will be inserted - as a CLOB (setClob or setNClob). If false or omitted (default), - the value will be inserted as a VARCHAR or NVARCHAR (setString or setNString). -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ColumnMapping Parameters
    Parameter NameTypeDescription
    nameStringRequired. The name of the database column.
    patternStringUse this attribute to insert a value or values from the log event in this column using a - PatternLayout pattern. Simply specify any legal pattern in this attribute. Either this - attribute, literal, or isEventTimestamp="true" must be specified, but not more - than one of these.
    literalStringUse this attribute to insert a literal value in this column. The value will be included directly in - the insert SQL, without any quoting (which means that if you want this to be a string, your value should - contain single quotes around it like this: literal="'Literal String'"). This is especially - useful for databases that don't support identity columns. For example, if you are using Oracle you could - specify literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL" to insert a unique ID in an ID column. - Either this attribute, pattern, or isEventTimestamp="true" must be specified, - but not more than one of these.
    layoutLayoutThe Layout to format the LogEvent.
    typeStringConversion type name, a fully-qualified class name.
    -

    - Here are a couple sample configurations for the JDBCAppender, as well as a sample factory implementation - that uses Commons Pooling and Commons DBCP to pool database connections: -

    - -
    
    -
    -  
    -    
    -      
    -      
    -      
    -      
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -
    
    -
    -  
    -    
    -      
    -      
    -      
    -      
    -      
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
     pool = new GenericObjectPool();
    -        DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
    -                "jdbc:mysql://example.org:3306/exampleDb", properties
    -        );
    -        new PoolableConnectionFactory(
    -                connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED
    -        );
    -
    -        this.dataSource = new PoolingDataSource(pool);
    -    }
    -
    -    public static Connection getDatabaseConnection() throws SQLException {
    -        return Singleton.INSTANCE.dataSource.getConnection();
    -    }
    -}]]>
    -

    - This appender is MapMessage-aware. -

    -

    - The following configuration uses a MessageLayout to indicate that the Appender should match - the keys of a MapMessage to the names of ColumnMappings when setting the - values of the Appender's SQL INSERT statement. This let you insert rows for custom values in a - database table based on a Log4j MapMessage instead of values from LogEvents. -

    -
    
    -
    -  
    -    
    -      
    -    
    -    
    -      
    -      
    -      
    -      
    -      
    -    
    -  
    -
    -  
    -    
    -      
    -    
    -
    -    
    -      
    -    
    -  
    -
    -]]>
    - - - - - - -

    - As of Log4j 2.11.0, JPA support has moved from the existing module logj-core to the new module log4j-jms. -

    -

    The JMS Appender sends the formatted log event to a JMS Destination.

    -

    - Note that in Log4j 2.0, this appender was split into a JMSQueueAppender and a JMSTopicAppender. Starting - in Log4j 2.1, these appenders were combined into the JMS Appender which makes no distinction between queues - and topics. However, configurations written for 2.0 which use the <JMSQueue/> or - <JMSTopic/> elements will continue to work with the new <JMS/> - configuration element. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    JMS Appender Parameters
    Parameter NameTypeDefaultDescription
    factoryBindingNameStringRequiredThe name to locate in the Context that provides the - ConnectionFactory. - This can be any subinterface of ConnectionFactory as well. -
    factoryNameStringRequiredThe fully qualified class name that should be used to define the Initial Context Factory as defined in - INITIAL_CONTEXT_FACTORY. - If a factoryName is specified without a providerURL a warning message will be logged as this is - likely to cause problems. -
    filterFilternullA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    layoutLayoutRequired - The Layout to use to format the LogEvent. - New since 2.9, in previous versions SerializedLayout was default. -
    nameStringRequiredThe name of the Appender.
    passwordStringnullThe password to use to create the JMS connection.
    providerURLStringRequiredThe URL of the provider to use as defined by - PROVIDER_URL. -
    destinationBindingNameStringRequired - The name to use to locate the - Destination. - This can be a Queue or Topic, and as such, the attribute names - queueBindingName and topicBindingName are aliases to maintain compatibility - with the Log4j 2.0 JMS appenders. -
    securityPrincipalNameStringnullThe name of the identity of the Principal as specified by - SECURITY_PRINCIPAL. - If a securityPrincipalName is specified without securityCredentials a warning message will be - logged as this is likely to cause problems.
    securityCredentialsStringnullThe security credentials for the principal as specified by - SECURITY_CREDENTIALS. -
    ignoreExceptionsbooleantrueWhen true, exceptions caught while appending events are - internally logged and then ignored. When false exceptions are propagated to the - caller. You must set this to false when wrapping this Appender in a - FailoverAppender.
    immediateFailbooleanfalseWhen set to true, log events will not wait to try to reconnect and will fail immediately if the - JMS resources are not available. New in 2.9.
    reconnectIntervalMillislong5000If set to a value greater than 0, after an error, the JMSManager will attempt to reconnect to - the broker after waiting the specified number of milliseconds. If the reconnect fails then - an exception will be thrown (which can be caught by the application if ignoreExceptions is - set to false). New in 2.9.
    urlPkgPrefixesStringnullA colon-separated list of package prefixes for the class name of the factory class that will create - a URL context factory as defined by - URL_PKG_PREFIXES. -
    userNameStringnullThe user id used to create the JMS connection.
    -

    - Here is a sample JMS Appender configuration: -

    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -

    - To map your Log4j MapMessages to JMS javax.jms.MapMessages, set the - layout of the appender to MessageLayout with <MessageLayout /> (Since 2.9.): -

    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -
    -
    - -

    - As of Log4j 2.11.0, JPA support has moved from the existing module logj-core to the new module log4j-jpa. -

    -

    The JPAAppender writes log events to a relational database table using the Java Persistence API 2.1. - It requires the API and a provider implementation be on the classpath. It also requires a decorated entity - configured to persist to the table desired. The entity should either extend - org.apache.logging.log4j.core.appender.db.jpa.BasicLogEventEntity (if you mostly want to - use the default mappings) and provide at least an @Id property, or - org.apache.logging.log4j.core.appender.db.jpa.AbstractLogEventWrapperEntity (if you want - to significantly customize the mappings). See the Javadoc for these two classes for more information. You - can also consult the source code of these two classes as an example of how to implement the entity.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    JPAAppender Parameters
    Parameter NameTypeDescription
    nameStringRequired. The name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter may be - used by using a CompositeFilter.
    bufferSizeintIf an integer greater than 0, this causes the appender to buffer log events and flush whenever the - buffer reaches this size.
    entityClassNameStringRequired. The fully qualified name of the concrete LogEventWrapperEntity implementation that - has JPA annotations mapping it to a database table.
    persistenceUnitNameStringRequired. The name of the JPA persistence unit that should be used for persisting log - events.
    -

    - Here is a sample configuration for the JPAAppender. The first XML sample is the Log4j configuration file, - the second is the persistence.xml file. EclipseLink is assumed here, but any JPA 2.1 or higher - provider will do. You should always create a separate persistence unit for logging, for - two reasons. First, <shared-cache-mode> must be set to "NONE," which is usually - not desired in normal JPA usage. Also, for performance reasons the logging entity should be isolated in its - own persistence unit away from all other entities and you should use a non-JTA data source. Note that your - persistence unit must also contain <class> elements for all of the - org.apache.logging.log4j.core.appender.db.jpa.converter converter classes. -

    - -
    
    -
    -  
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -
    
    -
    -
    -  
    -    org.eclipse.persistence.jpa.PersistenceProvider
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter
    -    org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter
    -    com.example.logging.JpaLogEntity
    -    jdbc/LoggingDataSource
    -    NONE
    -  
    -
    -]]>
    - -
    - -
    -
    -
    - -

    - The HttpAppender sends log events over HTTP. A Layout must be provided to format the LogEvent. -

    -

    - Will set the Content-Type header according to the layout. Additional headers can be specified - with embedded Property elements. -

    -

    - Will wait for response from server, and throw error if no 2xx response is received. -

    -

    - Implemented with - HttpURLConnection. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    HttpAppender Parameters
    Parameter NameTypeDescription
    nameStringThe name of the Appender.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    layoutLayoutThe Layout to use to format the LogEvent.
    SslSslConfigurationContains the configuration for the KeyStore and TrustStore for https. - Optional, uses Java runtime defaults if not specified. See SSL
    verifyHostnamebooleanWhether to verify server hostname against certificate. Only valid for https. - Optional, defaults to true
    urlstringThe URL to use. The URL scheme must be "http" or "https".
    methodstringThe HTTP method to use. Optional, default is "POST".
    connectTimeoutMillisintegerThe connect timeout in milliseconds. Optional, default is 0 (infinite timeout).
    readTimeoutMillisintegerThe socket read timeout in milliseconds. Optional, default is 0 (infinite timeout).
    headersProperty[]Additional HTTP headers to use. The values support lookups.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    -

    - Here is a sample HttpAppender configuration snippet: -

    -
    
    -  ...
    -  
    -    
    -      
    -      
    -      
    -        
    -        
    -      
    -    
    -  ]]>
    - - - -

    - As of Log4j 2.11.0, Apache Kafka support has moved from the - existing module logj-core to the new module log4j-kafka. -

    -

    - The KafkaAppender logs events to an Apache Kafka topic. - Each log event is sent as a Kafka record. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    KafkaAppender Parameters
    Parameter NameTypeDescription
    topicStringThe Kafka topic to use. Required.
    keyStringThe key that will be sent to Kafka with every message. Optional value defaulting to null. - Any of the Lookups) can be included. -
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    layoutLayout - The Layout to use to format the LogEvent. Required, there is no default. - New since 2.9, in previous versions <PatternLayout pattern="%m"/> was default. -
    nameStringThe name of the Appender. Required.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    syncSendbooleanThe default is true, causing sends to block until the record has been acknowledged by the - Kafka server. When set to false sends return immediately, allowing for lower latency and significantly - higher throughput. New since 2.8. Be aware that this is a new addition, and it has not been extensively tested. - Any failure sending to Kafka will be reported as error to StatusLogger and the log event will be dropped - (the ignoreExceptions parameter will not be effective). Log events may arrive out of order to the Kafka server. -
    propertiesProperty[] - You can set properties in Kafka producer properties. - You need to set the bootstrap.servers property, there are sensible default values for the others. - Do not set the value.serializer nor key.serializer properties. -
    -

    - Here is a sample KafkaAppender configuration snippet: -

    -
    
    -  ...
    -  
    -    
    -      
    -        localhost:9092
    -    
    -  ]]>
    -

    - This appender is synchronous by default and will block until the record has been acknowledged by the Kafka server, timeout - for this can be set with the timeout.ms property (defaults to 30 seconds). Wrap with - Async appender and/or set syncSend to - false to log asynchronously. -

    -

    - This appender requires the Kafka client library. Note that you need to use a version of - the Kafka client library matching the Kafka server used. -

    -

    - Note:Make sure to not let org.apache.kafka log to a Kafka appender on DEBUG level, - since that will cause recursive logging: -

    -
    
    -  ...
    -  
    -    
    -      
    -    
    -     
    -  ]]>
    - - - -

    New since 2.1. Be aware that this is a new addition, and although it has been - tested on several platforms, it does not have as much track record as the other file appenders.

    -

    - The MemoryMappedFileAppender maps a part of the specified file into memory - and writes log events to this memory, relying on the operating system's - virtual memory manager to synchronize the changes to the storage device. - The main benefit of using memory mapped files is I/O performance. Instead of making system - calls to write to disk, this appender can simply change the program's local memory, - which is orders of magnitude faster. Also, in most operating systems the memory - region mapped actually is the kernel's page - cache (file cache), meaning that no copies need to be created in user space. - (TODO: performance tests that compare performance of this appender to - RandomAccessFileAppender and FileAppender.) -

    -

    - There is some overhead with mapping a file region into memory, - especially very large regions (half a gigabyte or more). - The default region size is 32 MB, which should strike a reasonable balance - between the frequency and the duration of remap operations. - (TODO: performance test remapping various sizes.) -

    -

    - Similar to the FileAppender and the RandomAccessFileAppender, - MemoryMappedFileAppender uses a MemoryMappedFileManager to actually perform the - file I/O. While MemoryMappedFileAppender from different Configurations - cannot be shared, the MemoryMappedFileManagers can be if the Manager is - accessible. For example, two web applications in a servlet container can have - their own configuration and safely write to the same file if Log4j - is in a ClassLoader that is common to both of them. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    MemoryMappedFileAppender Parameters
    Parameter NameTypeDescription
    appendbooleanWhen true - the default, records will be appended to the end - of the file. When set to false, the file will be cleared before - new records are written. -
    fileNameStringThe name of the file to write to. If the file, or any of its - parent directories, do not exist, they will be created. -
    filtersFilterA Filter to determine if the event should be handled by this - Appender. More than one Filter may be used by using a CompositeFilter. -
    immediateFlushboolean -

    When set to true, each write will be followed by a - call to MappedByteBuffer.force(). - This will guarantee the data is written to the storage device. -

    -

    The default for this parameter is false. - This means that the data is written to the storage device even - if the Java process crashes, but there may be data loss if the - operating system crashes.

    -

    Note that manually forcing a sync on every log event loses most - of the performance benefits of using a memory mapped file.

    -

    Flushing after every write is only useful when using this - appender with synchronous loggers. Asynchronous loggers and - appenders will automatically flush at the end of a batch of events, - even if immediateFlush is set to false. This also guarantees - the data is written to disk but is more efficient. -

    -
    regionLengthintThe length of the mapped region, defaults to 32 MB - (32 * 1024 * 1024 bytes). This parameter must be a value - between 256 and 1,073,741,824 (1 GB or 2^30); - values outside this range will be adjusted to the closest valid - value. - Log4j will round the specified value up to the nearest power of two.
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is supplied the default pattern layout - of "%m%n" will be used.
    nameStringThe name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    -

    - Here is a sample MemoryMappedFile configuration: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - -

    - The NoSQLAppender writes log events to a NoSQL database using an internal lightweight provider interface. - Provider implementations currently exist for MongoDB and Apache CouchDB, and writing a custom provider is - quite simple. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    NoSQLAppender Parameters
    Parameter NameTypeDescription
    nameStringRequired. The name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter may be - used by using a CompositeFilter.
    bufferSizeintIf an integer greater than 0, this causes the appender to buffer log events and flush whenever the - buffer reaches this size.
    NoSqlProviderNoSQLProvider<C extends NoSQLConnection<W, T extends NoSQLObject<W>>>Required. The NoSQL provider that provides connections to the chosen NoSQL database.
    -

    You specify which NoSQL provider to use by specifying the appropriate configuration element within the - <NoSql> element. The types currently supported are <MongoDb> and - <CouchDb>. To create your own custom provider, read the JavaDoc for the - NoSQLProvider, NoSQLConnection, and NoSQLObject classes and the - documentation about creating Log4j plugins. We recommend you review the source code for the MongoDB and - CouchDB providers as a guide for creating your own provider. -

    -

    - The following example demonstrates how log events are persisted in NoSQL databases if represented in a JSON - format: -

    -
    -
    -
    - -

    - Starting with Log4 2.11.0, we provide two MongoDB modules: -

    -
    -

    - We no longer provide the module log4j-mongodb. -

    -

    - The module log4j-mongodb2 aliases the old configuration element MongoDb to MongoDb2. -

    - - - -

    - This section details specializations of the NoSQLAppender provider for MongoDB using - the MongoDB driver version 2. The NoSQLAppender Appender writes log events to a NoSQL database using an - internal lightweight provider interface. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    MongoDB2 Provider Parameters
    Parameter NameTypeDescription
    collectionNameStringRequired. The name of the MongoDB collection to insert the events into.
    writeConcernConstantFieldBy default, the MongoDB provider inserts records with the instructions - com.mongodb.WriteConcern.ACKNOWLEDGED. Use this optional attribute to specify the name of - a constant other than ACKNOWLEDGED.
    writeConcernConstantClassClassIf you specify writeConcernConstant, you can use this attribute to specify a class other - than com.mongodb.WriteConcern to find the constant on (to create your own custom - instructions).
    factoryClassNameClassTo provide a connection to the MongoDB database, you can use this attribute and - factoryMethodName to specify a class and static method to get the connection from. The - method must return a com.mongodb.DB or a com.mongodb.MongoClient. If the - DB is not authenticated, you must also specify a username and - password. If you use the factory method for providing a connection, you must not specify - the databaseName, server, or port attributes.
    factoryMethodNameMethodSee the documentation for attribute factoryClassName.
    databaseNameStringIf you do not specify a factoryClassName and factoryMethodName for providing - a MongoDB connection, you must specify a MongoDB database name using this attribute. You must also - specify a username and password. You can optionally also specify a - server (defaults to localhost), and a port (defaults to the default MongoDB - port).
    serverStringSee the documentation for attribute databaseName.
    portintSee the documentation for attribute databaseName.
    usernameStringSee the documentation for attributes databaseName and factoryClassName.
    passwordStringSee the documentation for attributes databaseName and factoryClassName.
    cappedbooleanEnable support for capped collections
    collectionSizeintSpecify the size in bytes of the capped collection to use if enabled. The minimum size is 4096 bytes, - and larger sizes will be increased to the nearest integer multiple of 256. See the capped collection documentation - linked above for more information.
    -

    - This appender is MapMessage-aware. -

    -

    - Here are a few sample configurations for the NoSQLAppender and MongoDB2 provider: -

    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - Starting in Log4j version 2.11.0, the provider element name is MongoDb2. - The name MongoDb is now a deprecated alias for MongoDb2. -

    - - - -

    - This section details specializations of the NoSQLAppender provider for MongoDB using - the MongoDB driver version 3. The NoSQLAppender Appender writes log events to a NoSQL database using an - internal lightweight provider interface. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    MongoDB3 Provider Parameters
    Parameter NameTypeDescription
    collectionNameStringRequired. The name of the MongoDB collection to insert the events into.
    writeConcernConstantFieldBy default, the MongoDB provider inserts records with the instructions - com.mongodb.WriteConcern.ACKNOWLEDGED. Use this optional attribute to specify the name of - a constant other than ACKNOWLEDGED.
    writeConcernConstantClassClassIf you specify writeConcernConstant, you can use this attribute to specify a class other - than com.mongodb.WriteConcern to find the constant on (to create your own custom - instructions).
    factoryClassNameClassTo provide a connection to the MongoDB database, you can use this attribute and - factoryMethodName to specify a class and static method to get the connection from. The - method must return a com.mongodb.client.MongoDatabase or a com.mongodb.MongoClient. If the - com.mongodb.client.MongoDatabase is not authenticated, you must also specify a username and - password. If you use the factory method for providing a connection, you must not specify - the databaseName, server, or port attributes.
    factoryMethodNameMethodSee the documentation for attribute factoryClassName.
    databaseNameStringIf you do not specify a factoryClassName and factoryMethodName for providing - a MongoDB connection, you must specify a MongoDB database name using this attribute. You must also - specify a username and password. You can optionally also specify a - server (defaults to localhost), and a port (defaults to the default MongoDB - port).
    serverStringSee the documentation for attribute databaseName.
    portintSee the documentation for attribute databaseName.
    usernameStringSee the documentation for attributes databaseName and factoryClassName.
    passwordStringSee the documentation for attributes databaseName and factoryClassName.
    cappedbooleanEnable support for capped collections
    collectionSizeintSpecify the size in bytes of the capped collection to use if enabled. The minimum size is 4096 bytes, - and larger sizes will be increased to the nearest integer multiple of 256. See the capped collection documentation - linked above for more information.
    -

    - This appender is MapMessage-aware. -

    -

    - Here are a few sample configurations for the NoSQLAppender and MongoDB3 provider: -

    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - -

    - This section details specializations of the NoSQLAppender provider for CouchDB. - The NoSQLAppender writes log events to a NoSQL database using an internal lightweight provider interface. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CouchDB Provider Parameters
    Parameter NameTypeDescription
    factoryClassNameClassTo provide a connection to the CouchDB database, you can use this attribute and - factoryMethodName to specify a class and static method to get the connection from. The - method must return a org.lightcouch.CouchDbClient or a - org.lightcouch.CouchDbProperties. If you use the factory method for providing a connection, - you must not specify the databaseName, protocol, server, - port, username, or password attributes.
    factoryMethodNameMethodSee the documentation for attribute factoryClassName.
    databaseNameStringIf you do not specify a factoryClassName and factoryMethodName for providing - a CouchDB connection, you must specify a CouchDB database name using this attribute. You must also - specify a username and password. You can optionally also specify a - protocol (defaults to http), server (defaults to localhost), and a - port (defaults to 80 for http and 443 for https).
    protocolStringMust either be "http" or "https." See the documentation for attribute databaseName.
    serverStringSee the documentation for attribute databaseName.
    portintSee the documentation for attribute databaseName.
    usernameStringSee the documentation for attributes databaseName.
    passwordStringSee the documentation for attributes databaseName.
    -

    - Here are a few sample configurations for the NoSQLAppender and CouchDB provider: -

    - -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - -

    - The OutputStreamAppender provides the base for many of the other Appenders such as the File and Socket - appenders that write the event to an Output Stream. It cannot be directly configured. Support for - immediateFlush and buffering is provided by the OutputStreamAppender. The OutputStreamAppender uses an - OutputStreamManager to handle the actual I/O, allowing the stream to be shared by Appenders in multiple - configurations. -

    -
    -
    - -

    - The RandomAccessFileAppender is similar to the standard - FileAppender - except it is always buffered (this cannot be switched off) - and internally it uses a - ByteBuffer + RandomAccessFile - instead of a - BufferedOutputStream. - We saw a 20-200% performance improvement compared to - FileAppender with "bufferedIO=true" in our - measurements. - Similar to the FileAppender, - RandomAccessFileAppender uses a RandomAccessFileManager to actually perform the - file I/O. While RandomAccessFileAppender - from different Configurations - cannot be shared, the RandomAccessFileManagers can be if the Manager is - accessible. For example, two web applications in a - servlet container can have - their own configuration and safely - write to the same file if Log4j - is in a ClassLoader that is common to - both of them. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    RandomAccessFileAppender Parameters
    Parameter NameTypeDescription
    appendbooleanWhen true - the default, records will be appended to the end - of the file. When set to false, - the file will be cleared before - new records are written. -
    fileNameStringThe name of the file to write to. If the file, or any of its - parent directories, do not exist, - they will be created. -
    filtersFilterA Filter to determine if the event should be handled by this - Appender. More than one Filter - may be used by using a CompositeFilter. -
    immediateFlushboolean -

    - When set to true - the default, each write will be followed by a flush. - This will guarantee the data is written - to disk but could impact performance. -

    -

    - Flushing after every write is only useful when using this - appender with synchronous loggers. Asynchronous loggers and - appenders will automatically flush at the end of a batch of events, - even if immediateFlush is set to false. This also guarantees - the data is written to disk but is more efficient. -

    -
    bufferSizeintThe buffer size, defaults to 262,144 bytes (256 * 1024).
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is supplied the default pattern layout - of "%m%n" will be used.
    nameStringThe name of the Appender.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    -

    - Here is a sample RandomAccessFile configuration: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - -

    - The RewriteAppender allows the LogEvent to manipulated before it is processed by another Appender. This - can be used to mask sensitive information such as passwords or to inject information into each event. - The RewriteAppender must be configured with a RewritePolicy. The - RewriteAppender should be configured after any Appenders it references to allow it to shut down properly. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    RewriteAppender Parameters
    Parameter NameTypeDescription
    AppenderRefStringThe name of the Appenders to call after the LogEvent has been manipulated. Multiple AppenderRef - elements can be configured.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    nameStringThe name of the Appender.
    rewritePolicyRewritePolicyThe RewritePolicy that will manipulate the LogEvent.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    -

    RewritePolicy

    -

    - RewritePolicy is an interface that allows implementations to inspect and possibly modify LogEvents - before they are passed to Appender. RewritePolicy declares a single method named rewrite that must - be implemented. The method is passed the LogEvent and can return the same event or create a new one. -

    -
    MapRewritePolicy
    -

    - MapRewritePolicy will evaluate LogEvents that contain a MapMessage and will add or update - elements of the Map. -

    - - - - - - - - - - - - - - - - -
    Parameter NameTypeDescription
    modeString"Add" or "Update"
    keyValuePairKeyValuePair[]An array of keys and their values.
    -

    - The following configuration shows a RewriteAppender configured to add a product key and its value - to the MapMessage.: -

    - -
    
    -
    -  
    -    
    -      
    -    
    -    
    -      
    -      
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    PropertiesRewritePolicy
    -

    - PropertiesRewritePolicy will add properties configured on the policy to the ThreadContext Map - being logged. The properties will not be added to the actual ThreadContext Map. The property - values may contain variables that will be evaluated when the configuration is processed as - well as when the event is logged. -

    - - - - - - - - - - - -
    Parameter NameTypeDescription
    propertiesProperty[]One of more Property elements to define the keys and values to be added to the ThreadContext Map.
    -

    - The following configuration shows a RewriteAppender configured to add a product key and its value - to the MapMessage: -

    -
    
    -
    -  
    -    
    -      
    -    
    -    
    -      
    -      
    -        ${sys:user.name}
    -        ${sys:environment}
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    LoggerNameLevelRewritePolicy
    -

    - You can use this policy to make loggers in third party code less chatty by changing event levels. - The LoggerNameLevelRewritePolicy will rewrite log event levels for a given logger name prefix. - You configure a LoggerNameLevelRewritePolicy with a logger name prefix and a pairs of levels, - where a pair defines a source level and a target level. -

    - - - - - - - - - - - - - - - - -
    Parameter NameTypeDescription
    loggerStringA logger name used as a prefix to test each event's logger name.
    LevelPairKeyValuePair[]An array of keys and their values, each key is a source level, each value a target level.
    -

    - The following configuration shows a RewriteAppender configured to map level INFO to DEBUG and level - WARN to INFO for all loggers that start with com.foo.bar. -

    -
    
    -
    -  
    -    
    -      
    -    
    -    
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - -

    The RollingFileAppender is an OutputStreamAppender that writes to the File named in the fileName parameter - and rolls the file over according the TriggeringPolicy and the RolloverPolicy. The - RollingFileAppender uses a RollingFileManager (which extends OutputStreamManager) to actually perform the - file I/O and perform the rollover. While RolloverFileAppenders from different Configurations cannot be - shared, the RollingFileManagers can be if the Manager is accessible. For example, two web applications in a - servlet container can have their own configuration and safely - write to the same file if Log4j is in a ClassLoader that is common to both of them.

    -

    - A RollingFileAppender requires a TriggeringPolicy and a - RolloverStrategy. The triggering policy determines if a rollover should - be performed while the RolloverStrategy defines how the rollover should be done. If no RolloverStrategy - is configured, RollingFileAppender will use the DefaultRolloverStrategy. - Since log4j-2.5, a custom delete action can be configured in the - DefaultRolloverStrategy to run at rollover. Since 2.8 if no file name is configured then - DirectWriteRolloverStrategy will be used instead of - DefaultRolloverStrategy. - Since log4j-2.9, a custom POSIX file attribute view action can be configured in the - DefaultRolloverStrategy to run at rollover, if not defined, inherited POSIX file attribute view from the RollingFileAppender will be applied. -

    -

    - File locking is not supported by the RollingFileAppender. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    RollingFileAppender Parameters
    Parameter NameTypeDescription
    appendbooleanWhen true - the default, records will be appended to the end of the file. When set to false, - the file will be cleared before new records are written.
    bufferedIObooleanWhen true - the default, records will be written to a buffer and the data will be written to - disk when the buffer is full or, if immediateFlush is set, when the record is written. - File locking cannot be used with bufferedIO. Performance tests have shown that using buffered I/O - significantly improves performance, even if immediateFlush is enabled.
    bufferSizeintWhen bufferedIO is true, this is the buffer size, the default is 8192 bytes.
    createOnDemandbooleanThe appender creates the file on-demand. The appender only creates the file when a log event - passes all filters and is routed to this appender. Defaults to false.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    fileNameStringThe name of the file to write to. If the file, or any of its parent directories, do not exist, - they will be created.
    filePatternStringThe pattern of the file name of the archived log file. The format of the pattern is - dependent on the RolloverPolicy that is used. The DefaultRolloverPolicy will accept both - a date/time pattern compatible with - SimpleDateFormat - and/or a %i which represents an integer counter. The pattern also supports interpolation at - runtime so any of the Lookups (such as the DateLookup) can - be included in the pattern.
    immediateFlushboolean

    When set to true - the default, each write will be followed by a flush. - This will guarantee the data is written - to disk but could impact performance.

    -

    Flushing after every write is only useful when using this - appender with synchronous loggers. Asynchronous loggers and - appenders will automatically flush at the end of a batch of events, - even if immediateFlush is set to false. This also guarantees - the data is written to disk but is more efficient.

    -
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is supplied the default pattern layout - of "%m%n" will be used.
    nameStringThe name of the Appender.
    policyTriggeringPolicyThe policy to use to determine if a rollover should occur.
    strategyRolloverStrategyThe strategy to use to determine the name and location of the archive file.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    filePermissionsString

    File attribute permissions in POSIX format to apply whenever the file is created.

    -

    Underlying files system shall support POSIX file attribute view.

    -

    Examples: rw------- or rw-rw-rw- etc...

    fileOwnerString

    File owner to define whenever the file is created.

    -

    Changing file's owner may be restricted for security reason and Operation not permitted IOException thrown. - Only processes with an effective user ID equal to the user ID - of the file or with appropriate privileges may change the ownership of a file - if _POSIX_CHOWN_RESTRICTED is in effect for path.

    -

    Underlying files system shall support file owner attribute view.

    -
    fileGroupString

    File group to define whenever the file is created.

    -

    Underlying files system shall support POSIX file attribute view.

    -
    - -

    Triggering Policies

    -
    Composite Triggering Policy
    -

    - The CompositeTriggeringPolicy combines multiple triggering policies and returns true if - any of the configured policies return true. The CompositeTriggeringPolicy is configured - simply by wrapping other policies in a Policies element. -

    -

    - For example, the following XML fragment defines policies that rollover the log when the JVM starts, - when the log size reaches twenty megabytes, and when the current date no longer matches the log’s - start date. -

    -
    
    -  
    -  
    -  
    -]]>
    -
    Cron Triggering Policy
    -

    The CronTriggeringPolicy triggers rollover based on a cron expression.

    - - - - - - - - - - - - - - - - - -
    CronTriggeringPolicy Parameters
    Parameter NameTypeDescription
    scheduleStringThe cron expression. The expression is the same as what is allowed in the Quartz scheduler. See - CronExpression - for a full description of the expression. -
    evaluateOnStartupbooleanOn startup the cron expression will be evaluated against the file's last modification timestamp. - If the cron expression indicates a rollover should have occurred between that time and the current - time the file will be immediately rolled over.
    -
    OnStartup Triggering Policy
    -

    - The OnStartupTriggeringPolicy policy causes a rollover if the log file is older than the - current JVM's start time and the minimum file size is met or exceeded. -

    - - - - - - - - - - - - -
    OnStartupTriggeringPolicy Parameters
    Parameter NameTypeDescription
    minSizelong - The minimum size the file must have to roll over. A size of zero will cause a roll over no matter - what the file size is. The default value is 1, which will prevent rolling over an empty file. -
    -

    - Google App Engine note:
    - When running in Google App Engine, the OnStartup policy causes a rollover if the log file is older - than the time when Log4J initialized. - (Google App Engine restricts access to certain classes so Log4J cannot determine JVM start time with - java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime() - and falls back to Log4J initialization time instead.) -

    -
    SizeBased Triggering Policy
    -

    - The SizeBasedTriggeringPolicy causes a rollover once the file has reached the specified - size. The size can be specified in bytes, with the suffix KB, MB or GB, for example 20MB. -

    -
    TimeBased Triggering Policy
    -

    - The TimeBasedTriggeringPolicy causes a rollover once the date/time pattern no longer - applies to the active file. This policy accepts an interval attribute which indicates how - frequently the rollover should occur based on the time pattern and a modulate boolean - attribute. -

    - - - - - - - - - - - - - - - - - - - - - - -
    TimeBasedTriggeringPolicy Parameters
    Parameter NameTypeDescription
    intervalintegerHow often a rollover should occur based on the most specific time unit in the date pattern. - For example, with a date pattern with hours as the most specific item and and increment of 4 rollovers - would occur every 4 hours. - The default value is 1.
    modulatebooleanIndicates whether the interval should be adjusted to cause the next rollover to occur on - the interval boundary. For example, if the item is hours, the current hour is 3 am and the - interval is 4 then the first rollover will occur at 4 am and then next ones will occur at - 8 am, noon, 4pm, etc.
    maxRandomDelayintegerIndicates the maximum number of seconds to randomly delay a rollover. By default, - this is 0 which indicates no delay. This setting is useful on servers where multiple - applications are configured to rollover log files at the same time and can spread - the load of doing so across time.
    -
    -

    Rollover Strategies

    -
    -
    Default Rollover Strategy
    -

    - The default rollover strategy accepts both a date/time pattern and an integer from the filePattern - attribute specified on the RollingFileAppender itself. If the date/time pattern - is present it will be replaced with the current date and time values. If the pattern contains an integer - it will be incremented on each rollover. If the pattern contains both a date/time and integer - in the pattern the integer will be incremented until the result of the date/time pattern changes. If - the file pattern ends with ".gz", ".zip", ".bz2", ".deflate", ".pack200", or ".xz" the resulting archive - will be compressed using the compression scheme that matches the suffix. The formats bzip2, Deflate, - Pack200 and XZ require Apache Commons Compress. - In addition, XZ requires XZ for Java. - The pattern may also contain lookup references that can be resolved at runtime such as is shown in the example - below. -

    -

    The default rollover strategy supports three variations for incrementing the counter. The first is - the "fixed window" strategy. To illustrate how it works, suppose that the min attribute is set to 1, - the max attribute is set to 3, the file name is "foo.log", and the file name pattern is "foo-%i.log". -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Number of rolloversActive output targetArchived log filesDescription
    0foo.log-All logging is going to the initial file.
    1foo.logfoo-1.logDuring the first rollover foo.log is renamed to foo-1.log. A new foo.log file is created and - starts being written to.
    2foo.logfoo-1.log, foo-2.logDuring the second rollover foo-1.log is renamed to foo-2.log and foo.log is renamed to - foo-1.log. A new foo.log file is created and starts being written to.
    3foo.logfoo-1.log, foo-2.log, foo-3.logDuring the third rollover foo-2.log is renamed to foo-3.log, foo-1.log is renamed to foo-2.log and - foo.log is renamed to foo-1.log. A new foo.log file is created and starts being written to.
    4foo.logfoo-1.log, foo-2.log, foo-3.logIn the fourth and subsequent rollovers, foo-3.log is deleted, foo-2.log is renamed to foo-3.log, - foo-1.log is renamed to foo-2.log and foo.log is renamed to foo-1.log. A new foo.log file is - created and starts being written to.
    -

    By way of contrast, when the fileIndex attribute is set to "max" but all the other settings - are the same the following actions will be performed. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Number of rolloversActive output targetArchived log filesDescription
    0foo.log-All logging is going to the initial file.
    1foo.logfoo-1.logDuring the first rollover foo.log is renamed to foo-1.log. A new foo.log file is created and - starts being written to.
    2foo.logfoo-1.log, foo-2.logDuring the second rollover foo.log is renamed to foo-2.log. A new foo.log file is created - and starts being written to.
    3foo.logfoo-1.log, foo-2.log, foo-3.logDuring the third rollover foo.log is renamed to foo-3.log. A new foo.log file is created and - starts being written to.
    4foo.logfoo-1.log, foo-2.log, foo-3.logIn the fourth and subsequent rollovers, foo-1.log is deleted, foo-2.log is renamed to foo-1.log, - foo-3.log is renamed to foo-2.log and foo.log is renamed to foo-3.log. A new foo.log file is - created and starts being written to.
    -

    - Finally, as of release 2.8, if the fileIndex attribute is set to "nomax" then the min and max values - will be ignored and file numbering will increment by 1 and each rollover will have an incrementally - higher value with no maximum number of files. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    DefaultRolloverStrategy Parameters
    Parameter NameTypeDescription
    fileIndexStringIf set to "max" (the default), files with a higher index will be newer than files with a - smaller index. If set to "min", file renaming and the counter will follow the Fixed Window strategy - described above.
    minintegerThe minimum value of the counter. The default value is 1.
    maxintegerThe maximum value of the counter. Once this values is reached older archives will be - deleted on subsequent rollovers. The default value is 7.
    compressionLevelinteger - Sets the compression level, 0-9, where 0 = none, 1 = best speed, through 9 = best compression. - Only implemented for ZIP files. -
    tempCompressedFilePatternStringThe pattern of the file name of the archived log file during compression.
    - -
    DirectWrite Rollover Strategy
    -

    - The DirectWriteRolloverStrategy causes log events to be written directly to files represented by the - file pattern. With this strategy file renames are not performed. If the size-based triggering policy - causes multiple files to be written durring the specified time period they will be numbered starting - at one and continually incremented until a time-based rollover occurs. -

    -

    - Warning: If the file pattern has a - suffix indicating compression should take place the current file will not be compressed when the - application is shut down. Furthermore, if the time changes such that the file pattern no longer - matches the current file it will not be compressed at startup either. -

    - - - - - - - - - - - - - - - - - - - - - - -
    DirectWriteRolloverStrategy Parameters
    Parameter NameTypeDescription
    maxFilesStringThe maximum number of files to allow in the time period matching the file pattern. If the - number of files is exceeded the oldest file will be deleted. If specified, the value must - be greater than 1. If the value is less than zero or omitted then the number of files will - not be limited.
    compressionLevelinteger - Sets the compression level, 0-9, where 0 = none, 1 = best speed, through 9 = best compression. - Only implemented for ZIP files. -
    tempCompressedFilePatternStringThe pattern of the file name of the archived log file during compression.
    -

    - Below is a sample configuration that uses a RollingFileAppender with both the time and size based - triggering policies, will create up to 7 archives on the same day (1-7) that are stored in a directory - based on the current year and month, and will compress each - archive using gzip: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - This second example shows a rollover strategy that will keep up to 20 files before removing them. -

    -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - Below is a sample configuration that uses a RollingFileAppender with both the time and size based - triggering policies, will create up to 7 archives on the same day (1-7) that are stored in a directory - based on the current year and month, and will compress each - archive using gzip and will roll every 6 hours when the hour is divisible by 6: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - This sample configuration uses a RollingFileAppender with both the cron and size based - triggering policies, and writes directly to an unlimited number of archive files. The cron - trigger causes a rollover every hour while the file size is limited to 250MB: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - This sample configuration is the same as the previous but limits the number of files saved each hour to 10: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    -
    Log Archive Retention Policy: Delete on Rollover
    -

    - Log4j-2.5 introduces a Delete action that gives users more control - over what files are deleted at rollover time than what was possible with the DefaultRolloverStrategy - max attribute. - The Delete action lets users configure one or more conditions that select the files to delete - relative to a base directory. -

    -

    - Note that it is possible to delete any file, not just rolled over log files, so use this action with care! - With the testMode parameter you can test your configuration without accidentally deleting the wrong files. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Delete Parameters
    Parameter NameTypeDescription
    basePathStringRequired. Base path from where to start scanning for files to delete.
    maxDepthintThe maximum number of levels of directories to visit. A value of 0 - means that only the starting file (the base path itself) is visited, - unless denied by the security manager. A value of - Integer.MAX_VALUE indicates that all levels should be visited. The default is 1, - meaning only the files in the specified base directory.
    followLinksbooleanWhether to follow symbolic links. Default is false.
    testModebooleanIf true, files are not deleted but instead a message is printed to the status logger at INFO level. - Use this to do a dry run to test if the configuration works as expected. Default is false.
    pathSorterPathSorterA plugin implementing the - PathSorter - interface to sort the files before selecting the files to delete. The default is to sort most recently - modified files first.
    pathConditions PathCondition[]

    Required if no ScriptCondition is specified. One or more PathCondition elements.

    -

    - If more than one condition is specified, - they all need to accept a path before it is deleted. Conditions can be nested, in which case the - inner condition(s) are evaluated only if the outer condition accepts the path. - If conditions are not nested they may be evaluated in any order. -

    -

    - Conditions can also be combined with the logical operators AND, OR and NOT by using the - IfAll, IfAny and IfNot composite conditions. -

    -

    Users can create custom conditions or use the built-in conditions:

    -
      -
    • IfFileName - accepts files whose path (relative to the base path) matches a - regular expression or a - glob.
    • -
    • IfLastModified - accepts files that are as old as or older than the specified - duration. -
    • -
    • IfAccumulatedFileCount - accepts paths after some count threshold is exceeded during the file tree walk.
    • -
    • IfAccumulatedFileSize - accepts paths after the accumulated file size threshold is exceeded during the file tree walk.
    • -
    • IfAll - accepts a path if all nested conditions accept it (logical AND). - Nested conditions may be evaluated in any order.
    • -
    • IfAny - accepts a path if one of the nested conditions accept it (logical OR). - Nested conditions may be evaluated in any order.
    • -
    • IfNot - accepts a path if the nested condition does not accept it (logical NOT).
    • -
    -
    scriptCondition ScriptCondition

    Required if no PathConditions are specified. A ScriptCondition element specifying a script.

    -

    - The ScriptCondition should contain a Script, - ScriptRef or ScriptFile element that specifies the logic to be executed. - (See also the ScriptFilter documentation for more examples of - configuring ScriptFiles and ScriptRefs.) -

    -

    The script is passed a number of parameters, - including a list of paths found under the base path (up to maxDepth) - and must return a list with the paths to delete.

    -
    -
    - - - - - - - - - - - - - - - - - - - - - - -
    IfFileName Condition Parameters
    Parameter NameTypeDescription
    globStringRequired if regex not specified. - Matches the relative path (relative to the base path) using a limited pattern language that resembles regular expressions but with a - simpler syntax. -
    regexStringRequired if glob not specified. - Matches the relative path (relative to the base path) using a regular expression as defined by the - Pattern class. -
    nestedConditionsPathCondition[]An optional set of nested PathConditions. If any nested conditions - exist they all need to accept the file before it is deleted. Nested conditions are only evaluated if the - outer condition accepts a file (if the path name matches). -
    -
    - - - - - - - - - - - - - - - - - -
    IfLastModified Condition Parameters
    Parameter NameTypeDescription
    ageStringRequired. - Specifies a duration. - The condition accepts files that are as old or older than the specified duration. -
    nestedConditionsPathCondition[]An optional set of nested PathConditions. If any nested conditions - exist they all need to accept the file before it is deleted. Nested conditions are only evaluated if the - outer condition accepts a file (if the file is old enough). -
    -
    - - - - - - - - - - - - - - - - - -
    IfAccumulatedFileCount Condition Parameters
    Parameter NameTypeDescription
    exceedsintRequired. - The threshold count from which files will be deleted. -
    nestedConditionsPathCondition[]An optional set of nested PathConditions. If any nested conditions - exist they all need to accept the file before it is deleted. Nested conditions are only evaluated if the - outer condition accepts a file (if the threshold count has been exceeded). -
    -
    - - - - - - - - - - - - - - - - - -
    IfAccumulatedFileSize Condition Parameters
    Parameter NameTypeDescription
    exceedsStringRequired. - The threshold accumulated file size from which files will be deleted. - The size can be specified in bytes, with the suffix KB, MB or GB, for example 20MB. -
    nestedConditionsPathCondition[]An optional set of nested PathConditions. If any nested conditions - exist they all need to accept the file before it is deleted. Nested conditions are only evaluated if the - outer condition accepts a file (if the threshold accumulated file size has been exceeded). -
    -

    - Below is a sample configuration that uses a RollingFileAppender with the cron - triggering policy configured to trigger every day at midnight. - Archives are stored in a directory based on the current year and month. - All files under the base directory that match the "*/app-*.log.gz" glob and are 60 days old - or older are deleted at rollover time. -

    - -
    
    -
    -  
    -    logs
    -  
    -  
    -    
    -      
    -      
    -      
    -        
    -          
    -          
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - Below is a sample configuration that uses a RollingFileAppender with both the time and size based - triggering policies, will create up to 100 archives on the same day (1-100) that are stored in a directory - based on the current year and month, and will compress each - archive using gzip and will roll every hour. - - During every rollover, this configuration will delete files that match "*/app-*.log.gz" - and are 30 days old or older, - but keep the most recent 100 GB or the most recent 10 files, whichever comes first. -

    - -
    
    -
    -  
    -    logs
    -  
    -  
    -    
    -      
    -      
    -        
    -        
    -      
    -      
    -        
    -        
    -          
    -            
    -              
    -                
    -                
    -              
    -            
    -          
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    - - - - - - - - - - - - -
    ScriptCondition Parameters
    Parameter NameTypeDescription
    scriptScript, ScriptFile or ScriptRefThe Script element that specifies the logic to be executed. The script is passed - a list of paths found under the base path and must return the paths to delete as a - java.util.List<PathWithAttributes>. - See also the ScriptFilter documentation for an example of - how ScriptFiles and ScriptRefs can be configured. -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Script Parameters
    Parameter NameTypeDescription
    basePathjava.nio.file.PathThe directory from where the Delete action started scanning for - files to delete. Can be used to relativize the paths in the pathList.
    pathListjava.util.List<PathWithAttributes>The list of paths found under the base path up to the specified max depth, - sorted most recently modified files first. - The script is free to modify and return this list.
    statusLoggerStatusLoggerThe StatusLogger that can be used to log internal events during script execution.
    configurationConfigurationThe Configuration that owns this ScriptCondition.
    substitutorStrSubstitutorThe StrSubstitutor used to replace lookup variables.
    ?StringAny properties declared in the configuration.
    -

    - Below is a sample configuration that uses a RollingFileAppender with the cron - triggering policy configured to trigger every day at midnight. - Archives are stored in a directory based on the current year and month. - The script returns a list of rolled over files under the base directory dated Friday the 13th. - The Delete action will delete all files returned by the script. -

    - -
    
    -
    -  
    -    logs
    -  
    -  
    -    
    -      
    -      
    -      
    -        
    -          
    -            
    -          
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -
    -
    Log Archive File Attribute View Policy: Custom file attribute on Rollover
    -

    - Log4j-2.9 introduces a PosixViewAttribute action that gives users more control - over which file attribute permissions, owner and group should be applied. - The PosixViewAttribute action lets users configure one or more conditions that select the eligible files - relative to a base directory. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    PosixViewAttribute Parameters
    Parameter NameTypeDescription
    basePathStringRequired. Base path from where to start scanning for files to apply attributes.
    maxDepthintThe maximum number of levels of directories to visit. A value of 0 - means that only the starting file (the base path itself) is visited, - unless denied by the security manager. A value of - Integer.MAX_VALUE indicates that all levels should be visited. The default is 1, - meaning only the files in the specified base directory.
    followLinksbooleanWhether to follow symbolic links. Default is false.
    pathConditionsPathCondition[]see DeletePathCondition
    filePermissionsString

    File attribute permissions in POSIX format to apply when action is executed.

    -

    Underlying files system shall support POSIX file attribute view.

    -

    Examples: rw------- or rw-rw-rw- etc...

    fileOwnerString

    File owner to define when action is executed.

    -

    Changing file's owner may be restricted for security reason and Operation not permitted IOException thrown. - Only processes with an effective user ID equal to the user ID - of the file or with appropriate privileges may change the ownership of a file - if _POSIX_CHOWN_RESTRICTED is in effect for path.

    -

    Underlying files system shall support file owner attribute view.

    -
    fileGroupString

    File group to define whene action is executed.

    -

    Underlying files system shall support POSIX file attribute view.

    -
    - -

    - Below is a sample configuration that uses a RollingFileAppender and defines different POSIX file attribute view for current and rolled log files. -

    - -
    
    -
    -  
    -    logs
    -  
    -  
    -    
    -      
    -      
    -      
    -        
    -        	
    -        
    -      
    -    
    -  
    -
    -  
    -    
    -      
    -    
    -  
    -
    -]]>
    - - -
    - -

    - The RollingRandomAccessFileAppender is similar to the standard - RollingFileAppender - except it is always buffered (this cannot be switched off) and - internally it uses a ByteBuffer + RandomAccessFile - instead of a BufferedOutputStream. - We saw a 20-200% performance improvement compared to - RollingFileAppender with "bufferedIO=true" - in our measurements. - - The RollingRandomAccessFileAppender writes to the File named in the - fileName parameter and rolls the file over according the - TriggeringPolicy and the RolloverPolicy. - - Similar to the RollingFileAppender, RollingRandomAccessFileAppender uses a RollingRandomAccessFileManager - to actually perform the file I/O and perform the rollover. While RollingRandomAccessFileAppender - from different Configurations cannot be shared, the RollingRandomAccessFileManagers can be - if the Manager is accessible. For example, two web applications in a servlet - container can have their own configuration and safely write to the - same file if Log4j is in a ClassLoader that is common to both of them. -

    -

    - A RollingRandomAccessFileAppender requires a - TriggeringPolicy and a - RolloverStrategy. - The triggering policy determines if a rollover should be performed - while the RolloverStrategy defines how the rollover should be done. - If no RolloverStrategy is configured, RollingRandomAccessFileAppender will use the - DefaultRolloverStrategy. - Since log4j-2.5, a custom delete action can be configured in the - DefaultRolloverStrategy to run at rollover. -

    -

    - File locking is not supported by the RollingRandomAccessFileAppender. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    RollingRandomAccessFileAppender Parameters
    Parameter NameTypeDescription
    appendbooleanWhen true - the default, records will be appended to the end - of the file. When set to false, - the file will be cleared before - new records are written. -
    filterFilterA Filter to determine if the event should be handled by this - Appender. More than one Filter - may be used by using a - CompositeFilter. -
    fileNameStringThe name of the file to write to. If the file, or any of its - parent directories, do not exist, - they will be created. -
    filePatternString - The pattern of the file name of the archived log file. The format - of the pattern should is - dependent on the RolloverPolicy that is - used. The DefaultRolloverPolicy - will accept both - a date/time - pattern compatible with - - SimpleDateFormat - - and/or a %i which represents an integer counter. The pattern - also supports interpolation at - runtime so any of the Lookups (such - as the - DateLookup - can - be included in the pattern. -
    immediateFlushboolean

    When set to true - the default, each write will be followed by a flush. - This will guarantee the data is written - to disk but could impact performance.

    -

    Flushing after every write is only useful when using this - appender with synchronous loggers. Asynchronous loggers and - appenders will automatically flush at the end of a batch of events, - even if immediateFlush is set to false. This also guarantees - the data is written to disk but is more efficient.

    -
    bufferSizeintThe buffer size, defaults to 262,144 bytes (256 * 1024).
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is supplied the default pattern layout - of "%m%n" will be used.
    nameStringThe name of the Appender.
    policyTriggeringPolicyThe policy to use to determine if a rollover should occur. -
    strategyRolloverStrategyThe strategy to use to determine the name and location of the - archive file. -
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    filePermissionsString

    File attribute permissions in POSIX format to apply whenever the file is created.

    -

    Underlying files system shall support POSIX file attribute view.

    -

    Examples: rw------- or rw-rw-rw- etc...

    fileOwnerString

    File owner to define whenever the file is created.

    -

    Changing file's owner may be restricted for security reason and Operation not permitted IOException thrown. - Only processes with an effective user ID equal to the user ID - of the file or with appropriate privileges may change the ownership of a file - if _POSIX_CHOWN_RESTRICTED is in effect for path.

    -

    Underlying files system shall support file owner attribute view.

    -
    fileGroupString

    File group to define whenever the file is created.

    -

    Underlying files system shall support POSIX file attribute view.

    -
    - -

    Triggering Policies

    -

    - See - RollingFileAppender Triggering Policies. -

    - -

    Rollover Strategies

    -

    - See - RollingFileAppender Rollover Strategies. -

    - -

    - Below is a sample configuration that uses a RollingRandomAccessFileAppender - with both the time and size based - triggering policies, will create - up to 7 archives on the same day (1-7) that - are stored in a - directory - based on the current year and month, and will compress - each - archive using gzip: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - This second example shows a rollover strategy that will keep up to - 20 files before removing them. -

    -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - Below is a sample configuration that uses a RollingRandomAccessFileAppender - with both the time and size based - triggering policies, will create - up to 7 archives on the same day (1-7) that - are stored in a - directory - based on the current year and month, and will compress - each - archive using gzip and will roll every 6 hours when the hour is - divisible - by 6: -

    - -
    
    -
    -  
    -    
    -      
    -        %d %p %c{1.} [%t] %m%n
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - -

    - The RoutingAppender evaluates LogEvents and then routes them to a subordinate Appender. The target - Appender may be an appender previously configured and may be referenced by its name or the - Appender can be dynamically created as needed. The RoutingAppender should be configured after any - Appenders it references to allow it to shut down properly. -

    -

    - You can also configure a RoutingAppender with scripts: you can run a script when the appender starts - and when a route is chosen for an log event. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    RoutingAppender Parameters
    Parameter NameTypeDescription
    FilterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    nameStringThe name of the Appender.
    RewritePolicyRewritePolicyThe RewritePolicy that will manipulate the LogEvent.
    RoutesRoutesContains one or more Route declarations to identify the criteria for choosing Appenders.
    ScriptScript -

    - This Script runs when Log4j starts the RoutingAppender and returns a String Route key to - determine the default Route. -

    -

    - This script is passed the following variables: -

    - - - - - - - - - - - - - - - - - -
    RoutingAppender Script Parameters
    Parameter NameTypeDescription
    configurationConfigurationThe active Configuration.
    staticVariablesMap - A Map shared between all script invocations for this appender instance. This is - the same map passed to the Routes Script. -
    -
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    -

    - In this example, the script causes the "ServiceWindows" route to be the default route on Windows and - "ServiceOther" on all other operating systems. Note that the List Appender is one of our test appenders, - any appender can be used, it is only used as a shorthand. -

    -
    
    -
    -  
    -    
    -      
    -      
    -        
    -          
    -        
    -        
    -          
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    Routes

    -

    - The Routes element accepts a single attribute named "pattern". The pattern is evaluated - against all the registered Lookups and the result is used to select a Route. Each Route may be - configured with a key. If the key matches the result of evaluating the pattern then that Route - will be selected. If no key is specified on a Route then that Route is the default. Only one Route - can be configured as the default. -

    -

    - The Routes element may contain a Script child element. If specified, the Script is run for each - log event and returns the String Route key to use. -

    -

    - You must specify either the pattern attribute or the Script element, but not both. -

    -

    - Each Route must reference an Appender. If the Route contains a ref attribute then the - Route will reference an Appender that was defined in the configuration. If the Route contains an - Appender definition then an Appender will be created within the context of the RoutingAppender and - will be reused each time a matching Appender name is referenced through a Route. -

    -

    - This script is passed the following variables: -

    - - - - - - - - - - - - - - - - - - - - - - -
    RoutingAppender Routes Script Parameters
    Parameter NameTypeDescription
    configurationConfigurationThe active Configuration.
    staticVariablesMap - A Map shared between all script invocations for this appender instance. This is - the same map passed to the Routes Script. -
    logEventLogEventThe log event.
    -

    - In this example, the script runs for each log event and picks a route based on the presence of a - Marker named "AUDIT". -

    -
    
    -
    -  
    -    
    -    
    -      
    -      
    -      
    -    
    -    
    -      
    -        
    -        
    -          
    -            
    -              %d %p %c{1.} [%t] %m%n
    -            
    -            
    -          
    -        
    -        
    -        
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -
    -]]>
    -

    Purge Policy

    -

    The RoutingAppender can be configured with a PurgePolicy whose purpose is to stop and remove dormant - Appenders that have been dynamically created by the RoutingAppender. Log4j currently provides the - IdlePurgePolicy as the only PurgePolicy available for cleaning up the Appenders. The IdlePurgePolicy - accepts 2 attributes; timeToLive, which is the number of timeUnits the Appender should survive without - having any events sent to it, and timeUnit, the String representation of java.util.concurrent.TimeUnit - which is used with the timeToLive attribute.

    -

    - Below is a sample configuration that uses a RoutingAppender to route all Audit events to - a FlumeAppender and all other events will be routed to a RollingFileAppender that captures only - the specific event type. Note that the AuditAppender was predefined while the RollingFileAppenders - are created as needed. -

    - -
    
    -
    -  
    -    
    -      
    -      
    -      
    -    
    -    
    -      
    -        
    -          
    -            
    -              %d %p %c{1.} [%t] %m%n
    -            
    -            
    -          
    -        
    -        
    -      
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    -
    - -

    - As of Log4j 2.11.0, Simple Mail Transfer Protocol (SMTP) support has moved from the existing module - logj-core to the new module log4j-smtp. -

    -

    - Sends an e-mail when a specific logging event occurs, typically on errors or fatal errors. -

    -

    - The number of logging events delivered in this e-mail depend on the value of - BufferSize option. The SMTPAppender keeps only the last - BufferSize logging events in its cyclic buffer. This keeps - memory requirements at a reasonable level while still delivering useful - application context. All events in the buffer are included in the email. - The buffer will contain the most recent events of level TRACE to WARN - preceding the event that triggered the email. -

    -

    - The default behavior is to trigger sending an email whenever an ERROR or higher - severity event is logged and to format it as HTML. The circumstances on when the - email is sent can be controlled by setting one or more filters on the Appender. - As with other Appenders, the formatting can be controlled by specifying a Layout - for the Appender. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SMTPAppender Parameters
    Parameter NameTypeDescription
    nameStringThe name of the Appender.
    fromStringThe email address of the sender.
    replyToStringThe comma-separated list of reply-to email addresses.
    toStringThe comma-separated list of recipient email addresses.
    ccStringThe comma-separated list of CC email addresses.
    bccStringThe comma-separated list of BCC email addresses.
    subjectStringThe subject of the email message.
    bufferSizeintegerThe maximum number of log events to be buffered for inclusion in the message. Defaults to 512.
    layoutLayoutThe Layout to use to format the LogEvent. If no layout is supplied HTML layout will be used.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter. -
    smtpDebugbooleanWhen set to true enables session debugging on STDOUT. Defaults to false.
    smtpHostStringThe SMTP hostname to send to. This parameter is required.
    smtpPasswordStringThe password required to authenticate against the SMTP server.
    smtpPortintegerThe SMTP port to send to.
    smtpProtocolStringThe SMTP transport protocol (such as "smtps", defaults to "smtp").
    smtpUsernameStringThe username required to authenticate against the SMTP server.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    -
    
    -
    -  
    -    
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    -
    - -

    - When the configuration is built, the ScriptAppenderSelector appender calls a Script - to compute an appender name. Log4j then creates one of the appender named listed under - AppenderSet using the name of the ScriptAppenderSelector. After configuration, Log4j - ignores the ScriptAppenderSelector. Log4j only builds the one selected appender from the - configuration tree, and ignores other AppenderSet child nodes. -

    -

    - In the following example, the script returns the name "List2". The appender name is recorded under - the name of the ScriptAppenderSelector, not the name of the selected appender, in this example, - "SelectIt". -

    -
    
    -  
    -    
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -
    -
    - -

    - The SocketAppender is an OutputStreamAppender that writes its output to a remote destination - specified by a host and port. The data can be sent over either TCP or UDP and can be sent in any format. - You can optionally secure communication with SSL. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SocketAppender Parameters
    Parameter NameTypeDescription
    nameStringThe name of the Appender.
    hostStringThe name or address of the system that is listening for log events. This parameter is required.
    portintegerThe port on the host that is listening for log events. This parameter must be specified.
    protocolString"TCP" (default), "SSL" or "UDP".
    SSLSslConfigurationContains the configuration for the KeyStore and TrustStore. See SSL.
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    immediateFailbooleanWhen set to true, log events will not wait to try to reconnect and will fail immediately if the - socket is not available.
    immediateFlushbooleanWhen set to true - the default, each write will be followed by a flush. - This will guarantee the data is written - to disk but could impact performance.
    bufferedIObooleanWhen true - the default, events are written to a buffer and the data will be written to - the socket when the buffer is full or, if immediateFlush is set, when the record is written.
    bufferSizeintWhen bufferedIO is true, this is the buffer size, the default is 8192 bytes.
    layoutLayoutThe Layout to use to format the LogEvent. Required, there is no default. - New since 2.9, in previous versions SerializedLayout was default.
    reconnectionDelayMillisintegerIf set to a value greater than 0, after an error the SocketManager will attempt to reconnect to - the server after waiting the specified number of milliseconds. If the reconnect fails then - an exception will be thrown (which can be caught by the application if ignoreExceptions is - set to false).
    connectTimeoutMillisintegerThe connect timeout in milliseconds. The default is 0 (infinite timeout, like Socket.connect() - methods).
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    - -

    - This is an unsecured TCP configuration: -

    -
    
    -
    -  
    -    
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - -

    - This is a secured SSL configuration: -

    -
    
    -
    -  
    -    
    -      
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - - -

    - Several appenders can be configured to use either a plain network connection or a Secure Socket Layer (SSL) - connection. This section documents the parameters available for SSL configuration. -

    - - - - - - - - - - - - - - - - - - - - - - -
    SSL Configuration Parameters
    Parameter NameTypeDescription
    protocolStringSSL if omitted. - See also Standard names.
    KeyStoreKeyStoreContains your private keys and certificates, - and determines which authentication credentials to send to the remote host.
    TrustStoreTrustStoreContains the CA certificates of the remote counterparty. - Determines whether the remote authentication credentials - (and thus the connection) should be trusted.
    - -

    KeyStore

    -

    - The keystore is meant to contain your private keys and certificates, - and determines which authentication credentials to send to the remote host. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    KeyStore Configuration Parameters
    Parameter NameTypeDescription
    locationStringPath to the keystore file.
    passwordchar[]Plain text password to access the keystore. Cannot be combined with either - passwordEnvironmentVariable or passwordFile.
    passwordEnvironmentVariableStringName of an environment variable that holds the password. Cannot be combined with either - password or passwordFile.
    passwordFileStringPath to a file that holds the password. Cannot be combined with either - password or passwordEnvironmentVariable.
    typeStringOptional KeyStore type, e.g. JKS, PKCS12, PKCS11, - BKS, Windows-MY/Windows-ROOT, KeychainStore, etc. - The default is JKS. See also Standard types.
    keyManagerFactoryAlgorithmStringOptional KeyManagerFactory algorithm. The default is SunX509. - See also Standard algorithms.
    - -

    TrustStore

    -

    - The trust store is meant to contain the CA certificates you are willing to trust - when a remote party presents its certificate. Determines whether the remote authentication credentials - (and thus the connection) should be trusted. -

    - In some cases, they can be one and the same store, - although it is often better practice to use distinct stores (especially when they are file-based). -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    TrustStore Configuration Parameters
    Parameter NameTypeDescription
    locationStringPath to the keystore file.
    passwordchar[]Plain text password to access the keystore. Cannot be combined with either - passwordEnvironmentVariable or passwordFile.
    passwordEnvironmentVariableStringName of an environment variable that holds the password. Cannot be combined with either - password or passwordFile.
    passwordFileStringPath to a file that holds the password. Cannot be combined with either - password or passwordEnvironmentVariable.
    typeStringOptional KeyStore type, e.g. JKS, PKCS12, PKCS11, - BKS, Windows-MY/Windows-ROOT, KeychainStore, etc. - The default is JKS. See also Standard types.
    trustManagerFactoryAlgorithmStringOptional TrustManagerFactory algorithm. The default is SunX509. - See also Standard algorithms.
    - -

    Example

    -
    
    -        
    -        
    -      
    -  ...]]>
    - -
    -
    - -

    - The SyslogAppender is a SocketAppender that writes its output to a remote destination - specified by a host and port in a format that conforms with either the BSD Syslog format or the RFC 5424 - format. The data can be sent over either TCP or UDP. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SyslogAppender Parameters
    Parameter NameTypeDescription
    advertisebooleanIndicates whether the appender should be advertised.
    appNameStringThe value to use as the APP-NAME in the RFC 5424 syslog record.
    charsetStringThe character set to use when converting the syslog String to a byte array. The String must be - a valid Charset. - If not specified, the default system Charset will be used.
    connectTimeoutMillisintegerThe connect timeout in milliseconds. The default is 0 (infinite timeout, like Socket.connect() - methods).
    enterpriseNumberintegerThe IANA enterprise number as described in - RFC 5424
    filterFilterA Filter to determine if the event should be handled by this Appender. More than one Filter - may be used by using a CompositeFilter.
    facilityStringThe facility is used to try to classify the message. The facility option must be set to one of - "KERN", "USER", "MAIL", "DAEMON", "AUTH", "SYSLOG", "LPR", "NEWS", "UUCP", "CRON", "AUTHPRIV", - "FTP", "NTP", "AUDIT", "ALERT", "CLOCK", "LOCAL0", "LOCAL1", "LOCAL2", "LOCAL3", "LOCAL4", "LOCAL5", - "LOCAL6", or "LOCAL7". These values may be specified as upper or lower case characters.
    formatStringIf set to "RFC5424" the data will be formatted in accordance with RFC 5424. Otherwise, it will - be formatted as a BSD Syslog record. Note that although BSD Syslog records are required to be - 1024 bytes or shorter the SyslogLayout does not truncate them. The RFC5424Layout also does not - truncate records since the receiver must accept records of up to 2048 bytes and may accept records - that are longer.
    hostStringThe name or address of the system that is listening for log events. This parameter is required.
    idStringThe default structured data id to use when formatting according to RFC 5424. If the LogEvent contains - a StructuredDataMessage the id from the Message will be used instead of this value.
    ignoreExceptionsbooleanThe default is true, causing exceptions encountered while appending events to be - internally logged and then ignored. When set to false exceptions will be propagated to the - caller, instead. You must set this to false when wrapping this Appender in a - FailoverAppender.
    immediateFailbooleanWhen set to true, log events will not wait to try to reconnect and will fail immediately if the - socket is not available.
    immediateFlushbooleanWhen set to true - the default, each write will be followed by a flush. - This will guarantee the data is written - to disk but could impact performance.
    includeMDCbooleanIndicates whether data from the ThreadContextMap will be included in the RFC 5424 Syslog record. - Defaults to true.
    LayoutLayoutA custom layout which overrides the format setting.
    loggerFieldsList of KeyValuePairsAllows arbitrary PatternLayout patterns to be included as specified ThreadContext fields; no default - specified. To use, include a >LoggerFields< nested element, containing one or more - >KeyValuePair< elements. Each >KeyValuePair< must have a key attribute, which - specifies the key name which will be used to identify the field within the MDC Structured Data element, - and a value attribute, which specifies the PatternLayout pattern to use as the value.
    mdcExcludesStringA comma separated list of mdc keys that should be excluded from the LogEvent. This is mutually - exclusive with the mdcIncludes attribute. This attribute only applies to RFC 5424 syslog records.
    mdcIncludesStringA comma separated list of mdc keys that should be included in the FlumeEvent. Any keys in the MDC - not found in the list will be excluded. This option is mutually exclusive with the mdcExcludes - attribute. This attribute only applies to RFC 5424 syslog records.
    mdcRequiredStringA comma separated list of mdc keys that must be present in the MDC. If a key is not present a - LoggingException will be thrown. This attribute only applies to RFC 5424 syslog records.
    mdcPrefixStringA string that should be prepended to each MDC key in order to distinguish it from event attributes. - The default string is "mdc:". This attribute only applies to RFC 5424 syslog records.
    messageIdStringThe default value to be used in the MSGID field of RFC 5424 syslog records.
    nameStringThe name of the Appender.
    newLinebooleanIf true, a newline will be appended to the end of the syslog record. The default is false.
    portintegerThe port on the host that is listening for log events. This parameter must be specified.
    protocolString"TCP" or "UDP". This parameter is required.
    SSLSslConfigurationContains the configuration for the KeyStore and TrustStore. See SSL.
    reconnectionDelayMillisintegerIf set to a value greater than 0, after an error the SocketManager will attempt to reconnect to - the server after waiting the specified number of milliseconds. If the reconnect fails then - an exception will be thrown (which can be caught by the application if ignoreExceptions is - set to false).
    -

    - A sample syslogAppender configuration that is configured with two SyslogAppenders, one using the BSD - format and one using RFC 5424. -

    - -
    
    -
    -  
    -    
    -    
    -  
    -  
    -    
    -      
    -    
    -    
    -      
    -    
    -  
    -]]>
    - -

    - For SSL this appender writes its output to a remote destination specified by a host and port over SSL in - a format that conforms with either the BSD Syslog format or the RFC 5424 format. -

    - -
    
    -
    -  
    -    
    -      
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    - - - - -

    - As of Log4j 2.11.0, ZeroMQ/JeroMQ support has moved from the existing module logj-core to the new module log4j-jeromq. -

    -

    - The ZeroMQ appender uses the JeroMQ library to send log - events to one or more ZeroMQ endpoints. -

    -

    - This is a simple JeroMQ configuration: -

    -
    
    -
    -  
    -    
    -      tcp://*:5556
    -      ipc://info-topic
    -    
    -  
    -  
    -    
    -      
    -    
    -  
    -]]>
    -

    - The table below describes all options. Please consult the JeroMQ and ZeroMQ documentation for details. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    JeroMQ Parameters
    Parameter NameTypeDescription
    nameStringThe name of the Appender. Required.
    LayoutlayoutThe Layout to use to format the LogEvent. If no layout is supplied the default pattern layout - of "%m%n" will be used.
    FiltersFilterThe Filter(s) of the Appender.
    PropertiesProperty[]One or more Property elements, named endpoint.
    ignoreExceptionsbooleanIf true, exceptions will be logged and suppressed. If false errors will be logged and then passed to the application.
    affinitylongThe ZMQ_AFFINITY option. Defaults to 0.
    backloglongThe ZMQ_BACKLOG option. Defaults to 100.
    delayAttachOnConnectbooleanThe ZMQ_DELAY_ATTACH_ON_CONNECT option. Defaults to false.
    identitybyte[]The ZMQ_IDENTITY option. Defaults to none.
    ipv4OnlybooleanThe ZMQ_IPV4ONLY option. Defaults to true.
    lingerlongThe ZMQ_LINGER option. Defaults to -1.
    maxMsgSizelongThe ZMQ_MAXMSGSIZE option. Defaults to -1.
    rcvHwmlongThe ZMQ_RCVHWM option. Defaults to 1000.
    receiveBufferSizelongThe ZMQ_RCVBUF option. Defaults to 0.
    receiveTimeOutintThe ZMQ_RCVTIMEO option. Defaults to -1.
    reconnectIVLlongThe ZMQ_RECONNECT_IVL option. Defaults to 100.
    reconnectIVLMaxlongThe ZMQ_RECONNECT_IVL_MAX option. Defaults to 0.
    sendBufferSizelongThe ZMQ_SNDBUF option. Defaults to 0.
    sendTimeOutintThe ZMQ_SNDTIMEO option. Defaults to -1.
    sndHwmlongThe ZMQ_SNDHWM option. Defaults to 1000.
    tcpKeepAliveintThe ZMQ_TCP_KEEPALIVE option. Defaults to -1.
    tcpKeepAliveCountlongThe ZMQ_TCP_KEEPALIVE_CNT option. Defaults to -1.
    tcpKeepAliveIdlelongThe ZMQ_TCP_KEEPALIVE_IDLE option. Defaults to -1.
    tcpKeepAliveIntervallongThe ZMQ_TCP_KEEPALIVE_INTVL option. Defaults to -1.
    xpubVerbosebooleanThe ZMQ_XPUB_VERBOSE option. Defaults to false.
    - - -
    - - From ee96440d5e58c92884680ce04f64960c4410cbab Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 17:38:23 -0500 Subject: [PATCH 0120/2347] LOG4J2-1802: Convert index page to asciidoc --- pom.xml | 6 ++ .../index.md.vm => asciidoc/index.adoc} | 82 ++++++++++--------- 2 files changed, 49 insertions(+), 39 deletions(-) rename src/site/{markdown/index.md.vm => asciidoc/index.adoc} (70%) diff --git a/pom.xml b/pom.xml index c417cd8b346..dfa6b5d92e2 100644 --- a/pom.xml +++ b/pom.xml @@ -1139,6 +1139,12 @@ ${log4jParentDir}/src/site + + + + ${Log4jReleaseVersion} + + - -#set($h1='#') -#set($h2='##') -#set($h3='###') - -$h1 Apache Log4j 2 +//// += Apache Log4j 2 Apache Log4j 2 is an upgrade to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides many of the improvements available in Logback while fixing some inherent problems in Logback's architecture. -$h2 Features +== Features -$h3 API Separation +=== API Separation The API for Log4j is separate from the implementation making it clear for application developers which classes and methods they can use while ensuring forward compatibility. This allows the Log4j team to improve the implementation safely and in a compatible manner. -$h3 Improved Performance +=== Improved Performance Log4j 2 contains next-generation Asynchronous Loggers based on the LMAX Disruptor library. In multi-threaded scenarios Asynchronous Loggers have 18 times higher throughput and orders of magnitude lower latency than Log4j 1.x and Logback. -See [Asynchronous Logging Performance](manual/async.html#Performance) for details. Otherwise, Log4j 2 significantly +See link:manual/async.html#Performance[Asynchronous Logging Performance] for details. Otherwise, Log4j 2 significantly outperforms Log4j 1.x, Logback and java.util.logging, especially in multi-threaded applications. -See [Performance](performance.html) for more information. +See link:performance.html[Performance] for more information. -$h3 Support for multiple APIs +=== Support for multiple APIs While the Log4j 2 API will provide the best performance, Log4j 2 provides support for the Log4j 1.2, SLF4J, Commons Logging and java.util.logging (JUL) APIs. -$h3 Avoid lock-in +=== Avoid lock-in Applications coded to the Log4j 2 API always have the option to use any SLF4J-compliant library as their logger implementation with the log4j-to-slf4j adapter. -$h3 Automatic Reloading of Configurations +=== Automatic Reloading of Configurations Like Logback, Log4j 2 can automatically reload its configuration upon modification. Unlike Logback, it will do so without losing log events while reconfiguration is taking place. -$h3 Advanced Filtering +=== Advanced Filtering Like Logback, Log4j 2 supports filtering based on context data, markers, regular expressions, and other components in the Log event. Filtering can be specified to apply to all events before being passed to Loggers or as they pass through Appenders. In addition, filters can also be associated with Loggers. Unlike Logback, you can use a common Filter class in any of these circumstances. -$h3 Plugin Architecture +=== Plugin Architecture Log4j uses the plugin pattern to configure components. As such, you do not need to write code to create and configure an Appender, Layout, Pattern Converter, and so on. Log4j automatically recognizes plugins and uses them when a configuration references them. -$h3 Property Support +=== Property Support You can reference properties in a configuration, Log4j will directly replace them, or Log4j will pass them to an underlying component that will dynamically resolve them. Properties come from values defined in the configuration file, system properties, environment variables, the ThreadContext Map, and data present in the event. Users can further -customize the property providers by adding their own [Lookup](manual/lookups.html) Plugin. +customize the property providers by adding their own link:manual/lookups.html[Lookup] Plugin. -$h3 Java 8 Lambda Support +=== Java 8 Lambda Support Previously, if a log message was expensive to construct, you would often explicitly check if the requested log level is enabled before constructing the message. Client code running on Java 8 can benefit from Log4j's -[lambda support](manual/api.html#LambdaSupport). Since Log4j will not evaluate a lambda expression if the requested log +link:manual/api.html#LambdaSupport[lambda support]. Since Log4j will not evaluate a lambda expression if the requested log level is not enabled, the same effect can be achieved with less code. -$h3 Custom Log Levels +=== Custom Log Levels -In Log4j 2, [custom log levels](manual/customloglevels.html) can easily be defined in code or in configuration. No +In Log4j 2, link:manual/customloglevels.html[custom log levels] can easily be defined in code or in configuration. No subclassing is required. -$h3 Garbage-free +=== Garbage-free -During steady state logging, Log4j 2 is [garbage-free](manual/garbagefree.html) in stand-alone applications, and low +During steady state logging, Log4j 2 is link:manual/garbagefree.html[garbage-free] in stand-alone applications, and low garbage in web applications. This reduces pressure on the garbage collector and can give better response time performance. -#h3 Integrating with Application Servers +=== Integrating with Application Servers Version 2.10.0 introduces a the module log4j-appserver to improve integration with Apache Tomcat and Eclipse Jetty. -$h2 Documentation +== Documentation -The Log4j 2 User's Guide is available on this [site](manual/index.html) or as a downloadable -[PDF](log4j-users-guide.pdf). +The Log4j 2 User's Guide is available on this link:manual/index.html[site] or as a downloadable +link:log4j-users-guide.pdf[PDF]. -$h2 Requirements +== Requirements Log4j 2.4 and greater requires Java 7, versions 2.0-alpha1 to 2.3 required Java 6. Some features require optional dependencies; the documentation for these features specifies the dependencies. -$h2 News +== News -Log4j $Log4jReleaseVersion is now available for production. The API for Log4j 2 is not compatible with Log4j 1.x, however an adapter is +Log4j {Log4jReleaseVersion} is now available for production. The API for Log4j 2 is not compatible with Log4j 1.x, however an adapter is available to allow applications to continue to use the Log4j 1.x API. Adapters are also available for Apache Commons Logging, SLF4J, and java.util.logging. -Log4j $Log4jReleaseVersion is the latest release of Log4j and contains several bug fixes that were found after the release of Log4j 2.6. -The list of fixes can be found in the latest [changes report](changes-report.html#a$Log4jReleaseVersion). +Log4j {Log4jReleaseVersion} is the latest release of Log4j and contains several bug fixes that were found after the release of Log4j 2.6. +The list of fixes can be found in the latest link:changes-report.html#a{Log4jReleaseVersion}[changes report]. Note that subsequent to the release of Log4j 2.6 a minor source incompatibility with prior release was found due to the addition of new methods to the Logger interface. If you have code that does: - logger.error(null, "This is the log message", throwable); +[source,java] +---- +logger.error(null, "This is the log message", throwable); +---- or similar with any log level you will get a compiler error saying the reference is ambiguous. To correct this either do: - logger.error("This is the log message", throwable); +[source,java] +---- +logger.error("This is the log message", throwable); +---- or - logger.error((Marker) null, "This is the log message", throwable); +[source,java] +---- +logger.error((Marker) null, "This is the log message", throwable); +---- -Log4j $Log4jReleaseVersion maintains binary compatibility with previous releases. +Log4j {Log4jReleaseVersion} maintains binary compatibility with previous releases. From 05511e486137b135c80b3e4d32e9bc60023a3a8b Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 17:53:17 -0500 Subject: [PATCH 0121/2347] LOG4J2-1802: Convert download page to asciidoc Also fixes v2.3 download link --- pom.xml | 2 + src/site/asciidoc/download.adoc | 118 +++++++++++++++++++++++++++++++ src/site/markdown/download.md.vm | 101 -------------------------- 3 files changed, 120 insertions(+), 101 deletions(-) create mode 100644 src/site/asciidoc/download.adoc delete mode 100644 src/site/markdown/download.md.vm diff --git a/pom.xml b/pom.xml index dfa6b5d92e2..cf4adbd0924 100644 --- a/pom.xml +++ b/pom.xml @@ -1143,6 +1143,8 @@ ${Log4jReleaseVersion} + ${Log4jReleaseManager} + ${Log4jReleaseKey} diff --git a/src/site/asciidoc/download.adoc b/src/site/asciidoc/download.adoc new file mode 100644 index 00000000000..38df7e395f8 --- /dev/null +++ b/src/site/asciidoc/download.adoc @@ -0,0 +1,118 @@ +//// + 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 + + https://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. +//// += Download Apache Log4j 2 + +Apache Log4j 2 is distributed under the +https://www.apache.org/licenses/LICENSE-2.0.html[Apache License, version 2.0]. + +The link in the Mirrors column should display a list of available +mirrors with a default selection based on your inferred location. If you +do not see that page, try a different browser. The checksum and +signature are links to the originals on the main distribution server. + +|=== +|Distribution |Mirrors |Checksum |Signature + +|Apache Log4j 2 binary (tar.gz) +|https://www.apache.org/dyn/closer.lua/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-bin.tar.gz[apache-log4j-{Log4jReleaseVersion}-bin.tar.gz] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-bin.tar.gz.md5[apache-log4j-{Log4jReleaseVersion}-bin.tar.gz.md5] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-bin.tar.gz.asc[apache-log4j-{Log4jReleaseVersion}-bin.tar.gz.asc] + +|Apache Log4j 2 binary (zip) +|https://www.apache.org/dyn/closer.lua/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-bin.zip[apache-log4j-{Log4jReleaseVersion}-bin.zip] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-bin.zip.md5[apache-log4j-{Log4jReleaseVersion}-bin.zip.md5] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-bin.zip.asc[apache-log4j-{Log4jReleaseVersion}-bin.zip.asc] + +|Apache Log4j 2 source (tar.gz) +|https://www.apache.org/dyn/closer.lua/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-src.tar.gz[apache-log4j-{Log4jReleaseVersion}-src.tar.gz] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-src.tar.gz.md5[apache-log4j-{Log4jReleaseVersion}-src.tar.gz.md5] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-src.tar.gz.asc[apache-log4j-{Log4jReleaseVersion}-src.tar.gz.asc] + +|Apache Log4j 2 source (zip) +|https://www.apache.org/dyn/closer.lua/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-src.zip[apache-log4j-{Log4jReleaseVersion}-src.zip] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-src.zip.md5[apache-log4j-{Log4jReleaseVersion}-src.zip.md5] +|https://www.apache.org/dist/logging/log4j/{Log4jReleaseVersion}/apache-log4j-{Log4jReleaseVersion}-src.zip.asc[apache-log4j-{Log4jReleaseVersion}-src.zip.asc] +|=== + +It is essential that you verify the integrity of the downloaded files +using the PGP or MD5 signatures. Please read +https://httpd.apache.org/dev/verification.html[Verifying Apache HTTP +Server Releases] for more information on why you should verify our +releases. + +The PGP signatures can be verified using PGP or GPG. First download the +https://www.apache.org/dist/logging/KEYS[KEYS] as well as the asc +signature file for the relevant distribution. Make sure you get these +files from the https://www.apache.org/dist/logging/[main distribution +directory], rather than from a mirror. Then verify the signatures using + +[source,sh,subs=attributes] +---- +gpg --import KEYS +gpg --verify apache-log4j-{Log4jReleaseVersion}-bin.tar.gz.asc apache-log4j-{Log4jReleaseVersion}-bin.tar.gz +gpg --verify apache-log4j-{Log4jReleaseVersion}-bin.zip.asc apache-log4j-{Log4jReleaseVersion}-bin.zip +gpg --verify apache-log4j-{Log4jReleaseVersion}-src.tar.gz.asc apache-log4j-{Log4jReleaseVersion}-src.tar.gz +gpg --verify apache-log4j-{Log4jReleaseVersion}-src.zip.asc apache-log4j-{Log4jReleaseVersion}-src.zip +---- + +Apache Log4j {Log4jReleaseVersion} is signed by {Log4jReleaseManager} ({Log4jReleaseKey}). + +Alternatively, you can verify the MD5 signature on the files. A unix +program called md5 or md5sum is included in many unix distributions. + +== Previous Releases + +Log4j 2.3 was the last 2.x release to support Java 6. Those artifacts +can be found at: + +|=== +|Distribution |Mirrors |Checksum |Signature + +|Apache Log4j 2 binary (tar.gz) +|https://www.apache.org/dyn/closer.lua/logging/log4j/2.3/apache-log4j-2.3-bin.tar.gz[apache-log4j-2.3-bin.tar.gz] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-bin.tar.gz.md5[apache-log4j-2.3-bin.tar.gz.md5] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-bin.tar.gz.asc[apache-log4j-2.3-bin.tar.gz.asc] + +|Apache Log4j 2 binary (zip) +|https://www.apache.org/dyn/closer.lua/logging/log4j/2.3/apache-log4j-2.3-bin.zip[apache-log4j-2.3-bin.zip] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-bin.zip.md5[apache-log4j-2.3-bin.zip.md5] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-bin.zip.asc[apache-log4j-2.3-bin.zip.asc] + +|Apache Log4j 2 source (tar.gz) +|https://www.apache.org/dyn/closer.lua/logging/log4j/2.3/apache-log4j-2.3-src.tar.gz[apache-log4j-2.3-src.tar.gz] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-src.tar.gz.md5[apache-log4j-2.3-src.tar.gz.md5] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-src.tar.gz.asc[apache-log4j-2.3-src.tar.gz.asc] + +|Apache Log4j 2 source (zip) +|https://www.apache.org/dyn/closer.lua/logging/log4j/2.3/apache-log4j-2.3-src.zip[apache-log4j-2.3-src.zip] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-src.zip.md5[apache-log4j-2.3-src.zip.md5] +|https://www.apache.org/dist/logging/log4j/2.3/apache-log4j-2.3-src.zip.asc[apache-log4j-2.3-src.zip.asc] +|======================================================================= + +All previous releases of Apache log4j can be found in the +https://archive.apache.org/dist/logging/log4j/[archive repository]. + +== Using Log4j on your classpath + +To use Log4j 2 in your application make sure that both the API and Core +jars are in the application’s classpath. Add the dependencies listed +below to your classpath. + +* log4j-api-{Log4jReleaseVersion}.jar +* log4j-core-{Log4jReleaseVersion}.jar + +You can do this from the command line or a manifest file. diff --git a/src/site/markdown/download.md.vm b/src/site/markdown/download.md.vm deleted file mode 100644 index 3ed0fe67526..00000000000 --- a/src/site/markdown/download.md.vm +++ /dev/null @@ -1,101 +0,0 @@ - - -#set($h1='#') -#set($h2='##') - -$h1 Download Apache Log4j 2 - -Apache Log4j 2 is distributed under the [Apache License, version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html). - -The link in the Mirrors column should display a list of available mirrors with a default selection based on your -inferred location. If you do not see that page, try a different browser. The checksum and signature are links to -the originals on the main distribution server. - -| Distribution | Mirrors | Checksum | Signature | -| ------------------------------ | -------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------- | -| Apache Log4j 2 binary (tar.gz) | [apache-log4j-${Log4jReleaseVersion}-bin.tar.gz][bintar] | [apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.md5][bintarmd5] | [apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc][bintarasc] | -| Apache Log4j 2 binary (zip) | [apache-log4j-${Log4jReleaseVersion}-bin.zip][binzip] | [apache-log4j-${Log4jReleaseVersion}-bin.zip.md5][binzipmd5] | [apache-log4j-${Log4jReleaseVersion}-bin.zip.asc][binzipasc] | -| Apache Log4j 2 source (tar.gz) | [apache-log4j-${Log4jReleaseVersion}-src.tar.gz][srctar] | [apache-log4j-${Log4jReleaseVersion}-src.tar.gz.md5][srctarmd5] | [apache-log4j-${Log4jReleaseVersion}-src.tar.gz.asc][srctarasc] | -| Apache Log4j 2 source (zip) | [apache-log4j-${Log4jReleaseVersion}-src.zip][srczip] | [apache-log4j-${Log4jReleaseVersion}-src.zip.md5][srczipmd5] | [apache-log4j-${Log4jReleaseVersion}-src.zip.asc][srczipasc] | - -[bintar]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz -[bintarmd5]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.md5 -[bintarasc]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc -[binzip]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip -[binzipmd5]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip.md5 -[binzipasc]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip.asc -[srctar]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz -[srctarmd5]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.md5 -[srctarasc]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.asc -[srczip]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip -[srczipmd5]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip.md5 -[srczipasc]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip.asc - -It is essential that you verify the integrity of the downloaded files using the PGP or MD5 signatures. -Please read [Verifying Apache HTTP Server Releases](https://httpd.apache.org/dev/verification.html) for more -information on why you should verify our releases. - -The PGP signatures can be verified using PGP or GPG. First download the -[KEYS](https://www.apache.org/dist/logging/KEYS) as well as the asc signature file for the relevant distribution. -Make sure you get these files from the [main distribution directory](https://www.apache.org/dist/logging/), rather -than from a mirror. Then verify the signatures using - - gpg --import KEYS - gpg --verify apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc - -Apache Log4j ${Log4jReleaseVersion} is signed by ${Log4jReleaseManager} (${Log4jReleaseKey}) - -Alternatively, you can verify the MD5 signature on the files. A unix program called md5 or md5sum is included -in many unix distributions. - -$h2 Previous Releases - -Log4j 2.3 was the last 2.x release to support Java 6. Those artifacts can be found at: - -| Distribution | Mirrors | Checksum | Signature | -| ------------------------------ | ------------------------------------------ | ------------------------------------------------- | ------------------------------------------------- | -| Apache Log4j 2 binary (tar.gz) | [apache-log4j-2.3-bin.tar.gz][bintar-jdk6] | [apache-log4j-2.3-bin.tar.gz.md5][bintarmd5-jdk6] | [apache-log4j-2.3-bin.tar.gz.asc][bintarasc-jdk6] | -| Apache Log4j 2 binary (zip) | [apache-log4j-2.3-bin.zip][binzip-jdk6] | [apache-log4j-2.3-bin.zip.md5][binzipmd5-jdk6] | [apache-log4j-2.3-bin.zip.asc][binzipasc-jdk6] | -| Apache Log4j 2 source (tar.gz) | [apache-log4j-2.3-src.tar.gz][srctar-jdk6] | [apache-log4j-2.3-src.tar.gz.md5][srctarmd5-jdk6] | [apache-log4j-2.3-src.tar.gz.asc][srctarasc-jdk6] | -| Apache Log4j 2 source (zip) | [apache-log4j-2.3-src.zip][srczip-jdk6] | [apache-log4j-2.3-src.zip.md5][srczipmd5-jdk6] | [apache-log4j-2.3-src.zip.asc][srczipasc-jdk6] | - -[bintar-jdk6]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz -[bintarmd5-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.md5 -[bintarasc-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc -[binzip-jdk6]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip -[binzipmd5-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip.md5 -[binzipasc-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip.asc -[srctar-jdk6]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz -[srctarmd5-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.md5 -[srctarasc-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.asc -[srczip-jdk6]: https://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip -[srczipmd5-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip.md5 -[srczipasc-jdk6]: https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip.asc - -All previous releases of Apache log4j can be found in the -[archive repository](https://archive.apache.org/dist/logging/log4j/). - -$h2 Using Log4j on your classpath - -To use Log4j 2 in your application make sure that both the API and Core jars are in the application's classpath. Add -the dependencies listed below to your classpath. - - log4j-api-${Log4jReleaseVersion}.jar - log4j-core-${Log4jReleaseVersion}.jar - -You can do this from the command line or a manifest file. From 158760735eaa79154717ca2714870ada8f340a0b Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 18:06:46 -0500 Subject: [PATCH 0122/2347] Update jenkins toolchain java 1.9 version --- jenkins-toolchains.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jenkins-toolchains.xml b/jenkins-toolchains.xml index 2ee96063cfc..5b02197f27b 100644 --- a/jenkins-toolchains.xml +++ b/jenkins-toolchains.xml @@ -44,7 +44,7 @@ sun - /home/jenkins/tools/java/jdk-9-b181 + /home/jenkins/tools/java/latest1.9 From 76446062a9b963f987f44b1faf998c160f553a99 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 18:07:34 -0500 Subject: [PATCH 0123/2347] Add java 10 config to jenkins toolchain --- jenkins-toolchains.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jenkins-toolchains.xml b/jenkins-toolchains.xml index 5b02197f27b..5821ce6acaf 100644 --- a/jenkins-toolchains.xml +++ b/jenkins-toolchains.xml @@ -47,6 +47,16 @@ /home/jenkins/tools/java/latest1.9 + + jdk + + 10 + sun + + + /home/jenkins/tools/java/latest10 + + From 9ef1cc933c4889aa1a363ff0bddddc3b9856f79e Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 18:10:20 -0500 Subject: [PATCH 0124/2347] Add jenkins pipeline --- Jenkinsfile | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000000..48942c798e2 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,49 @@ +#!groovy +/* + * 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 + * + * https://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. + */ + +pipeline { + agent { + label 'ubuntu' + } + tools { + jdk 'JDK 1.8 (latest)' + maven 'Maven 3 (latest)' + } + stages { + stage('Build') { + steps { + ansiColor('xterm') { + sh 'mvn -V -t jenkins-toolchains.xml -Djenkins clean install' + } + } + } + stage('Deploy') { + when { branch 'master' } + steps { + ansiColor('xterm') { + sh 'mvn deploy' + } + } +// post { +// failure { +// emailext body: "See <${env.BUILD_URL}>", replyTo: 'dev@logging.apache.org', subject: "[Log4j] Jenkins build failure (#${env.BUILD_NUMBER})", to: 'notifications@logging.apache.org' +// } +// } + } + } +} From 15cd6ac1c7f1d6838994490c15d5e1bcc006d987 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 19:50:03 -0500 Subject: [PATCH 0125/2347] LOG4J2-1802: Convert FAQ to asciidoc --- src/site/asciidoc/faq.adoc | 497 ++++++++++++++++++++++++++++++++++++ src/site/markdown/faq.md.vm | 480 ---------------------------------- 2 files changed, 497 insertions(+), 480 deletions(-) create mode 100644 src/site/asciidoc/faq.adoc delete mode 100644 src/site/markdown/faq.md.vm diff --git a/src/site/asciidoc/faq.adoc b/src/site/asciidoc/faq.adoc new file mode 100644 index 00000000000..b5cfd784bc6 --- /dev/null +++ b/src/site/asciidoc/faq.adoc @@ -0,0 +1,497 @@ +//// + 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 + + https://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. +//// += Frequently Asked Questions +:toc: + +''' + +[#missing_core] +== I'm seeing this error "Unable to locate a logging implementation, using SimpleLogger". What is wrong? + +You have the log4j-api-2.x jar file in your classpath but you still need +to add the log4j-core-2.x jar to the classpath. (Also, it looks like you +are using an old version of Log4j 2. You may want to upgrade.) + +[#which_jars] +== Which JAR files do I need? + +You need at least the log4j-api-2.x and the log4j-core-2.x jar files. + +The other jars are necessary if your application calls the API of +another logging framework and you want to route logging calls to the +Log4j 2 implementation. + +image:images/whichjar-2.x.png[Diagram showing which JARs correspond to +which systems] + +You can use the log4j-to-slf4j adapter jar when your application calls +the Log4j 2 API and you want to route logging calls to a SLF4J +implementation. + +image:images/whichjar-slf4j-2.x.png[Diagram showing the dependency flow +to use Log4j 2 API with SLF4J] + +Some of the Log4j components have features with optional dependencies. +The component page will have more detail. For example, the +link:log4j-core/index.html[log4j-core component page] has an outline of +which log4j-core features have external dependencies. + +[#exclusions] +== How do I exclude conflicting dependencies? + +There are several scenarios where you may end up with conflicting +dependencies, especially transitively included ones. The following table +shows for each Log4j dependency on the left (implicit groupId of +`org.apache.logging.log4j`), the following dependencies on the right can +be safely excluded (given in the format `groupId:artifactId`). + +[cols="4*"] +|=== +|Log4j Dependency +3+|Dependencies to Exclude + +|log4j-1.2-api +|log4j:log4j +2+|org.slf4j:log4j-over-slf4j + +|log4j-core +|log4j:log4j +|ch.qos.logback:logback-core +|org.apache.logging.log4j:log4j-to-slf4j + +|log4j-jcl +3+|org.slf4j:jcl-over-slf4j + +|log4j-jul +3+|org.slf4j:jul-to-slf4j + +|log4j-slf4j-impl +|org.apache.logging.log4j:log4j-to-slf4j +2+|ch.qos.logback:logback-core +|=== + +Using Apache Maven, dependencies can be globally excluded in your +project like so: + +[source,xml] +---- + + + log4j + log4j + 1.2.17 + provided + + +---- + +Dependencies can be explicitly excluded for specific dependencies as +well. For example, to use a project with Log4j 2 instead of Log4j 1.x: + +[source,xml,subs="attributes,specialchars"] +---- + + + com.example + example-project + 1.0 + + + log4j + log4j + + + org.slf4j + slf4j-log4j12 + + + + + org.apache.logging.log4j + log4j-core + {Log4jReleaseVersion} + + + org.apache.logging.log4j + log4j-slf4j-impl + {Log4jReleaseVersion} + + + org.apache.logging.log4j + log4j-1.2-api + {Log4jReleaseVersion} + + +---- + +Dependencies can be globally excluded in Gradle like so: + +[source,groovy] +---- +configurations { + all*.exclude group: 'log4j', module: 'log4j' +} +---- + +The equivalent Gradle config for the above Maven exclusion would look +like: + +[source,groovy,subs=attributes] +---- +dependencies { + compile('com.example:example-project:1.0') { + exclude group: 'log4j', module: 'log4j' + exclude group: 'org.slf4j', module: 'slf4j-log4j12' + } + compile('org.apache.logging.log4j:log4j-core:{Log4jReleaseVersion}') + compile('org.apache.logging.log4j:log4j-slf4j-impl:{Log4jReleaseVersion}') + compile('org.apache.logging.log4j:log4j-1.2-api:{Log4jReleaseVersion}') +} +---- + +[#config_location] +== How do I specify the configuration file location? + +By default, Log4j looks for a configuration file named *log4j2.xml* (not +log4j.xml) in the classpath. + +You can also specify the full path of the configuration file with this +system property: `-Dlog4j.configurationFile=path/to/log4j2.xml` + +That property can also be included in a classpath resource file named +`log4j2.component.properties`. + +Web applications can specify the Log4j configuration file location with +a servlet context parameter. See +http://logging.apache.org/log4j/2.x/manual/webapp.html#ContextParams[this +section] of the Using Log4j 2 in Web Applications manual page. + +[#config_from_code] +== How do I configure log4j2 in code without a configuration file? + +Starting with version 2.4, Log4j 2 provides an +link:manual/customconfig.html[API for programmatic configuration] The +new +link:log4j-core/apidocs/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.html[`ConfigurationBuilder` +API] allows you to create Configurations in code by constructing +component definitions without requiring you to know about the internals +of actual configuration objects like Loggers and Appenders. + +[#reconfig_from_code] +== How do I reconfigure log4j2 in code with a specific configuration file? + +See the below example. Be aware that this LoggerContext class is not +part of the public API so your code may break with any minor release. + +[source,java] +---- +// import org.apache.logging.log4j.core.LoggerContext; + +LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false); +File file = new File("path/to/a/different/log4j2.xml"); + +// this will force a reconfiguration +context.setConfigLocation(file.toURI()); +---- + +[#shutdown] +== How do I shut down log4j2 in code? + +Normally there is no need to do this manually. Each `LoggerContext` +registers a shutdown hook that takes care of releasing resources when +the JVM exits (unless system property `log4j.shutdownHookEnabled` is set +to `false`). Web applications should include the log4j-web module in +their classpath which disables the shutdown hook but instead cleans up +log4j resources when the web application is stopped. + +However, if you need to manually shut down Log4j, you can do so as in +the below example. Note that there is an optional parameter for +specifying which `LoggerContext` to shut down. + +[source,java] +---- +import org.apache.logging.log4j.LogManager; + +// ... + +LogManager.shutdown(); +---- + +[#config_sep_appender_level] +== How do I send log messages with different levels to different +appenders? You don’t need to declare separate loggers to achieve this. +You can set the logging level on the `AppenderRef` element. + +[source,xml] +---- + + + + + + %d %p %c{1.} [%t] %m %ex%n + + + + + + + + + + + + + +---- + +[#troubleshooting] +== How do I debug my configuration? + +First, make sure you have link:#which_jars[the right jar files] on your +classpath. You need at least log4j-api and log4j-core. + +Next, check the name of your configuration file. By default, log4j2 will +look for a configuration file named `log4j2.xml` on the classpath. Note +the ``2'' in the file name! (See the +link:manual/configuration.html#AutomaticConfiguration[configuration +manual page] for more details.) + +*From log4j-2.9 onward* + +From log4j-2.9 onward, log4j2 will print all internal logging to the +console if system property `log4j2.debug` is defined (with any or no +value). + +*Prior to log4j-2.9* + +Prior to log4j-2.9, there are two places where internal logging can be +controlled: + +If the configuration file is found correctly, log4j2 internal status +logging can be controlled by setting `` in +the configuration file. This will display detailed log4j2-internal log +statements on the console about what happens during the configuration +process. This may be useful to trouble-shoot configuration issues. By +default the status logger level is WARN, so you only see notifications +when there is a problem. + +If the configuration file is not found correctly, you can still enable +log4j2 internal status logging by setting system property +`-Dorg.apache.logging.log4j.simplelog.StatusLogger.level=TRACE`. + +[#separate_log_files] +== How do I dynamically write to separate log files? + +Look at the +http://logging.apache.org/log4j/2.x/manual/appenders.html#RoutingAppender[RoutingAppender]. +You can define multiple routes in the configuration, and put values in +the `ThreadContext` map that determine which log file subsequent events +in this thread get logged to. + +You can use the `ThreadContext` map value to determine the log file +name. + +[source,xml] +---- + + + + + + + + %d{ISO8601} [%t] %p %c{3} - %m%n + + + + + + + + + + + + + %d{ISO8601} [%t] %p %c{3} - %m%n + + + + + + + + + + + + + %d{ISO8601} [%t] %p %c{3} - %m%n + + + + + + + + + +---- + +[#reconfig_level_from_code] +== How do I set a logger’s level programmatically? + +You can set a logger’s level with the class +link:log4j-core/apidocs/org/apache/logging/log4j/core/config/Configurator.html[`Configurator`] +from Log4j Core. Be aware that the `Configurator` class is not part of +the public API. + +[source,xml] +---- +// org.apache.logging.log4j.core.config.Configurator; + +Configurator.setLevel("com.example.Foo", Level.DEBUG); + +// You can also set the root logger: +Configurator.setRootLevel(Level.DEBUG); +---- + +[#retention] +== How do I set my log archive retention policy? How do I delete old log archives? + +The `DefaultRolloverStrategy` of the Rolling File appender (and Rolling +Random Access File appender) supports a +link:manual/appenders.html#CustomDeleteOnRollover[Delete] element. + +Starting at a specified base directory, you can delete all files for +which some condition holds true, for example all files that match a +given file name pattern and are older than some number of days. More +complex conditions are possible, and if the built-in conditions are not +sufficient, users can provide custom conditions by creating +link:manual/appenders.html#DeletePathCondition[plugin conditions] or by +writing a link:manual/appenders.html#ScriptCondition[script condition]. + +[#api-tradeoffs] +== What are the trade-offs of using the Log4j 2 API versus the SLF4J API? + +The Log4j 2 API and SLF4J have a lot in common. They both share the +objective of cleanly separating the logging API from the implementation. +We believe that the Log4j 2 API can help make your application more +performant while offering more functionality and more flexibility. + +There may be a concern that using the Log4j 2 API will tightly couple +your application to Log4j 2. This is not the case: applications coded to +the Log4j 2 API always have the option to use any SLF4J-compliant +library as their logging implementation with the log4j-to-slf4j adapter. +See the link:#which_jars_log4j-to-slf4j[which jars] FAQ entry for +details. + +There are several advantages to using the Log4j 2 API: + +* SLF4J forces your application to log Strings. The Log4j 2 API supports +logging any CharSequence if you want to log text, but also supports +logging any Object as is. It is the responsibility of the logging +implementation to handle this object, and we consider it a design +mistake to limit applications to logging Strings. +* The Log4j 2 API offers support for logging +link:manual/messages.html[Message objects]. Messages allow support for +interesting and complex constructs to be passed through the logging +system and be efficiently manipulated. Users are free to create their +own Message types and write custom Layouts, Filters and Lookups to +manipulate them. +* The Log4j 2 API has support for Java 8 +link:manual/api.html#LambdaSupport[lambda expressions]. +* The Log4j 2 API has better support for +link:manual/garbagefree.html[garbage-free logging]: it avoids creating +vararg arrays and avoids creating Strings when logging CharSequence +objects. + +[#gc-free-slf4j] +== Is Log4j 2 still garbage-free when I use the SLF4J API? + +Yes, the log4j-slf4j-impl binding (together with log4j-core) implements +the `org.slf4j.Logger` methods to be GC-free. However, bear in mind that +there are some limitations: + +The SLF4J API only offers up to two parameters for a parameterized +message. More than that uses varargs which creates a temporary object +for the parameter array. The Log4j 2.6 API has methods for up to ten +unrolled parameters. + +Another consideration is that the SLF4J API forces your application to +log Strings. Log4j 2 API lets you log any java.lang.CharSequence, and +even any Objects. Log4j can log any Object that implements +`java.lang.CharSequence` or +`org.apache.logging.log4j.util.StringBuilderFormattable` without +creating garbage. + +The +http://www.slf4j.org/api/org/slf4j/spi/LocationAwareLogger.html#log(org.slf4j.Marker,%20java.lang.String,%20int,%20java.lang.String,%20java.lang.Object%5B%5D,%20java.lang.Throwable)[`org.slf4j.spi.LocationAwareLogger::log`] +method is not yet implemented in a garbage-free manner in the +log4j-slf4j-impl binding. It creates a new message object for each call. + +[#gc-free-domain-object] +== How do I log my domain object without creating garbage? + +One option is to let the domain object implement java.lang.CharSequence. +However, for many domain objects it may not be trivial to implement this +without allocating temporary objects. + +An alternative is to implement the +`org.apache.logging.log4j.util.StringBuilderFormattable` interface. If +an object is logged that implements this interface, its `formatTo` +method is called instead of `toString()`. + +[source,java] +---- +package org.apache.logging.log4j.util; +public interface StringBuilderFormattable { + /** + * Writes a text representation of this object into the specified {@code StringBuilder}, + * ideally without allocating temporary objects. + * + * @param buffer the StringBuilder to write into + */ + void formatTo(StringBuilder buffer); +} +---- + +[#logger-wrapper] +== How do I create a custom logger wrapper that shows the correct class, method and line number? + +Log4j remembers the fully qualified class name (FQCN) of the logger and +uses this to walk the stack trace for every log event when configured to +print location. (Be aware that logging with location is slow and may +impact the performance of your application.) + +The problem with custom logger wrappers is that they have a different +FQCN than the actual logger, so Log4j can’t find the place where your +custom logger was called. + +The solution is to provide the correct FQCN. The easiest way to do this +is to let Log4j generate the logger wrapper for you. Log4j comes with a +Logger wrapper generator tool. This tool was originally meant to support +custom log levels and is documented +https://logging.apache.org/log4j/2.x/manual/customloglevels.html#CustomLoggers[here]. + +The generated logger code will take care of the FQCN. diff --git a/src/site/markdown/faq.md.vm b/src/site/markdown/faq.md.vm deleted file mode 100644 index 132e6fe7d0d..00000000000 --- a/src/site/markdown/faq.md.vm +++ /dev/null @@ -1,480 +0,0 @@ - - -#set($dollar = '$') -#set($h1='#') -#set($h4='####') - -$h1 Frequently Asked Questions - -* [I'm seeing this error "Unable to locate a logging implementation, using SimpleLogger". What is wrong?](#missing_core) -* [Which JAR files do I need?](#which_jars) -* [How do I exclude conflicting dependencies?](#exclusions) -* [How do I specify the configuration file location?](#config_location) -* [How do I configure log4j2 in code without a configuration file?](#config_from_code) -* [How do I reconfigure log4j2 in code with a specific configuration file?](#reconfig_from_code) -* [How do I shut down log4j2 in code?](#shutdown) -* [How do I send log messages with different levels to different appenders?](#config_sep_appender_level) -* [How do I debug my configuration?](#troubleshooting) -* [How do I dynamically write to separate log files?](#separate_log_files) -* [How do I set a logger's level programmatically?](#reconfig_level_from_code) -* [How do I set my log archive retention policy? How do I delete old log archives?](#retention) -* [What are the trade-offs of using the Log4j 2 API versus the SLF4J API?](#api-tradeoffs) -* [Is Log4j 2 still garbage-free when I use the SLF4J API?](#gc-free-slf4j) -* [How do I log my domain object without creating garbage?](#gc-free-domain-object) -* [How do I create a custom logger wrapper that shows the correct class, method and line number?](#logger-wrapper) - - -$h4 I'm seeing this error "Unable to locate a logging implementation, using SimpleLogger". What is wrong? - -You have the log4j-api-2.x jar file in your classpath but you still need to add the log4j-core-2.x jar to the -classpath. (Also, it looks like you are using an old version of Log4j 2. You may want to upgrade.) - - -$h4 Which JAR files do I need? - -You need at least the log4j-api-2.x and the log4j-core-2.x jar files. - -The other jars are necessary if your application calls the API -of another logging framework and you want to route logging calls to the Log4j 2 implementation. - -![Diagram showing which JARs correspond to which systems](images/whichjar-2.x.png) - - -You can use the log4j-to-slf4j adapter jar when your application calls the Log4j 2 API and you -want to route logging calls to a SLF4J implementation. - -![Diagram showing the dependency flow to use Log4j 2 API with SLF4J](images/whichjar-slf4j-2.x.png) - -Some of the Log4j components have features with optional dependencies. -The component page will have more detail. For example, the -[log4j-core component page](log4j-core/index.html) -has an outline of which log4j-core features have external dependencies. - - -$h4 How do I exclude conflicting dependencies? - -There are several scenarios where you may end up with conflicting dependencies, especially transitively -included ones. The following table shows for each Log4j dependency on the left (implicit groupId of -`org.apache.logging.log4j`), the following dependencies on the right can be safely excluded -(given in the format `groupId:artifactId`). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Log4j DependencyDependencies to Exclude
    [log4j-1.2-api](log4j-1.2-api)log4j:log4jorg.slf4j:log4j-over-slf4j -
    [log4j-core](log4j-core)log4j:log4jch.qos.logback:logback-coreorg.apache.logging.log4j:log4j-to-slf4j
    [log4j-jcl](log4j-jcl)org.slf4j:jcl-over-slf4j - -
    [log4j-jul](log4j-jul)org.slf4j:jul-to-slf4j - -
    [log4j-slf4j-impl](log4j-slf4j-impl)org.apache.logging.log4j:log4j-to-slf4jch.qos.logback:logback-core -
    - -Using Apache Maven, dependencies can be globally excluded in your project like so: - -``` - - - log4j - log4j - 1.2.17 - provided - - -``` - -Dependencies can be explicitly excluded for specific dependencies as well. For example, to use a project -with Log4j 2 instead of Log4j 1.x: - -``` - - - com.example - example-project - 1.0 - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - - - - - org.apache.logging.log4j - log4j-core - ${Log4jReleaseVersion} - - - org.apache.logging.log4j - log4j-slf4j-impl - ${Log4jReleaseVersion} - - - org.apache.logging.log4j - log4j-1.2-api - ${Log4jReleaseVersion} - - -``` - -Dependencies can be globally excluded in Gradle like so: - -``` -configurations { - all*.exclude group: 'log4j', module: 'log4j' -} -``` - -The equivalent Gradle config for the above Maven exclusion would look like: - -``` -dependencies { - compile('com.example:example-project:1.0') { - exclude group: 'log4j', module: 'log4j' - exclude group: 'org.slf4j', module: 'slf4j-log4j12' - } - compile('org.apache.logging.log4j:log4j-core:${Log4jReleaseVersion}') - compile('org.apache.logging.log4j:log4j-slf4j-impl:${Log4jReleaseVersion}') - compile('org.apache.logging.log4j:log4j-1.2-api:${Log4jReleaseVersion}') -} -``` - -
    -$h4 How do I specify the configuration file location? - -By default, Log4j looks for a configuration file named **log4j2.xml** (not log4j.xml) in the classpath. - -You can also specify the full path of the configuration file with this system property: -`-Dlog4j.configurationFile=path/to/log4j2.xml` - -That property can also be included in a classpath resource file named `log4j2.component.properties`. - -Web applications can specify the Log4j configuration file location with a servlet context parameter. -See [this section](http://logging.apache.org/log4j/2.x/manual/webapp.html#ContextParams) -of the Using Log4j 2 in Web Applications manual page. - - -$h4 How do I configure log4j2 in code without a configuration file? - -Starting with version 2.4, Log4j 2 provides an [API for programmatic configuration](manual/customconfig.html) -The new -[`ConfigurationBuilder` API](log4j-core/apidocs/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.html) -allows you to create Configurations in code by constructing component definitions -without requiring you to know about the internals of actual configuration objects like Loggers and Appenders. - - -$h4 How do I reconfigure log4j2 in code with a specific configuration file? - -See the below example. -Be aware that this LoggerContext class is not part of the public API so your code may break with any minor release. - -``` -// import org.apache.logging.log4j.core.LoggerContext; - -LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false); -File file = new File("path/to/a/different/log4j2.xml"); - -// this will force a reconfiguration -context.setConfigLocation(file.toURI()); -``` - - -$h4 How do I shut down log4j2 in code? - -Normally there is no need to do this manually. -Each `LoggerContext` registers a shutdown hook that takes care of releasing resources -when the JVM exits (unless system property `log4j.shutdownHookEnabled` is set to `false`). -Web applications should include the log4j-web -module in their classpath which disables the shutdown hook but instead -cleans up log4j resources when the web application is stopped. - -However, if you need to manually shut down Log4j, you can do so as in the below example. -Note that there is an optional parameter for specifying which `LoggerContext` to -shut down. - -``` -import org.apache.logging.log4j.LogManager; - -// ... - -LogManager.shutdown(); -``` - - -$h4 How do I send log messages with different levels to different appenders? -You don't need to declare separate loggers to achieve this. -You can set the logging level on the `AppenderRef` element. - -``` - - - - - - %d %p %c{1.} [%t] %m %ex%n - - - - - - - - - - - - - -``` - - -$h4 How do I debug my configuration? - -First, make sure you have [the right jar files](#which_jars) on your classpath. -You need at least log4j-api and log4j-core. - -Next, check the name of your configuration file. By default, log4j2 will look -for a configuration file named `log4j2.xml` on the classpath. Note the "2" in the file name! -(See the [configuration manual page](manual/configuration.html#AutomaticConfiguration) for more details.) - -**From log4j-2.9 onward** - -From log4j-2.9 onward, log4j2 will print all internal logging to the console if system property `log4j2.debug` -is defined (with any or no value). - -**Prior to log4j-2.9** - -Prior to log4j-2.9, there are two places where internal logging can be controlled: - -If the configuration file is found correctly, log4j2 internal status logging can be controlled by -setting `` in the configuration file. This will display detailed log4j2-internal -log statements on the console about what happens during the configuration process. -This may be useful to trouble-shoot configuration issues. -By default the status logger level is WARN, so you only see notifications when there is a problem. - -If the configuration file is not found correctly, you can still enable -log4j2 internal status logging by setting system property -`-Dorg.apache.logging.log4j.simplelog.StatusLogger.level=TRACE`. - - -$h4 How do I dynamically write to separate log files? - -Look at the [RoutingAppender](http://logging.apache.org/log4j/2.x/manual/appenders.html#RoutingAppender). -You can define multiple routes in the configuration, and put values in the `ThreadContext` -map that determine which log file subsequent events in this thread get logged to. - -You can use the `ThreadContext` map value to determine the log file name. - -``` - - - - - - - - %d{ISO8601} [%t] %p %c{3} - %m%n - - - - - - - - - - - - - %d{ISO8601} [%t] %p %c{3} - %m%n - - - - - - - - - - - - - %d{ISO8601} [%t] %p %c{3} - %m%n - - - - - - - - - -``` - - -$h4 How do I set a logger's level programmatically? - -You can set a logger's level with the class -[`Configurator`](log4j-core/apidocs/org/apache/logging/log4j/core/config/Configurator.html) -from Log4j Core. Be aware that the `Configurator` class is not part of the public API. - -``` -// org.apache.logging.log4j.core.config.Configurator; - -Configurator.setLevel("com.example.Foo", Level.DEBUG); - -// You can also set the root logger: -Configurator.setRootLevel(Level.DEBUG); -``` - - -$h4 How do I set my log archive retention policy? How do I delete old log archives? - -The `DefaultRolloverStrategy` of the Rolling File appender (and Rolling Random Access File -appender) supports a [Delete](manual/appenders.html#CustomDeleteOnRollover) element. - -Starting at a specified base directory, you can delete all files for which some condition -holds true, for example all files that match a given file name pattern and are older -than some number of days. More complex conditions are possible, and if the built-in -conditions are not sufficient, users can provide custom conditions by creating -[plugin conditions](manual/appenders.html#DeletePathCondition) or by writing a -[script condition](manual/appenders.html#ScriptCondition). - - -$h4 What are the trade-offs of using the Log4j 2 API versus the SLF4J API? - -The Log4j 2 API and SLF4J have a lot in common. -They both share the objective of cleanly separating the logging API from the implementation. -We believe that the Log4j 2 API can help make your application more performant -while offering more functionality and more flexibility. - -There may be a concern that using the Log4j 2 API will tightly couple your application to Log4j 2. -This is not the case: applications coded to the Log4j 2 API always have the option to use any SLF4J-compliant -library as their logging implementation with the log4j-to-slf4j adapter. -See the [which jars](#which_jars_log4j-to-slf4j) FAQ entry for details. - -There are several advantages to using the Log4j 2 API: - -* SLF4J forces your application to log Strings. -The Log4j 2 API supports logging any CharSequence if you want to log text, but also -supports logging any Object as is. -It is the responsibility of the logging implementation to handle this object, -and we consider it a design mistake to limit applications to logging Strings. -* The Log4j 2 API offers support for logging [Message objects](manual/messages.html). -Messages allow support for interesting and complex constructs to be passed -through the logging system and be efficiently manipulated. -Users are free to create their own Message types and write custom Layouts, -Filters and Lookups to manipulate them. -* The Log4j 2 API has support for Java 8 [lambda expressions](manual/api.html#LambdaSupport). -* The Log4j 2 API has better support for [garbage-free logging](manual/garbagefree.html): -it avoids creating vararg arrays and avoids creating Strings when logging CharSequence objects. - - -$h4 Is Log4j 2 still garbage-free when I use the SLF4J API? - -Yes, the log4j-slf4j-impl binding (together with log4j-core) implements the -`org.slf4j.Logger` methods to be GC-free. -However, bear in mind that there are some limitations: - -The SLF4J API only offers up to two parameters for a parameterized message. -More than that uses varargs which creates a temporary object for the parameter array. -The Log4j 2.6 API has methods for up to ten unrolled parameters. - -Another consideration is that the SLF4J API forces your application to log Strings. -Log4j 2 API lets you log any java.lang.CharSequence, and even any Objects. -Log4j can log any Object that implements `java.lang.CharSequence` -or `org.apache.logging.log4j.util.StringBuilderFormattable` without creating garbage. - -The [`org.slf4j.spi.LocationAwareLogger::log`](http://www.slf4j.org/api/org/slf4j/spi/LocationAwareLogger.html#log(org.slf4j.Marker, java.lang.String, int, java.lang.String, java.lang.Object[], java.lang.Throwable)) -method is not yet implemented -in a garbage-free manner in the log4j-slf4j-impl binding. It creates a new message object for each call. - - -$h4 How do I log my domain object without creating garbage? - -One option is to let the domain object implement java.lang.CharSequence. -However, for many domain objects it may not be trivial to implement this without allocating temporary -objects. - -An alternative is to implement the `org.apache.logging.log4j.util.StringBuilderFormattable` interface. -If an object is logged that implements this interface, its `formatTo` method is called instead of -`toString()`. - -``` -package org.apache.logging.log4j.util; -public interface StringBuilderFormattable { - /** - * Writes a text representation of this object into the specified {@code StringBuilder}, - * ideally without allocating temporary objects. - * - * @param buffer the StringBuilder to write into - */ - void formatTo(StringBuilder buffer); -} -``` - - -$h4 How do I create a custom logger wrapper that shows the correct class, method and line number? - -Log4j remembers the fully qualified class name (FQCN) of the logger and uses this to walk the stack trace -for every log event when configured to print location. -(Be aware that logging with location is slow and may impact the performance of your application.) - -The problem with custom logger wrappers is that they have a different FQCN than the actual logger, -so Log4j can't find the place where your custom logger was called. - -The solution is to provide the correct FQCN. The easiest way to do this is to let Log4j generate -the logger wrapper for you. Log4j comes with a Logger wrapper generator tool. -This tool was originally meant to support custom log levels and is documented -[here](https://logging.apache.org/log4j/2.x/manual/customloglevels.html#CustomLoggers). - -The generated logger code will take care of the FQCN. From 5823e4f3fae7a83f0f461c2eb20311d644a3bff0 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 20:03:54 -0500 Subject: [PATCH 0126/2347] Add -e to mvn jenkins build --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 48942c798e2..0bddd6214ff 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -28,7 +28,7 @@ pipeline { stage('Build') { steps { ansiColor('xterm') { - sh 'mvn -V -t jenkins-toolchains.xml -Djenkins clean install' + sh 'mvn -V -e -t jenkins-toolchains.xml -Djenkins clean install' } } } From 9f23e21555ad1d5301f7cf627719fd9fe76529f5 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 20:13:47 -0500 Subject: [PATCH 0127/2347] Add pre-install phase to install dependencies cleanly --- Jenkinsfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0bddd6214ff..cd834a8cd7e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -28,7 +28,8 @@ pipeline { stage('Build') { steps { ansiColor('xterm') { - sh 'mvn -V -e -t jenkins-toolchains.xml -Djenkins clean install' + sh 'mvn -t jenkins-toolchains.xml -Djenkins -DskipTests=true -Dmaven.javadoc.skip=true -V install' + sh 'mvn -t jenkins-toolchains.xml -Djenkins -V install' } } } @@ -36,7 +37,7 @@ pipeline { when { branch 'master' } steps { ansiColor('xterm') { - sh 'mvn deploy' + sh 'mvn -t jenkins-toolchains.xml -Djenkins -V deploy' } } // post { From 22280cbeb615d8fcc73c222a231da6a0dbd941a1 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 20:29:47 -0500 Subject: [PATCH 0128/2347] Blacklist H20 node H20 is supposedly for website publishing, yet it has the ubuntu label right now. Let's see if this fixes the build errors on this node in particular. --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index cd834a8cd7e..04562e3e8a5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -18,7 +18,7 @@ pipeline { agent { - label 'ubuntu' + label 'ubuntu&&!H20' } tools { jdk 'JDK 1.8 (latest)' From 2b3656fe9c18e51488e784b3c23c44f1320cfe1f Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 20:49:20 -0500 Subject: [PATCH 0129/2347] Add Windows Jenkins pipeline --- Jenkinsfile | 17 +++--- ...hains.xml => toolchains-jenkins-ubuntu.xml | 0 toolchains-jenkins-win.xml | 52 +++++++++++++++++++ 3 files changed, 63 insertions(+), 6 deletions(-) rename jenkins-toolchains.xml => toolchains-jenkins-ubuntu.xml (100%) create mode 100644 toolchains-jenkins-win.xml diff --git a/Jenkinsfile b/Jenkinsfile index 04562e3e8a5..4cb4a419c76 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,26 +17,31 @@ */ pipeline { - agent { - label 'ubuntu&&!H20' - } tools { jdk 'JDK 1.8 (latest)' maven 'Maven 3 (latest)' } stages { - stage('Build') { + stage('Build (Ubuntu)') { + agent { label 'ubuntu&&!H20' } steps { ansiColor('xterm') { - sh 'mvn -t jenkins-toolchains.xml -Djenkins -DskipTests=true -Dmaven.javadoc.skip=true -V install' - sh 'mvn -t jenkins-toolchains.xml -Djenkins -V install' + sh 'mvn -t toolchains-jenkins-ubuntu.xml -Djenkins -V install' + stash includes: 'target/**', name: 'target' } } } + stage('Build (Windows)') { + agent { label 'Windows' } + steps { + bat 'mvn -t toolchains-jenkins-win.xml -Djenkins -V install' + } + } stage('Deploy') { when { branch 'master' } steps { ansiColor('xterm') { + unstash 'target' sh 'mvn -t jenkins-toolchains.xml -Djenkins -V deploy' } } diff --git a/jenkins-toolchains.xml b/toolchains-jenkins-ubuntu.xml similarity index 100% rename from jenkins-toolchains.xml rename to toolchains-jenkins-ubuntu.xml diff --git a/toolchains-jenkins-win.xml b/toolchains-jenkins-win.xml new file mode 100644 index 00000000000..2017b0bd5fe --- /dev/null +++ b/toolchains-jenkins-win.xml @@ -0,0 +1,52 @@ + + + + + + jdk + + 1.7 + sun + + + F:\hudson\tools\java\jdk1.7.0_79 + + + + jdk + + 1.8 + sun + + + F:\jenkins\tools\java\jdk1.8.0_152 + + + + jdk + + 9 + sun + + + F:\jenkins\tools\java\jdk9.0.1 + + + + + From 259a1c428cd338665506c2a66d0194c6902280be Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:00:19 -0500 Subject: [PATCH 0130/2347] Skip tests in deploy and fix agent syntax error --- Jenkinsfile | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4cb4a419c76..702e7d53221 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,13 +17,16 @@ */ pipeline { - tools { - jdk 'JDK 1.8 (latest)' - maven 'Maven 3 (latest)' - } + agent none stages { stage('Build (Ubuntu)') { agent { label 'ubuntu&&!H20' } + tools { + // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix + jdk 'JDK 1.8 (latest)' + // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix + maven 'Maven 3 (latest)' + } steps { ansiColor('xterm') { sh 'mvn -t toolchains-jenkins-ubuntu.xml -Djenkins -V install' @@ -33,16 +36,28 @@ pipeline { } stage('Build (Windows)') { agent { label 'Windows' } + tools { + // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix + jdk 'JDK 1.8 (latest)' + // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix + maven 'Maven 3 (latest)' + } steps { bat 'mvn -t toolchains-jenkins-win.xml -Djenkins -V install' } } stage('Deploy') { when { branch 'master' } + tools { + // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix + jdk 'JDK 1.8 (latest)' + // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix + maven 'Maven 3 (latest)' + } steps { ansiColor('xterm') { unstash 'target' - sh 'mvn -t jenkins-toolchains.xml -Djenkins -V deploy' + sh 'mvn -t jenkins-toolchains.xml -Djenkins -DskipTests -V deploy' } } // post { From 39e5d4cb6b9c952eb460f348e753f47f9cf85fa5 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:02:36 -0500 Subject: [PATCH 0131/2347] Make Ubuntu and Windows builds parallel --- Jenkinsfile | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 702e7d53221..97552ab6eb4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -19,31 +19,35 @@ pipeline { agent none stages { - stage('Build (Ubuntu)') { - agent { label 'ubuntu&&!H20' } - tools { - // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix - jdk 'JDK 1.8 (latest)' - // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix - maven 'Maven 3 (latest)' - } - steps { - ansiColor('xterm') { - sh 'mvn -t toolchains-jenkins-ubuntu.xml -Djenkins -V install' - stash includes: 'target/**', name: 'target' + stage('Build') { + parallel { + stage('Ubuntu') { + agent { label 'ubuntu&&!H20' } + tools { + // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix + jdk 'JDK 1.8 (latest)' + // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix + maven 'Maven 3 (latest)' + } + steps { + ansiColor('xterm') { + sh 'mvn -t toolchains-jenkins-ubuntu.xml -Djenkins -V install' + stash includes: 'target/**', name: 'target' + } + } + } + stage('Windows') { + agent { label 'Windows' } + tools { + // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix + jdk 'JDK 1.8 (latest)' + // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix + maven 'Maven 3 (latest)' + } + steps { + bat 'mvn -t toolchains-jenkins-win.xml -Djenkins -V install' + } } - } - } - stage('Build (Windows)') { - agent { label 'Windows' } - tools { - // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix - jdk 'JDK 1.8 (latest)' - // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix - maven 'Maven 3 (latest)' - } - steps { - bat 'mvn -t toolchains-jenkins-win.xml -Djenkins -V install' } } stage('Deploy') { From 57d5db3187e4221ece2f04621bd716a8e61fc364 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:06:31 -0500 Subject: [PATCH 0132/2347] Remove jenkins property from windows build --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 97552ab6eb4..da86e52dea7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -45,7 +45,7 @@ pipeline { maven 'Maven 3 (latest)' } steps { - bat 'mvn -t toolchains-jenkins-win.xml -Djenkins -V install' + bat 'mvn -t toolchains-jenkins-win.xml -V install' } } } From 7af15d04c34d75e9d43b0887a7bbf0e7821cabf8 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:15:07 -0500 Subject: [PATCH 0133/2347] Build on Java 9 in Jenkins Windows by default --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index da86e52dea7..862bbfd28ab 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -40,7 +40,7 @@ pipeline { agent { label 'Windows' } tools { // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix - jdk 'JDK 1.8 (latest)' + jdk 'JDK 9 (latest)' // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix maven 'Maven 3 (latest)' } From 34d7977d42e1ed716dd3d9fc50f1cbc2a7c4ced4 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:18:27 -0500 Subject: [PATCH 0134/2347] Fix jdk name --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 862bbfd28ab..cbd481f7dc6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -40,7 +40,7 @@ pipeline { agent { label 'Windows' } tools { // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix - jdk 'JDK 9 (latest)' + jdk 'JDK 1.9 (latest)' // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix maven 'Maven 3 (latest)' } From 6b556e8a604852aac620c468731e7ffdef2b4bfa Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:24:04 -0500 Subject: [PATCH 0135/2347] Fix java home paths for jenkins windows --- toolchains-jenkins-win.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/toolchains-jenkins-win.xml b/toolchains-jenkins-win.xml index 2017b0bd5fe..5fa1f44d5be 100644 --- a/toolchains-jenkins-win.xml +++ b/toolchains-jenkins-win.xml @@ -24,7 +24,7 @@ sun - F:\hudson\tools\java\jdk1.7.0_79 + F:\jenkins\tools\java\latest1.7 @@ -34,7 +34,7 @@ sun - F:\jenkins\tools\java\jdk1.8.0_152 + F:\jenkins\tools\java\latest1.8 @@ -44,7 +44,7 @@ sun - F:\jenkins\tools\java\jdk9.0.1 + F:\jenkins\tools\java\latest1.9 From 266e4745c9ef0bbea7460556c0dbff15aa5235a9 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:25:41 -0500 Subject: [PATCH 0136/2347] Fix java 9 path --- toolchains-jenkins-win.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchains-jenkins-win.xml b/toolchains-jenkins-win.xml index 5fa1f44d5be..51438bb8cf7 100644 --- a/toolchains-jenkins-win.xml +++ b/toolchains-jenkins-win.xml @@ -44,7 +44,7 @@ sun - F:\jenkins\tools\java\latest1.9 + F:\jenkins\tools\java\latest9 From 78c43c5b54d3814b618227525ae2d1cbb28ac276 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Fri, 6 Apr 2018 21:26:39 -0500 Subject: [PATCH 0137/2347] Revert to java 8 by default on jenkins windows --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index cbd481f7dc6..da86e52dea7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -40,7 +40,7 @@ pipeline { agent { label 'Windows' } tools { // https://cwiki.apache.org/confluence/display/INFRA/JDK+Installation+Matrix - jdk 'JDK 1.9 (latest)' + jdk 'JDK 1.8 (latest)' // https://cwiki.apache.org/confluence/display/INFRA/Maven+Installation+Matrix maven 'Maven 3 (latest)' } From 0738cf970c111a07a7307549b8c16af4d44af8a4 Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Mon, 2 Apr 2018 23:49:09 -0400 Subject: [PATCH 0138/2347] LOG4J2-2307: RingBufferLogEvent and MutableLogEvent memento to MementoLogEvent MementoLogEvent provides the original format string and parameters in addition to the formatted text. --- .../log4j/core/async/RingBufferLogEvent.java | 3 +- .../log4j/core/impl/MementoMessage.java | 83 +++++++++++++++++++ .../log4j/core/impl/MutableLogEvent.java | 2 +- .../apache/logging/log4j/core/LoggerTest.java | 11 ++- .../core/async/RingBufferLogEventTest.java | 26 ++++++ .../log4j/core/impl/MutableLogEventTest.java | 4 + src/changes/changes.xml | 3 + 7 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java index 27e719730f4..5e24d145b2e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java @@ -26,6 +26,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.impl.ContextDataFactory; import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.core.impl.MementoMessage; import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.time.Clock; import org.apache.logging.log4j.core.time.NanoClock; @@ -318,7 +319,7 @@ public CharSequence subSequence(final int start, final int end) { private Message getNonNullImmutableMessage() { - return message != null ? message : new SimpleMessage(String.valueOf(messageText)); + return message != null ? message : new MementoMessage(String.valueOf(messageText), messageFormat, getParameters()); } @Override diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java new file mode 100644 index 00000000000..c867ce44713 --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MementoMessage.java @@ -0,0 +1,83 @@ +/* + * 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.impl; + +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.StringBuilderFormattable; + +import java.util.Arrays; + +/** + * Consider this class private. + * + * {@link MementoMessage} is intended to be used when we need to make an + * immutable copy of a {@link Message} without forgetting the original + * {@link Message#getFormat()} and {@link Message#getParameters()} values. + * + * @since 3.0 + */ +public final class MementoMessage implements Message, StringBuilderFormattable { + + private final String formattedMessage; + private final String format; + private final Object[] parameters; + + public MementoMessage(String formattedMessage, String format, Object[] parameters) { + this.formattedMessage = formattedMessage; + this.format = format; + this.parameters = parameters; + } + + @Override + public String getFormattedMessage() { + return formattedMessage; + } + + @Override + public String getFormat() { + return format; + } + + @Override + public Object[] getParameters() { + return parameters; + } + + /** + * Always returns null. + * + * @return null + */ + @Override + public Throwable getThrowable() { + return null; + } + + @Override + public void formatTo(StringBuilder buffer) { + buffer.append(formattedMessage); + } + + @Override + public String toString() { + return "MementoMessage{" + + "formattedMessage='" + formattedMessage + '\'' + + ", format='" + format + '\'' + + ", parameters=" + Arrays.toString(parameters) + + '}'; + } +} diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java index ecabcbc32d4..be374a0867e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java @@ -309,7 +309,7 @@ public Message memento() { return message; } final Object[] params = parameters == null ? new Object[0] : Arrays.copyOf(parameters, parameterCount); - return new ParameterizedMessage(messageText.toString(), params); + return new MementoMessage(messageText.toString(), messageFormat, params); } @Override diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java index ba213ff5654..4cafb7b936d 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.core; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; @@ -39,9 +40,7 @@ import org.apache.logging.log4j.junit.LoggerContextRule; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.MessageFactory; -import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.ParameterizedMessageFactory; -import org.apache.logging.log4j.message.ReusableParameterizedMessage; import org.apache.logging.log4j.message.StringFormatterMessageFactory; import org.apache.logging.log4j.message.StructuredDataMessage; import org.apache.logging.log4j.spi.AbstractLogger; @@ -415,14 +414,14 @@ public void paramWithExceptionTest() throws Exception { logger.error("Throwing with parameters {}", "TestParam", new NullPointerException("Test Exception")); final List events = app.getEvents(); assertNotNull("Log event list not returned", events); - assertTrue("Incorrect number of log events: expected 1, actual " + events.size(), events.size() == 1); + assertEquals("Incorrect number of log events", 1, events.size()); final LogEvent event = events.get(0); final Throwable thrown = event.getThrown(); assertNotNull("No throwable present in log event", thrown); final Message msg = event.getMessage(); - assertTrue("Incorrect message type. Expected ParameterizedMessage/ReusableParameterizedMessage, actual " + msg.getClass().getSimpleName(), - msg instanceof ParameterizedMessage || msg instanceof ReusableParameterizedMessage); - + assertEquals("Throwing with parameters {}", msg.getFormat()); + assertEquals("Throwing with parameters TestParam", msg.getFormattedMessage()); + assertArrayEquals(new Object[] { "TestParam", thrown }, msg.getParameters()); } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java index 1d349216488..f89a10135b5 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java @@ -33,6 +33,7 @@ import org.apache.logging.log4j.core.time.internal.DummyNanoClock; import org.apache.logging.log4j.core.time.internal.FixedPreciseClock; import org.apache.logging.log4j.message.ParameterConsumer; +import org.apache.logging.log4j.message.ReusableMessageFactory; import org.apache.logging.log4j.util.FilteredObjectInputStream; import org.apache.logging.log4j.util.StringMap; import org.apache.logging.log4j.core.impl.ThrowableProxy; @@ -181,6 +182,31 @@ public void testCreateMementoReturnsCopy() { assertEquals(evt.getThrownProxy(), actual.getThrownProxy()); } + @Test + public void testCreateMementoRetainsParametersAndFormat() { + final RingBufferLogEvent evt = new RingBufferLogEvent(); + // Initialize the event with parameters + evt.swapParameters(new Object[10]); + final String loggerName = "logger.name"; + final Marker marker = MarkerManager.getMarker("marked man"); + final String fqcn = "f.q.c.n"; + final Level level = Level.TRACE; + ReusableMessageFactory factory = new ReusableMessageFactory(); + Message message = factory.newMessage("Hello {}!", "World"); + final Throwable t = new InternalError("not a real error"); + final ContextStack contextStack = new MutableThreadContextStack(Arrays.asList("a", "b")); + final String threadName = "main"; + final StackTraceElement location = null; + evt.setValues(null, loggerName, marker, fqcn, level, message, t, (StringMap) evt.getContextData(), + contextStack, -1, threadName, -1, location, new FixedPreciseClock(12345, 678), new DummyNanoClock(1)); + ((StringMap) evt.getContextData()).putValue("key", "value"); + + final Message actual = evt.createMemento().getMessage(); + assertEquals("Hello {}!", actual.getFormat()); + assertArrayEquals(new String[] { "World" }, actual.getParameters()); + assertEquals("Hello World!", actual.getFormattedMessage()); + } + @Test public void testMessageTextNeverThrowsNpe() { final RingBufferLogEvent evt = new RingBufferLogEvent(); diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java index 2bee6fb573e..655b561456b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java @@ -138,6 +138,10 @@ public void testInitFromReusableCopiesFormatString() { assertEquals("format", "msg in a {}", mutable.getFormat()); assertEquals("formatted", "msg in a bottle", mutable.getFormattedMessage()); assertEquals("parameters", new String[] {"bottle"}, mutable.getParameters()); + Message memento = mutable.memento(); + assertEquals("format", "msg in a {}", memento.getFormat()); + assertEquals("formatted", "msg in a bottle", memento.getFormattedMessage()); + assertEquals("parameters", new String[] {"bottle"}, memento.getParameters()); } @Test diff --git a/src/changes/changes.xml b/src/changes/changes.xml index f172b529ef4..d7ca266d0e5 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -118,6 +118,9 @@ FixedDateFormat parses timezone offsets, -8:00 is interpreted as GMT-8:00. + + MutableLogEvent and RingBufferLogEvent message mementos retain the original format string. + From f553c1af6f5bb7a49f012789a22bbde190d98aff Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 11:30:22 -0500 Subject: [PATCH 0139/2347] Add missing license headers --- src/site/asciidoc/manual/api.adoc | 16 ++++++++++++++++ src/site/asciidoc/manual/appenders.adoc | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/site/asciidoc/manual/api.adoc b/src/site/asciidoc/manual/api.adoc index d708aa166d2..6a6e15f9f64 100644 --- a/src/site/asciidoc/manual/api.adoc +++ b/src/site/asciidoc/manual/api.adoc @@ -1,3 +1,19 @@ +//// + 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 + + https://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. +//// = Log4j 2 API == Overview diff --git a/src/site/asciidoc/manual/appenders.adoc b/src/site/asciidoc/manual/appenders.adoc index b37af239ed3..526dcf30c86 100644 --- a/src/site/asciidoc/manual/appenders.adoc +++ b/src/site/asciidoc/manual/appenders.adoc @@ -1,3 +1,19 @@ +//// + 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 + + https://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. +//// = Appenders Ralph Goers; Gary Gregory; Nick Williams; Matt Sicker From c6b4182d8b4d54beeb74feafa7232edebbd814c1 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 12:08:49 -0500 Subject: [PATCH 0140/2347] LOG4J2-1802: Convert runtime dependencies page to asciidoc --- src/site/asciidoc/runtime-dependencies.adoc | 291 ++++++++++++++ src/site/xdoc/runtime-dependencies.xml | 413 -------------------- 2 files changed, 291 insertions(+), 413 deletions(-) create mode 100644 src/site/asciidoc/runtime-dependencies.adoc delete mode 100644 src/site/xdoc/runtime-dependencies.xml diff --git a/src/site/asciidoc/runtime-dependencies.adoc b/src/site/asciidoc/runtime-dependencies.adoc new file mode 100644 index 00000000000..36e8a427965 --- /dev/null +++ b/src/site/asciidoc/runtime-dependencies.adoc @@ -0,0 +1,291 @@ +//// + 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 + + https://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. +//// += Runtime Dependencies + +Some Log4j features depend on external libraries. This page lists the +required and optional dependencies. + +As of version 2.10.0 the Log4j API is a Java module (with a +module-info.java). Many of the other jars are automatic modules. The +characteristics of the modules are: + +[cols="3h,5m,12a"] +|=== +|Artifact Name |Module Name |Module Characteristics + +|log4j-api +|org.apache.logging.log4j +| +[cols="m,"] +!=== +!Module Directive !Notes + +2+!exports org.apache.logging.log4j + +2+!exports org.apache.logging.log4j.message + +2+!exports org.apache.logging.log4j.simple + +2+!exports org.apache.logging.log4j.spi + +2+!exports org.apache.logging.log4j.spi + +!exports org.apache.logging.log4j.util +!Some classes in this package are used by the logging implementation and should be considered private. +The module info definition may be modified in the future to export these only to the logging implementation. + +!uses org.apache.logging.log4j.spi.Provider +!Service that must be provided by the logging implementation. +!=== + +|log4j-core +|org.apache.logging.log4j.core +|Automatic Module + +|log4j-1.2-api +|org.apache.log4j +|Automatic Module + +|log4j-appserver +|org.apache.logging.log4j.appserver +|Automatic Module + +|log4j-flume-ng +|org.apache.logging.log4j.flume +|Automatic Module + +|log4j-iostreams +|org.apache.logging.log4j.iostreams +|Automatic Module + +|log4j-jcl +|org.apache.logging.log4j.jcl +|Automatic Module + +|log4j-jmx-gui +|org.apache.logging.log4j.jmx.gui +|Automatic Module + +|log4j-jul +|org.apache.logging.log4j.jul +|Automatic Module + +|log4j-couchdb +|org.apache.logging.log4j.couchdb +|Automatic Module + +|log4j-mongodb +|org.apache.logging.log4j.mongodb +|Automatic Module + +|log4j-cassandra +|org.apache.logging.log4j.cassandra +|Automatic Module + +|log4j-osgi +|org.apache.logging.log4j.osgi +|Automatic Module. Unclear how OSGi will support Java modules. + +|log4j-slf4j-impl +|org.apache.logging.log4j.slf4j.impl +|Automatic Module. May require renaming should SLF4J ever require all implementations to have the same module name. + +|log4j-to-slf4j +|org.apache.logging.log4j.slf4j +|Automatic Module + +|log4j-taglib +|org.apache.logging.log4j.taglib +|Automatic Module + +|log4j-web +|org.apache.logging.log4j.web +|Automatic Module +|=== + +As of version 2.9.1 Log4j supports Java 9 but will still work in Java 7 +or 8. In this version log4j-api is packaged as a multi-release jar and +supports the use of the StackWalker and Process APIs. + +As of version 2.4, Log4j requires Java 7. + +Log4j version 2.3 and older require Java 6. + +log4j-api[[log4j-api]]:: +The Log4j link:log4j-api/index.html[API] module has no external +dependencies. + +log4j-core[[log4j-core]]:: +The Log4j link:log4j-core/index.html[Implementation] has several +optional link:log4j-core/dependencies.html[dependencies]. See the +link:log4j-core/dependencies.html#Dependency_Tree[Dependency Tree] for +the exact list of JAR files needed for these features. + +.Optional Dependencies per Feature in Log4j Implementation +[cols="1,3"] +|=== +|Feature |Requirements + +|XML configuration +|- + +|Properties configuration +|- + +|JSON configuration +|https://github.com/FasterXML/jackson[Jackson core and databind] + +|YAML configuration +|https://github.com/FasterXML/jackson[Jackson databind] and https://github.com/FasterXML/jackson-dataformat-yaml[YAML data format] + +|CSV Layout +|https://commons.apache.org/proper/commons-csv/[Apache Commons CSV] + +|JSON Layout +|https://github.com/FasterXML/jackson[Jackson core and databind] + +|XML Layout +|https://github.com/FasterXML/jackson[Jackson core, databind and dataformat XML] and `com.fasterxml.woodstox:woodstox-core:5.0.2` + +|YAML Layout +|https://github.com/FasterXML/jackson[Jackson core, databind] and https://github.com/FasterXML/jackson-dataformat-yaml[YAML data format] + +|Async Loggers +|http://lmax-exchange.github.io/disruptor/[LMAX Disruptor] + +|Kafka Appender +a|http://kafka.apache.org/[Kafka client library]. +[NOTE] +==== +You need to use a version of the Kafka client library matching the Kafka server used. +==== + +|SMTP Appender +|an implementation of `javax.mail` + +|JMS Appender +|a JMS broker like http://activemq.apache.org/[Apache ActiveMQ] + +|Windows console color support +|http://jansi.fusesource.org/[Jansi] + +|JDBC Appender +|a JDBC driver for the database you choose to write events to + +|JPA Appender +|the Java Persistence API classes, a JPA provider implementation, and a decorated entity that the user implements. +It also requires an appropriate JDBC driver + +|NoSQL Appender with MongoDB provider +|MongoDB Java Client driver and Log4j MongoDB library + +|NoSQL Appender with Apache CouchDB provider +|LightCouch CouchDB client library and Log4j CouchDB library + +|Cassandra Appender +|Datastax Cassandra driver and Log4j Cassandra library + +|Bzip2, Deflate, Pack200, and XZ compression on rollover +|http://commons.apache.org/proper/commons-compress/[Apache Commons Compress]. +In addition, XZ requires http://tukaani.org/xz/java.html[XZ for Java]. + +|ZeroMQ Appender +|The ZeroMQ appender uses the https://github.com/zeromq/jeromq[JeroMQ] library which is licensed under the terms of the Mozilla Public License Version 2.0 (MPLv2). +For details see the file https://github.com/zeromq/jeromq/blob/master/LICENSE[LICENSE] included with the JeroMQ distribution. +|=== + +log4j-jcl[[log4j-jcl]]:: +The link:log4j-jcl/index.html[Commons Logging Bridge] requires +http://commons.apache.org/proper/commons-logging/[Commons Logging]. See +the link:log4j-jcl/dependencies.html#Dependency_Tree[Dependency Tree] +for the exact list of JAR files needed. + +log4j-1.2-api[[log4j-1.2-api]]:: +The link:log4j-1.2-api/index.html[Log4j 1.2 Bridge] has no external +dependencies. This only requires the Log4j API and Log4j Core. + +log4j-slf4j-impl[[log4j-slf4j-impl]]:: +The Log4j 2 link:log4j-slf4j-impl/index.html[SLF4J Binding] depends on +the http://www.slf4j.org/[SLF4J] API. See the +link:log4j-slf4j-impl/dependencies.html#Dependency_Tree[Dependency Tree] +for the exact list of JAR files needed. + +WARNING: Do not use this with the link:#log4j-to-slf4j[log4j-to-slf4j] module. + +log4j-jul[[log4j-jul]]:: +The Log4j 2 link:log4j-jul/index.html[Java Util Logging Adapter] has no +external dependencies. It optionally depends on the +link:log4j-api/index.html[Log4j Core] library. The only required module +is the Log4j API. + +log4j-to-slf4j[[log4j-to-slf4j]]:: +The link:log4j-to-slf4j/index.html[Log4j 2 to SLF4J Adapter] requires +the http://www.slf4j.org/[SLF4J] API and an SLF4J implementation. See +the link:log4j-to-slf4j/dependencies.html#Dependency_Tree[Dependency +Tree] for the exact list of JAR files needed. + +WARNING: Do not use this with the link:#log4j-slf4j-impl[log4j-slf4j-impl] module. + +log4j-flume-ng[[log4j-flume-ng]]:: +The link:log4j-flume-ng/index.html[Flume Appender] requires +http://flume.apache.org/[Apache Flume] and +http://avro.apache.org/[Apache Avro]. The persistent agent uses Berkeley +DB. See the +link:log4j-flume-ng/dependencies.html#Dependency_Tree[Dependency Tree] +for the exact list of JAR files needed. + +log4j-taglib[[log4j-taglib]]:: +The Log4j link:log4j-taglib/index.html[Log Tag Library] requires the +http://jakarta.apache.org/taglibs/log/[Jakarta Commons Log Taglib] and +the Servlet API. See the +link:log4j-taglib/dependencies.html#Dependency_Tree[Dependency Tree] for +the exact list of JAR files needed. + +log4j-jmx-gui[[log4j-jmx-gui]]:: +The Log4j link:log4j-jmx-gui/index.html[JMX GUI] requires the JConsole +jar when run as a JConsole plugin. Otherwise it has no external +dependencies. See the +link:log4j-jmx-gui/dependencies.html#Dependency_Tree[Dependency Tree] +for the exact list of JAR files needed. + +log4j-web[[log4j-web]]:: +The Log4j link:log4j-web/index.html[Web] module requires the Servlet +API. See the link:log4j-web/dependencies.html#Dependency_Tree[Dependency +Tree] for the exact list of JAR files needed. Note that this works with +the Servlet 2.5 API as well as the Servlet 3.x API. + +log4j-couchdb[[log4j-couchdb]]:: +The Log4j link:log4j-couchdb/index.html[CouchDB] module depends on the +http://www.lightcouch.org/[LightCouch] CouchDB client library. + +log4j-mongodb[[log4j-mongodb]]:: +The Log4j link:log4j-mongodb/index.html[MongoDB] module depends on the +http://docs.mongodb.org/ecosystem/drivers/java/[MongoDB Java Client +driver]. + +log4j-cassandra[[log4j-cassandra]]:: +The Log4j link:log4j-cassandra/index.html[Cassandra] module depends on the +http://docs.datastax.com/en/developer/driver-matrix/doc/javaDrivers.html[Datastax +Cassandra driver]. + +log4j-iostreams[[log4j-iostreams]]:: +The Log4j link:log4j-iostreams/index.html[IO Streams] module has no +external dependencies. This only requires the Log4j API. + +log4j-api-scala[[log4j-api-scala]]:: +The Log4j link:manual/scala-api.html[Scala API] requires Scala runtime +library and reflection in addition to the Log4j API. diff --git a/src/site/xdoc/runtime-dependencies.xml b/src/site/xdoc/runtime-dependencies.xml deleted file mode 100644 index 9429febb887..00000000000 --- a/src/site/xdoc/runtime-dependencies.xml +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - Log4j Runtime Dependencies - - - -
    -

    - Some Log4J features depend on external libraries. This page lists the required and optional - dependencies. -

    -

    - As of version 2.10.0 the Log4j API is a Java module (with a module-info.java). Many of the other - jars are automatic modules. The characteristics of the modules are: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Artifact NameModule NameModule Characteristics
    log4j-apiorg.apache.logging.log4j - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Module DirectiveNotes
    exports org.apache.logging.log4j
    exports org.apache.logging.log4j.message
    exports org.apache.logging.log4j.simple
    exports org.apache.logging.log4j.spi
    exports org.apache.logging.log4j.spi
    exports org.apache.logging.log4j.utilSome classes in this package are used by the logging implementation and should be - considered private. The module info definition may be modified in the future to export - these only to the logging implmentation.
    uses org.apache.logging.log4j.spi.ProviderService that must be provided by the logging implementation.
    -
    log4j-coreorg.apache.logging.log4j.coreAutomatic Module
    log4j-1.2-apiorg.apache.log4jAutomatic Module
    log4j-appserverorg.apache.logging.log4j.appserverAutomatic Module
    log4j-flume-ngorg.apache.logging.log4j.flumeAutomatic Module
    log4j-iostreamsorg.apache.logging.log4j.iostreamsAutomatic Module
    log4j-jclorg.apache.logging.log4j.jclAutomatic Module
    log4j-jmx-guiorg.apache.logging.log4j.jmx.guiAutomatic Module
    log4j-julorg.apache.logging.log4j.julAutomatic Module
    log4j-couchdborg.apache.logging.log4j.couchdbAutomatic Module
    log4j-mongodborg.apache.logging.log4j.mongodbAutomatic Module
    log4j-cassandraorg.apache.logging.log4j.cassandraAutomatic Module
    log4j-osgiorg.apache.logging.log4j.osgiAutomatic Module. Unclear how OSGi will support Java modules.
    log4j-slf4j-implorg.apache.logging.log4j.slf4j.implAutomatic Module. May require renaming should SLF4J ever require all implementations to have the same - module name.
    log4j-to-slf4jorg.apache.logging.log4j.slf4jAutomatic Module
    log4j-tagliborg.apache.logging.log4j.taglibAutomatic Module
    log4j-weborg.apache.logging.log4j.webAutomatic Module
    -

    -

    - As of version 2.9.1 Log4j supports Java 9 but will still work in Java 7 or 8. In this version log4j-api is - packaged as a multi-release jar and supports the use of the StackWalker and Process APIs. -

    -

    - As of version 2.4, Log4J requires Java 7. -

    -

    - Log4j version 2.3 and older require Java 6. -

    - -
    -

    log4j-api

    -

    - The Log4J API module has no external dependencies. -

    - - -

    log4j-core

    -

    - The Log4J Implementation has several optional - dependencies. - See the Dependency Tree for the - exact list of JAR files needed for these features. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Optional Dependencies per Feature in Log4J Implementation
    FeatureRequirements
    XML configuration-
    Properties configuration-
    JSON configurationJackson core and databind
    YAML configurationJackson databind and YAML data format
    CSV LayoutApache Commons CSV
    JSON LayoutJackson core and databind
    XML LayoutJackson core, databind and dataformat XML
    - And com.fasterxml.woodstox:woodstox-core:5.0.2
    YAML LayoutJackson core, databind and YAML data format
    Async LoggersLMAX Disruptor
    Kafka AppenderKafka client library. Note that you need to use a version of - the Kafka client library matching the Kafka server used.
    SMTP Appenderan implementation of javax.mail
    JMS Appendera JMS broker like Apache ActiveMQ
    Windows console color supportJansi
    JDBC Appendera JDBC driver for the database you choose to write events to
    JPA Appenderthe Java Persistence API classes, a JPA provider implementation, and a decorated - entity that the user implements. It also requires an appropriate JDBC driver -
    NoSQL Appender with MongoDB providerMongoDB Java Client driver and Log4j MongoDB library
    NoSQL Appender with Apache CouchDB providerLightCouch CouchDB client library and Log4j CouchDB library
    Cassandra AppenderDatastax Cassandra driver and Log4j Cassandra library
    Bzip2, Deflate, Pack200, and XZ compression on rolloverApache Commons Compress. - In addition, XZ requires XZ for Java. -
    ZeroMQ Appender - The ZeroMQ appender uses the JeroMQ library which is - licensed under the terms of the Mozilla Public License Version 2.0 (MPLv2). For details see the - file LICENSE included with the JeroMQ - distribution. -
    - - -

    log4j-jcl

    -

    - The Commons Logging Bridge requires - Commons Logging. See the - Dependency Tree for the exact - list of JAR files needed. -

    - - -

    log4j-1.2-api

    -

    - The Log4j 1.2 Bridge has no external dependencies. - This only requires the Log4j API and Log4j Core. -

    - - -

    log4j-slf4j-impl

    -

    - The Log4j 2 SLF4J Binding depends on the - SLF4J API. See the - Dependency Tree for the exact - list of JAR files needed. -

    -

    - - - Do not use this with the log4j-to-slf4j module. - -

    - - -

    log4j-jul

    -

    - The Log4j 2 Java Util Logging Adapter has no external dependencies. - It optionally depends on the Log4j Core library. The only required module - is the Log4j API. -

    - - -

    log4j-to-slf4j

    -

    - The Log4j 2 to SLF4J Adapter requires the - SLF4J API and an SLF4J implementation. See the - Dependency Tree for the exact list of JAR files needed. -

    -

    - - - Do not use this with the log4j-slf4j-impl module. - -

    - - -

    log4j-flume-ng

    -

    - The Flume Appender requires - Apache Flume and Apache Avro. - The persistent agent uses Berkeley DB. See the - Dependency Tree for the exact list of JAR files needed. -

    - - -

    log4j-taglib

    -

    - The Log4j Log Tag Library requires the - Jakarta Commons Log Taglib and the Servlet API. See the - Dependency Tree for the exact list of JAR files needed. -

    - - -

    log4j-jmx-gui

    -

    - The Log4j JMX GUI requires the JConsole jar when run as a JConsole plugin. - Otherwise it has no external dependencies. See the - Dependency Tree for the exact list of JAR files needed. -

    - - -

    log4j-web

    -

    - The Log4j Web module requires the Servlet API. See the - Dependency Tree for the exact list of JAR files needed. - Note that this works with the Servlet 2.5 API as well as the Servlet 3.x API. -

    - - -

    log4j-couchdb

    -

    - The Log4J CouchDB module depends on - the LightCouch CouchDB client library. -

    - - -

    log4j-mongodb

    -

    - The Log4J MongoDB module depends on - the MongoDB Java Client driver. -

    - - -

    log4j-cassandra

    -

    - The Log4J Cassandra module depends on - the Datastax Cassandra driver. -

    - - -

    log4j-iostreams

    -

    - The Log4j IO Streams module has no external dependencies. - This only requires the Log4j API. -

    - - -

    log4j-api-scala

    -

    - The Log4j Scala API requires Scala runtime library and reflection in - addition to the Log4j API. -

    - -
    - - From d159edb62ac888f102d4f40f2f6ea5f10565be5b Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 12:27:15 -0500 Subject: [PATCH 0141/2347] LOG4J2-1802: Convert performance page to asciidoc --- src/site/asciidoc/performance.adoc | 571 +++++++++++++++++++++++++++++ src/site/xdoc/performance.xml | 469 ----------------------- 2 files changed, 571 insertions(+), 469 deletions(-) create mode 100644 src/site/asciidoc/performance.adoc delete mode 100644 src/site/xdoc/performance.xml diff --git a/src/site/asciidoc/performance.adoc b/src/site/asciidoc/performance.adoc new file mode 100644 index 00000000000..4e25ba5a1e6 --- /dev/null +++ b/src/site/asciidoc/performance.adoc @@ -0,0 +1,571 @@ +//// + 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 + + https://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. +//// += Performance +Remko Popma ; Ralph Goers + +//// +One of the often-cited arguments against logging is its +computational cost. This is a legitimate concern as even moderately +sized applications can generate thousands of log requests. Much +effort was spent measuring and tweaking logging performance. Log4j +claims to be fast and flexible: speed first, flexibility second. +//// + +Apart from functional requirements, an important reason for selecting a +logging library is often how well it fulfills non-functional +requirements like reliability and performance. + +This page compares the performance of a number of logging frameworks +(java.util.logging "JUL", Logback, Log4j 1.2 and Log4j 2.6), and +documents some performance trade-offs for Log4j 2 functionality. + +[#benchmarks] +== Benchmarks + +Performance can mean different things to different people. Common terms +in this context are throughput and latency: _Throughput_ is a measure of +capacity and can be expressed in a single number: how many messages can +be logged in a certain period of time. _Response time latency_ is how +long it takes to log a message. This cannot be expressed in a single +number because each measurement has its own response time and we are +often most interested in the outliers: how many there were and how large +they were. + +When evaluating a logging framework's performance these may be useful +questions to ask: + +[qanda] +What is its *peak throughput*?:: +Many systems that react to external +events need to log bursts of messages followed by periods of relative +quiet. This number is the maximum throughput measured over a short +period of time and gives some idea of how well the logging library deals +with bursts. For systems that need to log a lot at a constant high rate +(for example, batch jobs) this is less likely to be a useful measure of +performance. + +What is the *maximum sustained throughput*?:: +This is the throughput +averaged over a long time. This is a useful measure of the "upper limit" +of the capacity of the logging library. It is not recommended that +reactive applications actually log at this rate since under this load +they will likely experience jitter and large response time spikes. + +What is its *response time* behaviour under various loads?:: +This is the +most important question for applications that need to react to external +events in a timely manner. Response time is the total amount of time it +takes to log a message and is the sum of the service time and wait time. +The *service time* is the time it takes to do the work to log the +message. As the workload increases, the service time often varies +little: to do X amount of work it always takes X amount of time. The +*wait time* is how long the request had to wait in a queue before being +serviced. _As the workload increases, wait time often grows to many +times the service time._ + +[[responseTimeVsServiceTime]] + +.Why Care About Response Time Latency? +**** +[width="100%",cols="50%,50%"] +|=== +a| +What is often measured and reported as _latency_ is actually _service +time_, and omits that a service time spike adds wait time for many +subsequent events. This may present results that are more optimistic +than what users experience. + +The graph on the right illustrates how much more optimistic service time +is than response time. The graph shows response time and service time +for the same system under a load of 100,000 messages per second. Out of +24 million measurements, only ~50 are more than 250 microseconds, less +than 0.001%. In a service time-only graph this would hardly be visible. +However, the depending on the load it will take a while to catch up +after a spike. + +The response time graph shows that in reality many more events are +impacted by these delays than the service time numbers alone would +suggest. + +To learn more, watch Gil Tene's eye-opening presentation +http://www.infoq.com/presentations/latency-response-time[How NOT to +measure latency]. + + +|link:images/ResponseTimeVsServiceTimeAsyncLoggers.png[image:images/ResponseTimeVsServiceTimeAsyncLoggers.png[image,width=480,height=288]] +|=== +**** + +[#loglibComparison] +== Logging Library Performance Comparison + +[#asyncLogging] +=== Asynchronous Logging - Peak Throughput Comparison + +Asynchronous logging is useful to deal with bursts of events. How this +works is that a minimum amount of work is done by the application thread +to capture all required information in a log event, and this log event +is then put on a queue for later processing by a background thread. As +long as the queue is sized large enough, the application threads should +be able to spend very little time on the logging call and return to the +business logic very quickly. + +It turns out that the choice of queue is extremely important for peak +throughput. Log4j 2's Async Loggers use a +http://lmax-exchange.github.com/disruptor/[lock-free data structure], +whereas Logback, Log4j 1.2 and Log4j 2's Asynchronous Appenders use an +ArrayBlockingQueue. With a blocking queue, multi-threaded applications +often experience lock contention when trying to enqueue the log event. + +The graph below illustrates the difference a lock-free data structure +can make to throughput in multi-threaded scenarios. _Log4j 2 scales +better with the number of threads: an application with more threads can +log more. The other logging libraries suffer from lock contention and +total throughput stays constant or drops when more threads are logging. +This means that with the other logging libraries, each individual thread +will be able to log less._ + +Bear in mind that this is _peak_ throughput: Log4j 2's Async Loggers +give better throughput up to a point, but once the queue is full, the +appender thread needs to wait until a slot becomes available in the +queue, and throughput will drop to the maximum sustained throughput of +the underlying appenders at best. + +image:images/async-throughput-comparison.png[Peak throughput comparison] + +For details, see the link:manual/async.html[Async Loggers] manual page. + +[#asyncLoggingResponseTime] +=== Asynchronous Logging Response Time + +Response time behaviour varies a lot with the workload and the number of +threads that log concurrently. The link:manual/async.html#Latency[Async +Loggers] manual page and the +link:manual/garbagefree.html#Latency[garbage-free logging] manual page +provide some graphs showing response time behaviour under various loads. + +This section shows another graph showing response time latency behaviour +under a modest total workload of 64,000 messages per second, with 4 +threads logging concurrently. At this load and on this hardware/OS/JVM +configuration, lock contention and context switches play less of a role +and the pauses are mostly caused by minor garbage collections. Garbage +collection pause duration and frequency can vary a lot: when testing the +Log4j 1.2.17 Async Appender a minor GC pause of 7 milliseconds occurred +while the Log4j 2 Async Appender test only saw a GC pause of a little +over 2 milliseconds. This does not necessarily mean that one is better +than the other. + +Generally, garbage-free async loggers had the best response time +behaviour in all configurations we tested. + +image:images/ResponseTimeAsyncLogging4Threads@16kEach.png[Response time comparison] + +The above result was obtained with the ResponseTimeTest class which can +be found in the Log4j 2 unit test source directory, running on JDK +1.8.0_45 on RHEL 6.5 (Linux 2.6.32-573.1.1.el6.x86_64) with 10-core Xeon +CPU E5-2660 v3 @2.60GHz with hyperthreading switched on (20 virtual +cores). + +[#asyncLoggingWithParams] +=== Asynchronous Logging Parameterized Messages + +Many logging libraries offer an API for logging parameterized messages. +This enables application code to look something like this: + +[source,java] +---- +logger.debug("Entry number: {} is {}", i, entry[i]); +---- + +In the above example, the fully formatted message text is not created +unless the DEBUG level is enabled for the logger. Without this API, you +would need three lines of code to accomplish the same: + +[source,java] +---- +if (logger.isDebugEnabled()) { + logger.debug("Entry number: " + i + " is " + entry[i].toString()); +} +---- + +If the DEBUG level _is_ enabled, then at some point the message needs to +be formatted. When logging asynchronously, the message parameters may be +changed by the application thread before the background thread had a +chance to log the message. This would show the wrong values in the log +file. To prevent this, Log4j 2, Log4j 1.2 and Logback format the message +text in the application thread _before_ passing off the log event to the +background thread. + +This is the safe thing to do, but the formatting has a performance cost. +The graph below compares the throughput of logging messages with +parameters using various logging libraries. These are all asynchronous +logging calls, so these numbers do not include the cost of disk I/O and +represent _peak_ throughput. + +JUL (java.util.logging) does not have a built-in asynchronous Handler. +https://docs.oracle.com/javase/8/docs/api/java/util/logging/MemoryHandler.html[`MemoryHandler`] +is the nearest thing available so we included it here. MemoryHandler +does _not_ do the safe thing of taking a snapshot of the current +parameter state (it just keeps a reference to the original parameter +objects), and as a result it is very fast when single-threaded. However, +when more application threads are logging concurrently, the cost of lock +contention outweighs this gain. + +In absolute numbers, _Log4j 2's Async Loggers perform well compared to +the other logging frameworks, but notice that the message formatting +cost increases sharply with the number of parameters. In this area, +Log4j 2 still has work to do to improve: we would like to keep this cost +more constant._ + +image:images/ParamMsgThrpt1-4T.png[image] + +The results above are for JUL (java.util.logging) 1.8.0_45, Log4j 2.6, +Log4j 1.2.17 and Logback 1.1.7, and were obtained with the +http://openjdk.java.net/projects/code-tools/jmh/[JMH] Java benchmark +harness. See the AsyncAppenderLog4j1Benchmark, +AsyncAppenderLog4j2Benchmark, AsyncAppenderLogbackBenchmark, +AsyncLoggersBenchmark and the MemoryHandlerJULBenchmark source code in +the log4j-perf module. + +[#asyncLoggingWithLocation] +=== Asynchronous Logging with Caller Location Information + +Some layouts can show the class, method and line number in the +application where the logging call was made. In Log4j 2, examples of +such layout options are HTML +link:layouts.html#HtmlLocationInfo[locationInfo], or one of the patterns +link:layouts.html#PatternClass[%C or $class], +link:layouts.html#PatternFile[%F or %file], +link:layouts.html#PatternLocation[%l or %location], +link:layouts.html#PatternLine[%L or %line], +link:layouts.html#PatternMethod[%M or %method]. In order to provide +caller location information, the logging library will take a snapshot of +the stack, and walk the stack trace to find the location information. + +The graph below shows the performance impact of capturing caller +location information when logging asynchronously from a single thread. +Our tests show that _capturing caller location has a similar impact +across all logging libraries, and slows down asynchronous logging by +about 30-100x_. + +image:images/AsyncWithLocationThrpt1T-labeled.png[image] + +The results above are for JUL (java.util.logging) 1.8.0_45, Log4j 2.6, +Log4j 1.2.17 and Logback 1.1.7, and were obtained with the +http://openjdk.java.net/projects/code-tools/jmh/[JMH] Java benchmark +harness. See the AsyncAppenderLog4j1LocationBenchmark, +AsyncAppenderLog4j2LocationBenchmark, +AsyncAppenderLogbackLocationBenchmark, AsyncLoggersLocationBenchmark and +the MemoryHandlerJULLocationBenchmark source code in the log4j-perf +module. + +[#fileLoggingComparison] +=== Synchronous File Logging - Sustained Throughput Comparison + +This section discusses the maximum sustained throughput of logging to a +file. In any system, the maximum sustained throughput is determined by +its slowest component. In the case of logging, this is the appender, +where the message formatting and disk I/O takes place. For this reason +we will look at simple _synchronous_ logging to a file, without queues +or background threads. + +The graph below compares Log4j 2.6's RandomAccessFile appender to the +respective File appenders of Log4j 1.2.17, Logback 1.1.7 and Java util +logging (JUL) on Oracle Java 1.8.0_45. ImmediateFlush was set to false +for all loggers that support this. The JUL results are for the +XMLFormatter (which in our measurements was about twice as fast as the +SimpleFormatter). + +_Log4j 2's sustained throughput drops a little when more threads are +logging simultaneously, but its fine-grained locking pays off and +throughput stays relatively high. The other logging frameworks' +throughput drops dramatically in multi-threaded applications: Log4j 1.2 +has 1/4th of its single-threaded capacity, Logback has 1/10th of its +single-threaded capacity, and JUL steadily drops from 1/4th to 1/10th of +its single-threaded throughput as more threads are added._ + +image:images/SyncThroughputLoggerComparisonLinux.png[image] + +The synchronous logging throughput results above are obtained with the +http://openjdk.java.net/projects/code-tools/jmh/[JMH] Java benchmark +harness. See the FileAppenderBenchmark source code in the log4j-perf +module. + +=== Synchronous File Logging - Response Time Comparison + +Response time for synchronous file logging varies a lot with the +workload and the number of threads. Below is a sample for a workload of +32,000 events per second, with 2 threads logging 16,000 events per +second each. + +image:images/SynchronousFileResponseTime2T32k-labeled.png[image] + +The above result was obtained with the ResponseTimeTest class which can +be found in the Log4j 2 unit test source directory, running on JDK +1.8.0_45 on RHEL 6.5 (Linux 2.6.32-573.1.1.el6.x86_64) with 10-core Xeon +CPU E5-2660 v3 @2.60GHz with hyperthreading switched on (20 virtual +cores). + +//// +TODO +=== Synchronous Socket Sustained Throughput Comparison + +=== Synchronous Syslog Sustained Throughput Comparison +//// + +[#filtering] +=== Filtering by Level + +The most basic filtering a logging framework provides is filtering by +log level. When logging is turned off entirely or just for a set of +Levels, the cost of a log request consists of a number of method +invocations plus an integer comparison. Unlike Log4j, Log4j 2 Loggers +don't "walk a hierarchy". Loggers point directly to the Logger +configuration that best matches the Logger's name. This incurs extra +overhead when the Logger is first created but reduces the overhead every +time the Logger is used. + +=== Advanced Filtering + +Both Logback and Log4j 2 support advanced filtering. Logback calls them +TurboFilters while Log4j 2 has a single Filter object. Advanced +filtering provides the capability to filter LogEvents using more than +just the Level before the events are passed to Appenders. However, this +flexibility does come with some cost. Since multi-threading can also +have an impact on the performance of advanced filtering, the chart below +shows the difference in performance of filtering based on a Marker or a +Marker's parent. + +The "Simple Marker" comparison checks to see if a Marker that has no +references to other markers matches the requested Marker. The "Parent +Marker" comparison checks to see if a Marker that does have references +to other markers matches the requested Marker. + +It appears that coarse-grained synchronization in SLF4J can impact +performance in multi-threaded scenarios. See +http://jira.qos.ch/browse/SLF4J-240[SLF4J-240]. + +image:images/MarkerFilterCostComparison.png[image] + +Log4j and Logback also support filtering on a value in the Log4j +ThreadContext vs filtering in Logback on a value in the MDC. The graph +below shows that the performance difference between Log4j 2 and Logback +is small for the ThreadContext filter. + +image:images/ThreadContextFilterCostComparison.png[image] + +The Filter comparison results above are obtained with the +http://openjdk.java.net/projects/code-tools/jmh/[JMH] Java benchmark +harness. See the MarkerFilterBenchmark and MDCFilterBenchmark in the +log4j-perf module for details on these benchmarks. + +[#tradeoffs] +== Trade-offs + +[#whichAppender] +=== Which Log4j 2 Appender to Use? + +Assuming that you selected Log4j 2 as your logging framework, next you +may be interested in learning what the performance trade-offs are for +selecting a specific Log4j 2 configuration. For example, there are three +appenders for logging to a file: the File, RandomAccessFile and +MemoryMappedFile appenders. Which one should you use? + +If performance is all you care about, the graphs below show your best +choice is either the MemoryMappedFile appender or the RandomAccessFile +appender. Some things to bear in mind: + +* MemoryMappedFile appender does not have a rolling variant yet. +* When the log file size exceeds the MemoryMappedFile's region length, +the file needs to be remapped. This can be a very expensive operation, +taking several seconds if the region is large. +* MemoryMappedFile appender creates a presized file from the beginning +and fills it up gradually. This can confuse tools like `tail`; many such +tools don't work very well with memory mapped files. +* On Windows, using a tool like `tail` on a file created by +RandomAccessFile appender can hold a lock on this file which may prevent +Log4j from opening the file again when the application is restarted. In +a development environment where you expect to restart your application +regularly while using tools like tail to view the log file contents, the +File appender may be a reasonable trade-off between performance and +flexibility. For production environments performance may have higher +priority. + +The graph below shows sustained throughput for the console and file +appenders in Log4j 2.6, and for reference also provides the 2.5 +performance. + +It turns out that the garbage-free text encoding logic in 2.6 gives +these appenders a performance boost compared to Log4j 2.5. It used to be +that the RandomAccessFile appender was significantly faster, especially +in multi-threaded scenarios, but with the 2.6 release the File appender +performance has improved and the performance difference between these +two appender is smaller. + +Another takeaway is just how much of a performance drag logging to the +console can be. Considering logging to a file and using a tool like +`tail` to watch the file change in real time. + +image:images/Log4j2AppenderThroughputComparison-linux.png[image] + +On Windows, the results are similar but the RandomAccessFile and +MemoryMappedFile appenders outperform the plain File appender in +multi-threaded scenarios. The absolute numbers are higher on Windows: we +don't know why but it looks like Windows handles lock contention better +than Linux. + +image:images/Log4j2AppenderThroughputComparison-windows.png[image] + +The Log4j 2 appender comparison results above are obtained with the +http://openjdk.java.net/projects/code-tools/jmh/[JMH] Java benchmark +harness. See the Log4j2AppenderComparisonBenchmark source code in the +log4j-perf module. + +//// +The user should be aware of the following performance issues. + +=== Logging performance when logging is turned off. + +When logging is turned off entirely or just for a set of Levels, the +cost of a log request consists of two method invocations plus an integer +comparison. On a 2.53 GHz Intel Core 2 Duo MacBook Pro calling +isDebugEnabled 10 million times produces an average result in +nanoseconds of: + +.... + Log4j: 4 + Logback: 5 + Log4j 2: 3 + +.... + +The numbers above will vary slightly from run to run so the only +conclusion that should be drawn is that all 3 frameworks perform +similarly on this task. + +However, The method invocation involves the "hidden" cost of parameter +construction. + +For example, + +.... + logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); + +.... + +incurs the cost of constructing the message parameter, i.e. converting +both integer `i` and `entry[i]` to a String, and concatenating +intermediate strings, regardless of whether the message will be logged +or not. This cost of parameter construction can be quite high and it +depends on the size of the parameters involved. A comparison run on the +same hardware as above yields: + +.... + Log4j: 188 + Logback: 183 + Log4j 2: 188 + +.... + +Again, no conclusion should be drawn regarding relative differences +between the frameworks on this task, but it should be obvious that it is +considerably more expensive than simply testing the level. + +The best approach to avoid the cost of parameter construction is to use +Log4j 2's formatting capabilities. For example, instead of the above +write: + +.... + logger.debug("Entry number: {} is {}", i, entry[i]); + +.... + +Using this approach, a comparison run again on the same hardware +produces: + +.... + Log4j: Not supported + Logback: 9 + Log4j 2: 4 + +.... + +These results show that the difference in performance between the call +to isDebugEnabled and logger.debug is barely discernible. + +In some circumstances one of the parameters to logger.debug will be a +costly method call that should be avoided if debugging is disabled. In +those cases write: + +.... + if(logger.isDebugEnabled() { + logger.debug("Entry number: " + i + " is " + entry[i].toString()); + } + +.... + +This will not incur the cost of whatever the toString() method needs to +do if debugging is disabled. On the other hand, if the logger is enabled +for the debug level, it will incur twice the cost of evaluating whether +the logger is enabled or not: once in `isDebugEnabled` and once in +`debug`. This is an insignificant overhead because evaluating a logger +takes about 1% of the time it takes to actually log. + +Certain users resort to pre-processing or compile-time techniques to +compile out all log statements. This leads to perfect performance +efficiency with respect to logging. However, since the resulting +application binary does not contain any log statements, logging cannot +be turned on for that binary. This seems to be a disproportionate price +to pay in exchange for a small performance gain. + +The performance of deciding whether to log or not to log when logging is +turned on. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Unlike Log4j, Log4j 2 Loggers don't "walk a hierarchy". Loggers point +directly to the Logger configuration that best matches the Logger's +name. This incurs extra overhead when the Logger is first created but +reduces the overhead every time the Logger is used. + +=== Actually outputting log messages + +This is the cost of formatting the log output and sending it to its +target destination. Here again, a serious effort was made to make +layouts (formatters) perform as quickly as possible. The same is true +for appenders. One of the fundamental tenets of Log4j 2 is to use +immutable objects whenever possible and to lock at the lowest +granularity possible. However, the cost of actually formatting and +delivering log events will never be insignificant. For example, the +results of writing to a simple log file using the same format using +Log4j, Logback and Log4j 2 are: + +.... + Log4j: 1651 + Logback: 1419 + Log4j 2.0: 1542 + +.... + +As with many of the other results on this page the differences between +the frameworks above should be considered insignificant. The values will +change somewhat on each execution and changing the order the frameworks +are tested or adding calls to System.gc() between the tests can cause a +variation in the reported times. However, these results show that +actually writing out the events can be at least 1000 times more +expensive than when they are disabled, so it is always recommended to +take advantage of Log4j 2's fine-grained filtering capabilities. +//// diff --git a/src/site/xdoc/performance.xml b/src/site/xdoc/performance.xml deleted file mode 100644 index ff892fad543..00000000000 --- a/src/site/xdoc/performance.xml +++ /dev/null @@ -1,469 +0,0 @@ - - - - - - Performance - Remko Popma - Ralph Goers - - - -
    - -

    Apart from functional requirements, an important reason for selecting a logging library is often how well it - fulfills non-functional requirements like reliability and performance.

    -

    This page compares the performance of a number of logging frameworks - (java.util.logging "JUL", Logback, Log4j 1.2 and Log4j 2.6), - and documents some performance trade-offs for Log4j 2 functionality. -

    - -

    Benchmarks

    -

    Performance can mean different things to different people. Common terms in this context are - throughput and latency: Throughput is a measure of capacity and can be expressed in a single number: - how many messages can be logged in a certain period of time. - Response time latency is how long it takes to log a message. - This cannot be expressed in a single number because each measurement has its own - response time and we are often most interested in the outliers: how many there were and how large they were.

    -

    When evaluating a logging framework's performance these may be useful questions to ask:

    -
    - - - -
    -
    Sidebar: Why Care About Response Time Latency?
    - - - - - -

    - What is often measured and reported as latency is actually service time, - and omits that a service time spike adds wait time for many subsequent events. - This may present results that are more optimistic than what users experience. -

    - The graph on the right illustrates how much more optimistic service time is than response time. - The graph shows response time and service time for the same system under a load of 100,000 messages - per second. Out of 24 million measurements, only ~50 are more than 250 microseconds, less than 0.001%. - In a service time-only graph this would hardly be visible. - However, the depending on the load it will take a while to catch up after a spike. -

    - The response time graph shows that in reality many more events are - impacted by these delays than the service time numbers alone would suggest. -

    -

    - To learn more, watch Gil Tene's eye-opening presentation - How NOT to measure - latency. -

    -
    -
    -
    -
    -

    Logging Library Performance Comparison

    - -
    -

    Asynchronous Logging - Peak Throughput Comparison

    -

    Asynchronous logging is useful to deal with bursts of events. How this works is that - a minimum amount of work is done by the application thread to capture all required information in a log event, - and this log event is then put on a queue for later processing by a background thread. - As long as the queue is sized large enough, the application threads should be able to spend - very little time on the logging call and return to the business logic very quickly. -

    -

    It turns out that the choice of queue is extremely important for peak throughput. - Log4j 2's Async Loggers use a - lock-free data structure, whereas - Logback, Log4j 1.2 and Log4j 2's Asynchronous Appenders use an ArrayBlockingQueue. - With a blocking queue, multi-threaded applications often experience lock contention when trying to - enqueue the log event. -

    -

    The graph below illustrates the difference a lock-free data structure can make to throughput - in multi-threaded scenarios. Log4j 2 scales better with the number of threads: - an application with more threads can log more. The other logging libraries suffer - from lock contention and total throughput stays constant or drops when more threads are logging. - This means that with the other logging libraries, each individual thread will be able to log less.

    -

    Bear in mind that this is peak throughput: Log4j 2's Async Loggers give better throughput up to a point, but - once the queue is full, the appender thread needs to wait until a slot becomes available in the queue, - and throughput will drop to the maximum sustained throughput of the underlying appenders at best. -

    -

    Peak throughput comparison -

    -

    For details, see the Async - Loggers manual page.

    - - -

    Asynchronous Logging Response Time

    -

    Response time behaviour varies a lot with the workload and the number of threads that log concurrently. - The Async Loggers manual page and the - garbage-free logging manual page - provide some graphs showing response time behaviour under various loads. -

    -

    This section shows another graph showing response time latency behaviour - under a modest total workload of 64,000 messages per second, with 4 threads logging concurrently. - At this load and on this hardware/OS/JVM configuration, lock contention and context switches play less of a role - and the pauses are mostly caused by minor garbage collections. - Garbage collection pause duration and frequency can vary a lot: when testing the Log4j 1.2.17 - Async Appender - a minor GC pause of 7 milliseconds occurred while the Log4j 2 Async Appender test only saw - a GC pause of a little over 2 milliseconds. This does not necessarily mean that one is better than the other. -

    -

    Generally, garbage-free async loggers had the best response time behaviour - in all configurations we tested.

    -

    -

    The above result was obtained with - the ResponseTimeTest class which can be found in the Log4j 2 unit test source directory, - running on JDK 1.8.0_45 on - RHEL 6.5 (Linux 2.6.32-573.1.1.el6.x86_64) with - 10-core Xeon CPU E5-2660 v3 @2.60GHz with hyperthreading switched on (20 virtual cores). -

    - -

    Asynchronous Logging Parameterized Messages

    -

    Many logging libraries offer an API for logging parameterized messages. - This enables application code to look something like this:

    -logger.debug("Entry number: {} is {}", i, entry[i]);
    - In the above example, the fully formatted message text is not created unless the DEBUG level is enabled for the logger. - Without this API, you would need three lines of code to accomplish the same: -
    -if (logger.isDebugEnabled()) {
    -    logger.debug("Entry number: " + i + " is " + entry[i].toString());
    -}
    -

    -

    If the DEBUG level is enabled, then at some point the message needs to be formatted. - When logging asynchronously, the message parameters may be changed - by the application thread before the background thread had a chance to log the message. - This would show the wrong values in the log file. - To prevent this, Log4j 2, Log4j 1.2 and Logback format the message text in the application thread - before passing off the log event to the background thread.

    -

    This is the safe thing to do, but the formatting has a performance cost. - The graph below compares the throughput of logging messages with parameters using various logging libraries. - These are all asynchronous logging calls, so these numbers do not include the cost of disk I/O - and represent peak throughput.

    -

    JUL (java.util.logging) does not have a built-in asynchronous Handler. - MemoryHandler - is the nearest thing available so we included it here. - MemoryHandler does not do the safe thing of taking a snapshot - of the current parameter state (it just keeps a reference to the original parameter objects), - and as a result it is very fast when single-threaded. - However, when more application threads are logging concurrently, the cost of lock contention outweighs this gain.

    -

    In absolute numbers, Log4j 2's Async Loggers perform well compared to the other logging - frameworks, but notice that the message formatting cost increases sharply with the number of parameters. - In this area, Log4j 2 still has work to do to improve: we would like to keep this cost more constant. -

    -

    -

    The results above are for JUL (java.util.logging) 1.8.0_45, Log4j 2.6, Log4j 1.2.17 and Logback 1.1.7, - and were obtained with the - JMH Java benchmark harness. - See the AsyncAppenderLog4j1Benchmark, AsyncAppenderLog4j2Benchmark, AsyncAppenderLogbackBenchmark, - AsyncLoggersBenchmark and the MemoryHandlerJULBenchmark source code in the log4j-perf module. -

    - - -

    Asynchronous Logging with Caller Location Information

    -

    - Some layouts can show the class, method and line number in the application where the logging call was made. - In Log4j 2, examples of such layout options are HTML - locationInfo, - or one of the patterns %C or $class, - %F or %file, - %l or %location, - %L or %line, - %M or %method. - In order to provide caller location information, the logging library - will take a snapshot of the stack, and walk the stack trace to find the location information. -

    -

    - The graph below shows the performance impact of capturing caller location information when logging - asynchronously from a single thread. Our tests show that capturing caller location has a similar impact - across all logging libraries, and slows down asynchronous - logging by about 30-100x. -

    -

    -

    The results above are for JUL (java.util.logging) 1.8.0_45, Log4j 2.6, Log4j 1.2.17 and Logback 1.1.7, - and were obtained with the - JMH Java benchmark harness. - See the AsyncAppenderLog4j1LocationBenchmark, AsyncAppenderLog4j2LocationBenchmark, - AsyncAppenderLogbackLocationBenchmark, AsyncLoggersLocationBenchmark and the - MemoryHandlerJULLocationBenchmark source code in the log4j-perf module. -

    - - -

    Synchronous File Logging - Sustained Throughput Comparison

    -

    This section discusses the maximum sustained throughput of logging to a file. - In any system, the maximum sustained throughput is determined by its slowest component. - In the case of logging, this is the appender, where the message formatting and disk I/O takes place. - For this reason we will look at simple synchronous logging to a file, - without queues or background threads.

    -

    The graph below compares Log4j 2.6's RandomAccessFile appender - to the respective File appenders of Log4j 1.2.17, Logback 1.1.7 and - Java util logging (JUL) on Oracle Java 1.8.0_45. ImmediateFlush was set to false for all - loggers that support this. The JUL results are for the XMLFormatter (which in our measurements was - about twice as fast as the SimpleFormatter).

    -

    Log4j 2's sustained throughput drops a little when more threads are logging simultaneously, - but its fine-grained locking pays off and throughput stays relatively high. - The other logging frameworks' throughput drops dramatically in multi-threaded applications: - Log4j 1.2 has 1/4th of its single-threaded capacity, - Logback has 1/10th of its single-threaded capacity, and JUL steadily drops from 1/4th to 1/10th of its - single-threaded throughput as more threads are added.

    -

    -

    The synchronous logging throughput results above are obtained with the - JMH Java benchmark harness. - See the FileAppenderBenchmark source code in the log4j-perf module.

    - -

    Synchronous File Logging - Response Time Comparison

    -

    Response time for synchronous file logging varies a lot with the workload and the - number of threads. Below is a sample for a workload of 32,000 events per second, - with 2 threads logging 16,000 events per second each.

    -

    -

    The above result was obtained with the ResponseTimeTest class which can be found in the Log4j 2 - unit test source directory, running on JDK 1.8.0_45 on RHEL 6.5 (Linux 2.6.32-573.1.1.el6.x86_64) - with 10-core Xeon CPU E5-2660 v3 @2.60GHz with hyperthreading switched on (20 virtual cores).

    - - -

    Filtering by Level

    -

    The most basic filtering a logging framework provides is filtering by log level. - When logging is turned off entirely or just for a set of Levels, the cost of a log request consists - of a number of method invocations plus an integer comparison. - Unlike Log4j, Log4j 2 Loggers don't "walk a hierarchy". - Loggers point directly to the Logger configuration that best matches the Logger's name. - This incurs extra overhead when the Logger is first created but reduces the overhead every - time the Logger is used. -

    -

    Advanced Filtering

    -

    - Both Logback and Log4j 2 support advanced filtering. Logback calls them TurboFilters while - Log4j 2 has a single Filter object. Advanced filtering provides the capability to filter - LogEvents using more than just the Level before the events are passed to Appenders. - However, this flexibility does come with some cost. - Since multi-threading can also have an impact on the - performance of advanced filtering, the chart below shows the difference in performance of filtering based - on a Marker or a Marker's parent.

    -

    - The "Simple Marker" comparison checks to see if a Marker that has no references - to other markers matches the requested Marker. The "Parent Marker" comparison checks to see - if a Marker that does have references to other markers matches the requested Marker.

    -

    It appears that coarse-grained synchronization in SLF4J can impact performance in - multi-threaded scenarios. See - SLF4J-240.

    -

    -

    Log4j and Logback also support filtering - on a value in the Log4j ThreadContext vs filtering in Logback on a value in the MDC. - The graph below shows that the performance difference between Log4j 2 and Logback - is small for the ThreadContext filter. -

    -

    The Filter comparison results above are obtained with the - JMH Java benchmark harness. - See the MarkerFilterBenchmark and MDCFilterBenchmark in the log4j-perf module for details on these - benchmarks.

    - -

    Trade-offs

    -
    -

    Which Log4j 2 Appender to Use?

    -

    Assuming that you selected Log4j 2 as your logging framework, - next you may be interested in learning what the performance trade-offs are for - selecting a specific Log4j 2 configuration. For example, there are three appenders - for logging to a file: the File, RandomAccessFile and MemoryMappedFile appenders. - Which one should you use?

    -

    If performance is all you care about, the graphs below show your best choice is either - the MemoryMappedFile appender or the RandomAccessFile appender. - Some things to bear in mind: -

    -
      -
    • MemoryMappedFile appender does not have a rolling variant yet.
    • -
    • When the log file size exceeds the MemoryMappedFile's region length, the file needs to be remapped. - This can be a very expensive operation, taking several seconds if the region is large.
    • -
    • MemoryMappedFile appender creates a presized file from the beginning and fills it up gradually. - This can confuse tools like tail; many such tools don't work very well with memory mapped files.
    • -
    • On Windows, using a tool like tail on a file created by RandomAccessFile appender - can hold a lock on this file which may prevent Log4j from opening the file again when the - application is restarted. In a development environment where you expect to restart your application - regularly while using tools like tail to view the log file contents, the File appender may be - a reasonable trade-off between performance and flexibility. For production environments - performance may have higher priority.
    • -
    -

    - The graph below shows sustained throughput for the console and file appenders in Log4j 2.6, - and for reference also provides the 2.5 performance.

    -

    It turns out that the garbage-free text encoding logic in 2.6 gives - these appenders a performance boost compared to Log4j 2.5. - It used to be that the RandomAccessFile appender was significantly faster, - especially in multi-threaded scenarios, but with the 2.6 release the File appender - performance has improved and the performance difference between these two appender is smaller.

    -

    Another takeaway is just how much of a performance drag logging to the console can be. - Considering logging to a file and using a tool like tail to watch the file change in real time.

    -

    -

    On Windows, the results are similar but the RandomAccessFile and MemoryMappedFile appenders outperform - the plain File appender in multi-threaded scenarios. - The absolute numbers are higher on Windows: we don't know why but it looks like Windows - handles lock contention better than Linux.

    -

    -

    The Log4j 2 appender comparison results above are obtained with the - JMH Java benchmark harness. - See the Log4j2AppenderComparisonBenchmark source code in the log4j-perf module.

    - - -
    - -
    From 079f09ef12d1f39e001b3f0e451d4d2800261d9f Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 13:18:02 -0500 Subject: [PATCH 0142/2347] Add 90 minute timeout to jenkins pipeline --- Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index da86e52dea7..a9e29d66a72 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,6 +17,9 @@ */ pipeline { + options { + timeout time: 90, unit: 'MINUTES' + } agent none stages { stage('Build') { From bc28fdacc4e804fdb9b3b8aa79c9086392a5b965 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 13:22:10 -0500 Subject: [PATCH 0143/2347] Specify jenkins windows file encoding as utf-8 for consistency with ubuntu build --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index a9e29d66a72..09123a57343 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -48,7 +48,7 @@ pipeline { maven 'Maven 3 (latest)' } steps { - bat 'mvn -t toolchains-jenkins-win.xml -V install' + bat 'mvn -t toolchains-jenkins-win.xml -V -Dfile.encoding=UTF-8 install' } } } From 49442e47fb4d1d82d60d90940cfe3db0294f268a Mon Sep 17 00:00:00 2001 From: Gary Gregory Date: Sat, 7 Apr 2018 12:27:43 -0600 Subject: [PATCH 0144/2347] [LOG4J2-2289] XML Schema for DynamicFilterThreshold does not accept multiple KeyValuePairs. --- src/changes/changes.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d7ca266d0e5..50d8a38125a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -330,6 +330,9 @@ + + XML Schema for DynamicFilterThreshold does not accept multiple KeyValuePairs. + Properly escape newlines and other control characters in JSON. From 967ebdad81c522ccde808acf2c6889c18003eed0 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 13:49:26 -0500 Subject: [PATCH 0145/2347] LOG4J2-1802: Convert architecture page to asciidoc --- src/site/asciidoc/manual/architecture.adoc | 474 +++++++++++++ src/site/xdoc/manual/architecture.xml | 737 --------------------- 2 files changed, 474 insertions(+), 737 deletions(-) create mode 100644 src/site/asciidoc/manual/architecture.adoc delete mode 100644 src/site/xdoc/manual/architecture.xml diff --git a/src/site/asciidoc/manual/architecture.adoc b/src/site/asciidoc/manual/architecture.adoc new file mode 100644 index 00000000000..73fa6e1d4ae --- /dev/null +++ b/src/site/asciidoc/manual/architecture.adoc @@ -0,0 +1,474 @@ +//// + 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 + + https://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. +//// += Architecture +Ralph Goers + +== Main Components + +Log4j uses the classes shown in the diagram below. + +image:../images/Log4jClasses.jpg[Log4j 2 Class Relationships,title="Log4j 2 Class Relationships"] + +Applications using the Log4j 2 API will request a Logger with a specific +name from the LogManager. The LogManager will locate the appropriate +LoggerContext and then obtain the Logger from it. If the Logger must be +created it will be associated with the LoggerConfig that contains either +a) the same name as the Logger, b) the name of a parent package, or c) +the root LoggerConfig. LoggerConfig objects are created from Logger +declarations in the configuration. The LoggerConfig is associated with +the Appenders that actually deliver the LogEvents. + +=== Logger Hierarchy + +The first and foremost advantage of any logging API over plain +`System.out.println` resides in its ability to disable certain log +statements while allowing others to print unhindered. This capability +assumes that the logging space, that is, the space of all possible +logging statements, is categorized according to some developer-chosen +criteria. + +In Log4j 1.x the Logger Hierarchy was maintained through a relationship +between Loggers. In Log4j 2 this relationship no longer exists. Instead, +the hierarchy is maintained in the relationship between LoggerConfig +objects. + +Loggers and LoggerConfigs are named entities. Logger names are +case-sensitive and they follow the hierarchical naming rule: + +Named Hierarchy:: +A LoggerConfig is said to be an _ancestor_ of another LoggerConfig if +its name followed by a dot is a prefix of the _descendant_ logger +name. A LoggerConfig is said to be a _parent_ of a _child_ +LoggerConfig if there are no ancestors between itself and the +descendant LoggerConfig. + +For example, the LoggerConfig named `"com.foo"` is a parent of the +LoggerConfig named`"com.foo.Bar"`. Similarly, `"java"` is a parent of +`"java.util"` and an ancestor of `"java.util.Vector"`. This naming +scheme should be familiar to most developers. + +The root LoggerConfig resides at the top of the LoggerConfig hierarchy. +It is exceptional in that it always exists and it is part of every +hierarchy. A Logger that is directly linked to the root LoggerConfig can +be obtained as follows: + +[source,java] +---- +Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME); +---- + +Alternatively, and more simply: + +[source,java] +---- +Logger logger = LogManager.getRootLogger(); +---- + +All other Loggers can be retrieved using the +link:../log4j-api/apidocs/org/apache/logging/log4j/LogManager.html#getLogger(java.lang.String)[`LogManager.getLogger`] +static method by passing the name of the desired Logger. Further +information on the Logging API can be found in the +link:../log4j-api/api.html[Log4j 2 API]. + +=== LoggerContext + +The +link:../log4j-core/apidocs/org/apache/logging/log4j/core/LoggerContext.html[`LoggerContext`] +acts as the anchor point for the Logging system. However, it is possible +to have multiple active LoggerContexts in an application depending on +the circumstances. More details on the LoggerContext are in the +link:logsep.html[Log Separation] section. + +=== Configuration + +Every LoggerContext has an active +link:../log4j-core/apidocs/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`]. +The Configuration contains all the Appenders, context-wide Filters, +LoggerConfigs and contains the reference to the StrSubstitutor. During +reconfiguration two Configuration objects will exist. Once all Loggers +have been redirected to the new Configuration, the old Configuration +will be stopped and discarded. + +=== Logger + +As stated previously, Loggers are created by calling +link:../log4j-api/apidocs/org/apache/logging/log4j/LogManager.html#getLogger(java.lang.String)[`LogManager.getLogger`]. +The Logger itself performs no direct actions. It simply has a name and +is associated with a LoggerConfig. It extends +link:../log4j-api/apidocs/org/apache/logging/log4j/spi/AbstractLogger.html[`AbstractLogger`] +and implements the required methods. As the configuration is modified +Loggers may become associated with a different LoggerConfig, thus +causing their behavior to be modified. + +Retrieving Loggers + +Calling the `LogManager.getLogger` method with the same name will always +return a reference to the exact same Logger object. + +For example, in + +[source,java] +---- +Logger x = LogManager.getLogger("wombat"); +Logger y = LogManager.getLogger("wombat"); +---- + +`x` and `y` refer to _exactly_ the same Logger object. + +Configuration of the log4j environment is typically done at application +initialization. The preferred way is by reading a configuration file. +This is discussed in link:configuration.html[Configuration]. + +Log4j makes it easy to name Loggers by _software component_. This can be +accomplished by instantiating a Logger in each class, with the logger +name equal to the fully qualified name of the class. This is a useful +and straightforward method of defining loggers. As the log output bears +the name of the generating Logger, this naming strategy makes it easy to +identify the origin of a log message. However, this is only one +possible, albeit common, strategy for naming loggers. Log4j does not +restrict the possible set of loggers. The developer is free to name the +loggers as desired. + +Since naming Loggers after their owning class is such a common idiom, +the convenience method `LogManager.getLogger()` is provided to +automatically use the calling class's fully qualified class name as the +Logger name. + +Nevertheless, naming loggers after the class where they are located +seems to be the best strategy known so far. + +=== LoggerConfig + +link:../log4j-core/apidocs/org/apache/logging/log4j/core/config/LoggerConfig.html[`LoggerConfig`] +objects are created when Loggers are declared in the logging +configuration. The LoggerConfig contains a set of Filters that must +allow the LogEvent to pass before it will be passed to any Appenders. It +contains references to the set of Appenders that should be used to +process the event. + +==== Log Levels + +LoggerConfigs will be assigned a Log +link:../log4j-api/apidocs/org/apache/logging/log4j/Level.html[`Level`]. +The set of built-in levels includes TRACE, DEBUG, INFO, WARN, ERROR, and +FATAL. Log4j 2 also supports link:customloglevels.html[custom log +levels]. Another mechanism for getting more granularity is to use +link:../log4j-api/api.html#Markers[Markers] instead. + +http://logging.apache.org/log4j/1.2/manual.html[Log4j 1.x] and +http://logback.qos.ch/manual/architecture.html#effectiveLevel[Logback] +both have the concept of "Level Inheritance". In Log4j 2, Loggers and +LoggerConfigs are two different objects so this concept is implemented +differently. Each Logger references the appropriate LoggerConfig which +in turn can reference its parent, thus achieving the same effect. + +Below are five tables with various assigned level values and the +resulting levels that will be associated with each Logger. Note that in +all these cases if the root LoggerConfig is not configured a default +Level will be assigned to it. + +.Example 1 +[cols=",,,",options="header",] +|==================================================================== +|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Logger Level +|root |root |DEBUG |DEBUG +|X |root |DEBUG |DEBUG +|X.Y |root |DEBUG |DEBUG +|X.Y.Z |root |DEBUG |DEBUG +|==================================================================== + +In example 1 above, only the root logger is configured and has a Log +Level. All the other Loggers reference the root LoggerConfig and use its +Level. + +.Example 2 +[cols=",,,",options="header",] +|============================================================= +|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level +|root |root |DEBUG |DEBUG +|X |X |ERROR |ERROR +|X.Y |X.Y |INFO |INFO +|X.Y.Z |X.Y.Z |WARN |WARN +|============================================================= + +In example 2, all loggers have a configured LoggerConfig and obtain +their Level from it. + +.Example 3 +[cols=",,,",options="header",] +|============================================================= +|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level +|root |root |DEBUG |DEBUG +|X |X |ERROR |ERROR +|X.Y |X |ERROR |ERROR +|X.Y.Z |X.Y.Z |WARN |WARN +|============================================================= + +In example 3, the loggers`root`, `X` and `X.Y.Z` each have a configured +LoggerConfig with the same name. The Logger `X.Y` does not have a +configured LoggerConfig with a matching name so uses the configuration +of LoggerConfig `X` since that is the LoggerConfig whose name has the +longest match to the start of the Logger's name. + +.Example 4 +[cols=",,,",options="header",] +|============================================================= +|Logger Name |Assigned LoggerConfig |LoggerConfig Level |level +|root |root |DEBUG |DEBUG +|X |X |ERROR |ERROR +|X.Y |X |ERROR |ERROR +|X.Y.Z |X |ERROR |ERROR +|============================================================= + +In example 4, the loggers `root` and `X` each have a Configured +LoggerConfig with the same name. The loggers `X.Y` and `X.Y.Z` do not +have configured LoggerConfigs and so get their Level from the +LoggerConfig assigned to them,`X`, since it is the LoggerConfig whose +name has the longest match to the start of the Logger's name. + +.Example 5 +[cols=",,,",options="header",] +|============================================================= +|Logger Name |Assigned LoggerConfig |LoggerConfig Level |level +|root |root |DEBUG |DEBUG +|X |X |ERROR |ERROR +|X.Y |X.Y |INFO |INFO +|X.YZ |X |ERROR |ERROR +|============================================================= + +In example 5, the loggers`root`.`X`, and `X.Y` each have a Configured +LoggerConfig with the same name. The logger `X.YZ` does not have +configured LoggerConfig and so gets its Level from the LoggerConfig +assigned to it,`X`, since it is the LoggerConfig whose name has the +longest match to the start of the Logger's name. It is not associated +with LoggerConfig `X.Y` since tokens after periods must match exactly. + +.Example 6 +[cols=4*,options="header"] +|=== +|Logger Name |Assigned LoggerConfig |LoggerConfig Level |Level +|root |root |DEBUG |DEBUG +|X |X |ERROR |ERROR +|X.Y |X.Y | |ERROR +|X.Y.Z |X.Y | |ERROR +|=== + +In example 6, LoggerConfig X.Y it has no configured level so it inherits +its level from LoggerConfig X. Logger X.Y.Z uses LoggerConfig X.Y since +it doesn't have a LoggerConfig with a name that exactly matches. It too +inherits its logging level from LoggerConfig X. + +The table below illustrates how Level filtering works. In the table, the +vertical header shows the Level of the LogEvent, while the horizontal +header shows the Level associated with the appropriate LoggerConfig. The +intersection identifies whether the LogEvent would be allowed to pass +for further processing (Yes) or discarded (No). + +[cols=8*,options="header"] +|=== +|Event Level +7+|LoggerConfig Level + +|  |`TRACE` |`DEBUG` |`INFO` |`WARN` |`ERROR` |`FATAL` |`OFF` + +|`ALL` |✅ |✅ |✅ |✅ |✅ |✅ |⌠+ +|`TRACE` |✅ |⌠|⌠|⌠|⌠|⌠|⌠+ +|`DEBUG` |✅ |✅ |⌠|⌠|⌠|⌠|⌠+ +|`INFO` |✅ |✅ |✅ |⌠|⌠|⌠|⌠+ +|`WARN` |✅ |✅ |✅ |✅ |⌠|⌠|⌠+ +|`ERROR` |✅ |✅ |✅ |✅ |✅ |⌠|⌠+ +|`FATAL` |✅ |✅ |✅ |✅ |✅ |✅ |⌠+ +|`OFF` |⌠|⌠|⌠|⌠|⌠|⌠|⌠+|=== + +=== Filter + +In addition to the automatic log Level filtering that takes place as +described in the previous section, Log4j provides +link:../log4j-core/apidocs/org/apache/logging/log4j/core/Filter.html[`Filter`]s +that can be applied before control is passed to any LoggerConfig, after +control is passed to a LoggerConfig but before calling any Appenders, +after control is passed to a LoggerConfig but before calling a specific +Appender, and on each Appender. In a manner very similar to firewall +filters, each Filter can return one of three results, `Accept`, `Deny` +or `Neutral`. A response of `Accept` means that no other Filters should +be called and the event should progress. A response of `Deny` means the +event should be immediately ignored and control should be returned to +the caller. A response of `Neutral` indicates the event should be passed +to other Filters. If there are no other Filters the event will be +processed. + +Although an event may be accepted by a Filter the event still might not +be logged. This can happen when the event is accepted by the +pre-LoggerConfig Filter but is then denied by a LoggerConfig filter or +is denied by all Appenders. + +=== Appender + +The ability to selectively enable or disable logging requests based on +their logger is only part of the picture. Log4j allows logging requests +to print to multiple destinations. In log4j speak, an output destination +is called an +link:../log4j-core/apidocs/org/apache/logging/log4j/core/Appender.html[`Appender`]. +Currently, appenders exist for the console, files, remote socket +servers, Apache Flume, JMS, remote UNIX Syslog daemons, and various +database APIs. See the section on link:appenders.html[Appenders] for +more details on the various types available. More than one Appender can +be attached to a Logger. + +An Appender can be added to a Logger by calling the +link:../log4j-core/apidocs/org/apache/logging/log4j/core/config/Configuration.html#addLoggerAppender(org.apache.logging.log4j.core.Logger,%20org.apache.logging.log4j.core.Appender)[`addLoggerAppender`] +method of the current Configuration. If a LoggerConfig matching the name +of the Logger does not exist, one will be created, the Appender will be +attached to it and then all Loggers will be notified to update their +LoggerConfig references. + +*Each enabled logging request for a given logger will be forwarded to +all the appenders in that Logger's LoggerConfig as well as the Appenders +of the LoggerConfig's parents.* In other words, Appenders are inherited +additively from the LoggerConfig hierarchy. For example, if a console +appender is added to the root logger, then all enabled logging requests +will at least print on the console. If in addition a file appender is +added to a LoggerConfig, say _C_, then enabled logging requests for _C_ +and _C_'s children will print in a file _and_ on the console. It is +possible to override this default behavior so that Appender accumulation +is no longer additive by setting `additivity="false"` on the Logger +declaration in the configuration file. + +The rules governing appender additivity are summarized below. + +Appender Additivity:: +The output of a log statement of Logger _L_ will go to all the +Appenders in the LoggerConfig associated with _L_ and the ancestors of +that LoggerConfig. This is the meaning of the term "appender +additivity". ++ +However, if an ancestor of the LoggerConfig associated with Logger +_L_, say _P_, has the additivity flag set to `false`, then _L_'s +output will be directed to all the appenders in _L_'s LoggerConfig and +it's ancestors up to and including _P_ but not the Appenders in any of +the ancestors of _P_. ++ +Loggers have their additivity flag set to `true` by default. + +The table below shows an example: + +|=== +|Logger Name |Added Appenders |Additivity Flag |Output Targets |Comment + +|root +|A1 +|not applicable +|A1 +|The root logger has no parent so additivity does not apply to it. + +|x +|A-x1, A-x2 +|true +|A1, A-x1, A-x2 +|Appenders of "x" and root. + +|x.y +|none +|true +|A1, A-x1, A-x2 +|Appenders of "x" and root. It would not be typical to configure a Logger with no Appenders. + +|x.y.z +|A-xyz1 +|true +|A1, A-x1, A-x2, A-xyz1 +|Appenders in "x.y.z", "x" and root. + +|security +|A-sec +|false +|A-sec +|No appender accumulation since the additivity flag is set to `false`. + +|security.access +|none +|true +|A-sec +|Only appenders of "security" because the additivity flag in "security" is set to `false`. +|=== + +=== Layout + +More often than not, users wish to customize not only the output +destination but also the output format. This is accomplished by +associating a +link:../log4j-core/apidocs/org/apache/logging/log4j/core/Layout.html[`Layout`] +with an Appender. The Layout is responsible for formatting the LogEvent +according to the user's wishes, whereas an appender takes care of +sending the formatted output to its destination. The +link:../log4j-core/apidocs/org/apache/logging/log4j/core/layout/PatternLayout.html[`PatternLayout`], +part of the standard log4j distribution, lets the user specify the +output format according to conversion patterns similar to the C language +`printf` function. + +For example, the PatternLayout with the conversion pattern "%r [%t] %-5p +%c - %m%n" will output something akin to: + +.... +176 [main] INFO org.foo.Bar - Located nearest gas station. +.... + +The first field is the number of milliseconds elapsed since the start of +the program. The second field is the thread making the log request. The +third field is the level of the log statement. The fourth field is the +name of the logger associated with the log request. The text after the +'-' is the message of the statement. + +Log4j comes with many different link:layouts.html[Layouts] for various +use cases such as JSON, XML, HTML, and Syslog (including the new RFC +5424 version). Other appenders such as the database connectors fill in +specified fields instead of a particular textual layout. + +Just as importantly, log4j will render the content of the log message +according to user specified criteria. For example, if you frequently +need to log `Oranges`, an object type used in your current project, then +you can create an OrangeMessage that accepts an Orange instance and pass +that to Log4j so that the Orange object can be formatted into an +appropriate byte array when required. + +=== StrSubstitutor and StrLookup + +The +link:../log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor.html[`StrSubstitutor`] +class and +link:../log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrLookup.html[`StrLookup`] +interface were borrowed from +https://commons.apache.org/proper/commons-lang/[Apache Commons Lang] and +then modified to support evaluating LogEvents. In addition the +link:../log4j-core/apidocs/org/apache/logging/log4j/core/lookup/Interpolator.html[`Interpolator`] +class was borrowed from Apache Commons Configuration to allow the +StrSubstitutor to evaluate variables that from multiple StrLookups. It +too was modified to support evaluating LogEvents. Together these provide +a mechanism to allow the configuration to reference variables coming +from System Properties, the configuration file, the ThreadContext Map, +StructuredData in the LogEvent. The variables can either be resolved +when the configuration is processed or as each event is processed, if +the component is capable of handling it. See link:lookups.html[Lookups] +for more information. diff --git a/src/site/xdoc/manual/architecture.xml b/src/site/xdoc/manual/architecture.xml deleted file mode 100644 index 524e031a5f3..00000000000 --- a/src/site/xdoc/manual/architecture.xml +++ /dev/null @@ -1,737 +0,0 @@ - - - - - - Log4j 2 Architecture - Ralph Goers - - - -
    - -

    Log4j uses the classes shown in the diagram below.

    - Log4j 2 Class Relationships -

    Applications using the Log4j 2 API will request a Logger with a specific name from the - LogManager. The LogManager will locate the appropriate LoggerContext and then obtain the Logger from it. - If the Logger must be created it will be associated with the LoggerConfig that contains either a) the - same name as the Logger, b) the name of a parent package, or c) the root LoggerConfig. LoggerConfig - objects are created from Logger declarations in the configuration. The LoggerConfig is associated with - the Appenders that actually deliver the LogEvents. -

    -

    Logger Hierarchy

    -

    The first and foremost advantage of any logging API over plain - System.out.println - resides in its ability to disable - certain log statements while allowing others to print unhindered. This - capability assumes that the logging space, that is, the space of all - possible logging statements, is categorized according to some - developer-chosen criteria. -

    -

    In Log4j 1.x the Logger Hierarchy was maintained through a relationship between Loggers. - In Log4j 2 this relationship no longer exists. Instead, the hierarchy is maintained - in the relationship between LoggerConfig objects. -

    - -

    Loggers and LoggerConfigs are named entities. Logger names are case-sensitive and - they follow the hierarchical naming rule: -

    - -
    -
    -
    Named Hierarchy
    -
    - A LoggerConfig is said to be an ancestor of another LoggerConfig if its name followed by a dot - is a prefix of the descendant logger name. A LoggerConfig is said to be a parent of a - child LoggerConfig if there are no ancestors between itself and the descendant LoggerConfig. -
    -
    -
    - -

    For example, the LoggerConfig named - "com.foo" - is a parent - of the LoggerConfig named"com.foo.Bar". Similarly, - "java" - is a parent of - "java.util" - and an - ancestor of "java.util.Vector". This naming scheme - should be familiar to most developers. -

    - -

    The root LoggerConfig resides at the top of the LoggerConfig hierarchy. It - is exceptional in that it always exists and it is part of every hierarchy. A Logger - that is directly linked to the root LoggerConfig can be obtained as follows: -

    -
    Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    -

    - Alternatively, and more simply: -

    -
    Logger logger = LogManager.getRootLogger();
    -

    - All other Loggers can be retrieved using the - - LogManager.getLogger - - static method by passing the name of the desired Logger. Further information on the Logging - API can be found in the Log4j 2 API. -

    -

    LoggerContext

    -

    - The - LoggerContext - acts as the anchor point for the Logging system. However, it is possible to have multiple active - LoggerContexts in an application depending on the circumstances. - More details on the LoggerContext are in the Log Separation section. -

    -

    Configuration

    -

    Every LoggerContext has an active - - Configuration. - The Configuration contains all the Appenders, - context-wide Filters, LoggerConfigs and contains the reference to the StrSubstitutor. During - reconfiguration two Configuration objects will exist. Once all Loggers have been redirected to - the new Configuration, the old Configuration will be stopped and discarded. -

    -

    Logger

    -

    As stated previously, Loggers are created by calling - LogManager.getLogger. - The Logger itself performs no direct actions. It simply has a name and is associated with a LoggerConfig. - It extends - - AbstractLogger - - and implements the required methods. As the configuration is modified Loggers may become associated - with a different LoggerConfig, thus causing their behavior to be modified. -

    -
    Retrieving Loggers
    -

    - Calling the LogManager.getLogger method with the same name will always return a reference to the - exact same Logger object. -

    - -

    For example, in -

    -
    -Logger x = LogManager.getLogger("wombat");
    -Logger y = LogManager.getLogger("wombat");
    -
    -

    - x and y refer to exactly the same Logger object. -

    - -

    Configuration of the log4j environment is typically done at - application initialization. The preferred way is by reading a - configuration file. This is discussed in Configuration. -

    - -

    Log4j makes it easy to name Loggers by software component. This can be accomplished - by instantiating a Logger in each class, with the logger name equal to the fully - qualified name of the class. This is a useful and straightforward - method of defining loggers. As the log output bears the name of the - generating Logger, this naming strategy makes it easy to identify - the origin of a log message. However, this is only one possible, - albeit common, strategy for naming loggers. Log4j does not restrict - the possible set of loggers. The developer is free to name the - loggers as desired. -

    - -

    Since naming Loggers after their owning class is such a common idiom, the convenience method - LogManager.getLogger() is provided to automatically use the calling class's fully - qualified class name as the Logger name. -

    - -

    Nevertheless, naming loggers after the class where they are - located seems to be the best strategy known so far. -

    -

    LoggerConfig

    -

    - LoggerConfig - objects are created when Loggers are declared in the logging configuration. - The LoggerConfig contains a set of Filters that must allow the LogEvent to pass before it will be - passed to any Appenders. It contains references to the set of Appenders that should be used to - process the event. -

    -
    Log Levels
    -

    LoggerConfigs will be assigned a Log - Level. The set of built-in - levels includes TRACE, DEBUG, INFO, WARN, ERROR, and FATAL. Log4j 2 also supports - custom log levels. - Another mechanism for getting more granularity is to use - Markers instead. -

    -

    - Log4j 1.x - and - Logback - both have the concept of "Level Inheritance". In Log4j 2, Loggers and LoggerConfigs are two different - objects so this concept is implemented differently. Each Logger references the - appropriate LoggerConfig which in turn can reference its parent, thus achieving the same effect. -

    -

    Below are five tables with various assigned level values and the resulting levels that - will be associated with each Logger. Note that in all these cases if the root LoggerConfig - is not configured a default Level will be assigned to it. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Example 1
    Logger NameAssigned LoggerConfigLoggerConfig LevelLogger Level
    rootrootDEBUGDEBUG
    XrootDEBUGDEBUG
    X.YrootDEBUGDEBUG
    X.Y.ZrootDEBUGDEBUG
    - -

    In example 1 above, only the root logger is configured and has a Log Level. All the other - Loggers reference the root LoggerConfig and use its Level. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Example 2
    Logger NameAssigned LoggerConfigLoggerConfig LevelLevel
    rootrootDEBUGDEBUG
    XXERRORERROR
    X.YX.YINFOINFO
    X.Y.ZX.Y.ZWARNWARN
    - -

    In example 2, all loggers have a configured LoggerConfig and obtain their Level - from it. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Example 3
    Logger NameAssigned LoggerConfigLoggerConfig LevelLevel
    rootrootDEBUGDEBUG
    XXERRORERROR
    X.YXERRORERROR
    X.Y.ZX.Y.ZWARNWARN
    - -

    In example 3, the loggersroot, - X - and - X.Y.Z - each have a configured LoggerConfig with the same name. The Logger - X.Y - does not have a configured LoggerConfig with a matching name so uses - the configuration of LoggerConfig - X - since that is the LoggerConfig whose - name has the longest match to the start of the Logger's name. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Example 4
    Logger NameAssigned LoggerConfigLoggerConfig Levellevel
    rootrootDEBUGDEBUG
    XXERRORERROR
    X.YXERRORERROR
    X.Y.ZXERRORERROR
    - -

    In example 4, the loggers - root - and - X - each have a Configured - LoggerConfig with the same name. The loggers - X.Y - and - X.Y.Z - do not have configured LoggerConfigs and so get their Level from the LoggerConfig - assigned to them,X, since it is the LoggerConfig whose name has the - longest match to the start of the Logger's name. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Example 5
    Logger NameAssigned LoggerConfigLoggerConfig Levellevel
    rootrootDEBUGDEBUG
    XXERRORERROR
    X.YX.YINFOINFO
    X.YZXERRORERROR
    - -

    In example 5, the loggersroot.X, and - X.Y - each - have a Configured LoggerConfig with the same name. The logger - X.YZ - does not have configured LoggerConfig and so gets its Level from the LoggerConfig - assigned to it,X, since it is the LoggerConfig whose name has the - longest match to the start of the Logger's name. It is not associated with LoggerConfig - X.Y - since tokens after periods must match exactly. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Example 6
    Logger NameAssigned LoggerConfigLoggerConfig LevelLevel
    rootrootDEBUGDEBUG
    XXERRORERROR
    X.YX.YERROR
    X.Y.ZX.YERROR
    - -

    In example 6, LoggerConfig X.Y it has no configured level so it inherits its level - from LoggerConfig X. Logger X.Y.Z uses LoggerConfig X.Y since it doesn't have a LoggerConfig with - a name that exactly matches. It too inherits its logging level from LoggerConfig X. -

    - -

    The table below illustrates how Level filtering works. In the table, the vertical - header shows the Level of the LogEvent, while the horizontal header shows the Level associated - with the appropriate LoggerConfig. The intersection identifies whether the LogEvent would - be allowed to pass for further processing (Yes) or discarded (No). -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Event LevelLoggerConfig Level
     TRACEDEBUGINFOWARNERRORFATALOFF
    ALLYESYESYESYESYESYESNO
    TRACEYESNONONONONONO
    DEBUGYESYESNONONONONO
    INFOYESYESYESNONONONO
    WARNYESYESYESYESNONONO
    ERRORYESYESYESYESYESNONO
    FATALYESYESYESYESYESYESNO
    OFFNONONONONONONO
    - -

    Filter

    -

    In addition to the automatic log Level filtering that takes place as described in the previous - section, Log4j provides - Filters that can - be applied before control is passed to any LoggerConfig, after control is passed to a LoggerConfig - but before calling any Appenders, after control is passed to a LoggerConfig but before calling a - specific Appender, and on each Appender. In a manner very similar to firewall filters, - each Filter can return one of three results, Accept, Deny or Neutral. - A response of Accept means that no other Filters should be called and the event should progress. - A response of Deny means the event should be immediately ignored and control should be returned - to the caller. A response of Neutral indicates the event should be passed to other Filters. If - there are no other Filters the event will be processed. -

    -

    Although an event may be accepted by a Filter the event still might not be logged. This can happen - when the event is accepted by the pre-LoggerConfig Filter but is then denied by a LoggerConfig - filter or is denied by all Appenders. -

    - -

    Appender

    - -

    The ability to selectively enable or disable logging requests based - on their logger is only part of the picture. Log4j allows logging - requests to print to multiple destinations. In log4j speak, an output - destination is called an - Appender. - Currently, appenders exist for the console, files, remote socket servers, Apache Flume, - JMS, remote UNIX Syslog daemons, and various database APIs. See the section on - Appenders for more details on the various types available. - More than one Appender can be attached to a Logger. -

    -

    An Appender can be added to a Logger by calling the - addLoggerAppender - method of the current Configuration. If a LoggerConfig matching the name of the Logger does - not exist, one will be created, the Appender will be attached to it and then all Loggers - will be notified to update their LoggerConfig references. -

    -

    Each enabled logging request for a given logger will be forwarded to all the appenders in - that Logger's LoggerConfig as well as the Appenders of the LoggerConfig's parents. In - other words, Appenders are inherited additively from the LoggerConfig hierarchy. For example, - if a console appender is added to the root logger, then all enabled logging requests will at - least print on the console. If in addition a file appender is added to a LoggerConfig, say - C, then enabled logging requests for C and C's children will print - in a file and on the console. It is possible to override this default behavior so that - Appender accumulation is no longer additive by setting additivity="false" on the - Logger declaration in the configuration file. -

    -

    The rules governing appender additivity are summarized below.

    - -
    -
    -
    Appender Additivity
    -
    -

    - The output of a log statement of Logger L will go to all the Appenders in the LoggerConfig - associated with L and the ancestors of that LoggerConfig. This is the meaning of the term - "appender additivity". -

    -

    - However, if an ancestor of the LoggerConfig associated with Logger L, say P, has the - additivity flag set to false, then L's output will be directed to all the - appenders in L's LoggerConfig and it's ancestors up to and including P but not the - Appenders in any of the ancestors of P. -

    -

    Loggers have their additivity flag set to true by default.

    -
    -
    -
    - -

    The table below shows an example:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Logger
    Name
    Added
    Appenders
    Additivity
    Flag
    Output TargetsComment
    rootA1not applicableA1The root logger has no parent so additivity does not apply to it.
    xA-x1, A-x2true A1, A-x1, A-x2Appenders of "x" and root.
    x.ynonetrue A1, A-x1, A-x2Appenders of "x" and root. It would not be typical to configure a Logger with no Appenders.
    x.y.zA-xyz1true A1, A-x1, A-x2, A-xyz1Appenders in "x.y.z", "x" and root.
    securityA-secfalseA-secNo appender accumulation since the additivity flag is set to false.
    security.accessnonetrueA-secOnly appenders of "security" because the additivity flag in "security" is - set to false. -
    - -

    Layout

    -

    More often than not, users wish to customize not only the output destination but also the output format. - This is accomplished by associating a - Layout - with an Appender. The Layout is responsible for formatting the LogEvent according to the user's - wishes, whereas an appender takes care of sending the formatted output to its destination. - The PatternLayout, - part of the standard log4j distribution, lets the user specify the output - format according to conversion patterns similar to the C language printf function. -

    - -

    For example, the PatternLayout with the conversion pattern "%r [%t] - %-5p %c - %m%n" will output something akin to: -

    -
    176 [main] INFO  org.foo.Bar - Located nearest gas station.
    - -

    The first field is the number of milliseconds elapsed since the - start of the program. The second field is the thread making the log - request. The third field is the level of the log statement. The - fourth field is the name of the logger associated with the log - request. The text after the '-' is the message of the statement. -

    - -

    Log4j comes with many different Layouts for various use cases such as - JSON, XML, HTML, and Syslog (including the new RFC 5424 version). Other appenders such as the - database connectors fill in specified fields instead of a particular textual layout. -

    - -

    Just as importantly, log4j will render the content of the log - message according to user specified criteria. For example, if you - frequently need to log Oranges, an object type used in - your current project, then you can create an OrangeMessage that accepts an - Orange instance and pass that to Log4j so that the Orange object can - be formatted into an appropriate byte array when required. -

    - -

    StrSubstitutor and StrLookup

    -

    The - - StrSubstitutor - - class and - StrLookup - interface were borrowed from - Apache Commons Lang and then modified - to support evaluating LogEvents. In addition the - Interpolator - class was borrowed from Apache Commons Configuration to allow the StrSubstitutor to evaluate variables - that from multiple StrLookups. It too was modified to support evaluating LogEvents. Together these - provide a mechanism to allow the configuration to reference variables coming from System Properties, - the configuration file, the ThreadContext Map, StructuredData in the LogEvent. The variables can - either be resolved when the configuration is processed or as each event is processed, if the component - is capable of handling it. See - Lookups - for more information. -

    - -
    - -
    - -
    From 3da773ad838909c05f8294a9cceed95f631045f4 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 14:49:58 -0500 Subject: [PATCH 0146/2347] Switch to highlight.js for syntax highlighting --- src/site/resources/css/github.css | 99 +++++++++++++++++++++++++ src/site/resources/css/site.css | 28 ------- src/site/resources/js/highlight.pack.js | 2 + src/site/resources/js/site.js | 44 ----------- src/site/site.vm | 4 +- 5 files changed, 104 insertions(+), 73 deletions(-) create mode 100644 src/site/resources/css/github.css create mode 100644 src/site/resources/js/highlight.pack.js diff --git a/src/site/resources/css/github.css b/src/site/resources/css/github.css new file mode 100644 index 00000000000..86d4897bb2c --- /dev/null +++ b/src/site/resources/css/github.css @@ -0,0 +1,99 @@ +/* + +github.com style (c) Vasily Polovnyov + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + background: #f5f5f5; +} + +.hljs-comment, +.hljs-quote { + color: #998; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-subst { + color: #333; + font-weight: bold; +} + +.hljs-number, +.hljs-literal, +.hljs-variable, +.hljs-template-variable, +.hljs-tag .hljs-attr { + color: #008080; +} + +.hljs-string, +.hljs-doctag { + color: #d14; +} + +.hljs-title, +.hljs-section, +.hljs-selector-id { + color: #900; + font-weight: bold; +} + +.hljs-subst { + font-weight: normal; +} + +.hljs-type, +.hljs-class .hljs-title { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-name, +.hljs-attribute { + color: #000080; + font-weight: normal; +} + +.hljs-regexp, +.hljs-link { + color: #009926; +} + +.hljs-symbol, +.hljs-bullet { + color: #990073; +} + +.hljs-built_in, +.hljs-builtin-name { + color: #0086b3; +} + +.hljs-meta { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/src/site/resources/css/site.css b/src/site/resources/css/site.css index fbe21fc9025..5a37173e9d6 100644 --- a/src/site/resources/css/site.css +++ b/src/site/resources/css/site.css @@ -67,37 +67,9 @@ dt { margin: 15px 0 5px 0; font-size: 1.2em } .table-not-wide { width: inherit;} .alert-heading { display: block; font-size: 14px; margin-bottom: 6px; font-weight: bold; } -/* Pretty printing styles. Used with prettify.js. ----------------------------------------------------- */ -.com { color: #93a1a1; } -.lit { color: #195f91; } -.pun, .opn, .clo { color: #93a1a1; } -.fun { color: #dc322f; } -.str, .atv { color: #D14; } -.kwd, .linenums .tag { color: #1e347b; } -.typ, .atn, .dec, .var { color: teal; } -.pln { color: #48484c; } -.prettyprint { padding: 8px; background-color: #f7f7f9; border: 1px solid #e1e1e8; } -.prettyprint.linenums { - -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; - -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; - box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; -} -ol.linenums { margin: 0 0 0 33px; } -ol.linenums li { padding-left: 12px; color: #bebec5; line-height: 18px; text-shadow: 0 1px 0 #fff; } - /* Additional styles. -----------------------*/ -/* fixed width font links (e.g., to a JavaDoc page) */ -a.javadoc, a.javadoc:hover { - font: 12px Menlo, Monaco, "Courier New", monospace; -} -/* reset code links to same color as normal links */ -a.javadoc, a tt, a code { - color: #0088CC; -} - /* add film icons to youtube and vimeo links (.icon-film) */ a[href^='https://www.youtube.com/']::before, a[href^='https://vimeo.com/']::before { diff --git a/src/site/resources/js/highlight.pack.js b/src/site/resources/js/highlight.pack.js new file mode 100644 index 00000000000..786b1b124ff --- /dev/null +++ b/src/site/resources/js/highlight.pack.js @@ -0,0 +1,2 @@ +/*! highlight.js v9.12.0 | BSD3 License | git.io/hljslicense */ +!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){s+=""}function c(e){("start"===e.event?o:u)(e.node)}for(var l=0,s="",f=[];e.length||r.length;){var g=i();if(s+=n(a.substring(l,g[0].offset)),l=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===l);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return s+n(a.substr(l))}function l(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?u("keyword",a.k):x(a.k).forEach(function(e){u(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return l("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var c=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=c.length?t(c.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function l(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?"":I.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=l(E,r),e?(B+=e[1],a+=p(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!y[E.sL])return n(k);var t=e?f(E.sL,k,!0,x[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(B+=t.r),e&&(x[E.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=null!=E.sL?d():h(),k=""}function v(e){L+=e.cN?p(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(k+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),b(),t.rB||t.eB||(k=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),b(),a.eE&&(k=n));do E.cN&&(L+=C),E.skip||(B+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,E=i||N,x={},L="";for(R=E;R!==N;R=R.parent)R.cN&&(L=p(R.cN,"",!0)+L);var k="",B=0;try{for(var M,j,O=0;;){if(E.t.lastIndex=O,M=E.t.exec(t),!M)break;j=m(t.substring(O,M.index),M[0]),O=M.index+j}for(m(t.substr(O)),R=E;R.parent;R=R.parent)R.cN&&(L+=C);return{r:B,value:L,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function g(e,t){t=t||I.languages||x(y);var r={r:0,value:n(e)},a=r;return t.filter(w).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return I.tabReplace||I.useBR?e.replace(M,function(e,n){return I.useBR&&"\n"===e?"
    ":I.tabReplace?n.replace(/\t/g,I.tabReplace):""}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function d(e){var n,t,r,o,l,s=i(e);a(s)||(I.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,l=n.textContent,r=s?f(s,l,!0):g(l),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),l)),r.value=p(r.value),e.innerHTML=r.value,e.className=h(e.className,s,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){I=o(I,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,d)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=y[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function R(){return x(y)}function w(e){return e=(e||"").toLowerCase(),y[e]||y[L[e]]}var E=[],x=Object.keys,y={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="
    ",I={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=d,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0}]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[t],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("gradle",function(e){return{cI:!0,k:{keyword:"task project allprojects subprojects artifacts buildscript configurations dependencies repositories sourceSets description delete from into include exclude source classpath destinationDir includes options sourceCompatibility targetCompatibility group flatDir doLast doFirst flatten todir fromdir ant def abstract break case catch continue default do else extends final finally for if implements instanceof native new private protected public return static switch synchronized throw throws transient try volatile while strictfp package import false null super this true antlrtask checkstyle codenarc copy boolean byte char class double float int interface long short void compile runTime file fileTree abs any append asList asWritable call collect compareTo count div dump each eachByte eachFile eachLine every find findAll flatten getAt getErr getIn getOut getText grep immutable inject inspect intersect invokeMethods isCase join leftShift minus multiply newInputStream newOutputStream newPrintWriter newReader newWriter next plus pop power previous print println push putAt read readBytes readLines reverse reverseEach round size sort splitEachLine step subMap times toInteger toList tokenize upto waitForOrKill withPrintWriter withReader withStream withWriter withWriterAppend write writeLine"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.NM,e.RM]}});hljs.registerLanguage("ruby",function(e){var b="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},c={cN:"doctag",b:"@[A-Za-z]+"},a={b:"#<",e:">"},s=[e.C("#","$",{c:[c]}),e.C("^\\=begin","^\\=end",{c:[c],r:10}),e.C("^__END__","\\n$")],n={cN:"subst",b:"#\\{",e:"}",k:r},t={cN:"string",c:[e.BE,n],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{b:/<<(-?)\w+$/,e:/^\s*\w+$/}]},i={cN:"params",b:"\\(",e:"\\)",endsParent:!0,k:r},d=[t,a,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{b:"<\\s*",c:[{b:"("+e.IR+"::)?"+e.IR}]}].concat(s)},{cN:"function",bK:"def",e:"$|;",c:[e.inherit(e.TM,{b:b}),i].concat(s)},{b:e.IR+"::"},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":(?!\\s)",c:[t,{b:b}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{cN:"params",b:/\|/,e:/\|/,k:r},{b:"("+e.RSR+"|unless)\\s*",k:"unless",c:[a,{cN:"regexp",c:[e.BE,n],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(s),r:0}].concat(s);n.c=d,i.c=d;var l="[>?]>",o="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",w=[{b:/^\s*=>/,starts:{e:"$",c:d}},{cN:"meta",b:"^("+l+"|"+o+"|"+u+")",starts:{e:"$",c:d}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,i:/\/\*/,c:s.concat(w).concat(d)}});hljs.registerLanguage("yaml",function(e){var b="true false yes no null",a="^[ \\-]*",r="[a-zA-Z_][\\w\\-]*",t={cN:"attr",v:[{b:a+r+":"},{b:a+'"'+r+'":'},{b:a+"'"+r+"':"}]},c={cN:"template-variable",v:[{b:"{{",e:"}}"},{b:"%{",e:"}"}]},l={cN:"string",r:0,v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/\S+/}],c:[e.BE,c]};return{cI:!0,aliases:["yml","YAML","yaml"],c:[t,{cN:"meta",b:"^---s*$",r:10},{cN:"string",b:"[\\|>] *$",rE:!0,c:l.c,e:t.v[0].b},{b:"<%[%=-]?",e:"[%-]?%>",sL:"ruby",eB:!0,eE:!0,r:0},{cN:"type",b:"!!"+e.UIR},{cN:"meta",b:"&"+e.UIR+"$"},{cN:"meta",b:"\\*"+e.UIR+"$"},{cN:"bullet",b:"^ *-",r:0},e.HCM,{bK:b,k:{literal:b}},e.CNM,l]}});hljs.registerLanguage("groovy",function(e){return{k:{literal:"true false null",keyword:"byte short char int long boolean float double void def as in assert trait super this abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof"},c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,{cN:"string",b:'"""',e:'"""'},{cN:"string",b:"'''",e:"'''"},{cN:"string",b:"\\$/",e:"/\\$",r:10},e.ASM,{cN:"regexp",b:/~?\/[^\/\n]+\//,c:[e.BE]},e.QSM,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.BNM,{cN:"class",bK:"class interface trait enum",e:"{",i:":",c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"meta",b:"@[A-Za-z]+"},{cN:"string",b:/[^\?]{0}[A-Za-z0-9_$]+ *:/},{b:/\?/,e:/\:/},{cN:"symbol",b:"^\\s*[A-Za-z0-9_$]+:",r:0}],i:/#|<\//}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("kotlin",function(e){var t={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit initinterface annotation data sealed internal infix operator out by constructor super trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},r={cN:"keyword",b:/\b(break|continue|return|this)\b/,starts:{c:[{cN:"symbol",b:/@\w+/}]}},i={cN:"symbol",b:e.UIR+"@"},n={cN:"subst",b:"\\${",e:"}",c:[e.ASM,e.CNM]},a={cN:"variable",b:"\\$"+e.UIR},c={cN:"string",v:[{b:'"""',e:'"""',c:[a,n]},{b:"'",e:"'",i:/\n/,c:[e.BE]},{b:'"',e:'"',i:/\n/,c:[e.BE,a,n]}]},s={cN:"meta",b:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UIR+")?"},o={cN:"meta",b:"@"+e.UIR,c:[{b:/\(/,e:/\)/,c:[e.inherit(c,{cN:"meta-string"})]}]};return{k:t,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,r,i,s,o,{cN:"function",bK:"fun",e:"[(]|$",rB:!0,eE:!0,k:t,i:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,r:5,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"type",b://,k:"reified",r:0},{cN:"params",b:/\(/,e:/\)/,endsParent:!0,k:t,r:0,c:[{b:/:/,e:/[=,\/]/,eW:!0,c:[{cN:"type",b:e.UIR},e.CLCM,e.CBCM],r:0},e.CLCM,e.CBCM,s,o,c,e.CNM]},e.CBCM]},{cN:"class",bK:"class interface trait",e:/[:\{(]|$/,eE:!0,i:"extends implements",c:[{bK:"public protected internal private constructor"},e.UTM,{cN:"type",b://,eB:!0,eE:!0,r:0},{cN:"type",b:/[,:]\s*/,e:/[<\(,]|$/,eB:!0,rE:!0},s,o]},c,{cN:"meta",b:"^#!/usr/bin/env",e:"$",i:"\n"},e.CNM]}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("scala",function(e){var t={cN:"meta",b:"@[A-Za-z]+"},a={cN:"subst",v:[{b:"\\$[A-Za-z0-9_]+"},{b:"\\${",e:"}"}]},r={cN:"string",v:[{b:'"',e:'"',i:"\\n",c:[e.BE]},{b:'"""',e:'"""',r:10},{b:'[a-z]+"',e:'"',i:"\\n",c:[e.BE,a]},{cN:"string",b:'[a-z]+"""',e:'"""',c:[a],r:10}]},c={cN:"symbol",b:"'\\w[\\w\\d_]*(?!')"},i={cN:"type",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},s={cN:"title",b:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,r:0},n={cN:"class",bK:"class object trait type",e:/[:={\[\n;]/,eE:!0,c:[{bK:"extends with",r:10},{b:/\[/,e:/\]/,eB:!0,eE:!0,r:0,c:[i]},{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,r:0,c:[i]},s]},l={cN:"function",bK:"def",e:/[:={\[(\n;]/,eE:!0,c:[s]};return{k:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},c:[e.CLCM,e.CBCM,r,c,i,l,n,e.CNM,t]}});hljs.registerLanguage("java",function(e){var a="[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",t=a+"(<"+a+"(\\s*,\\s*"+a+")*>)?",r="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",s="\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",c={cN:"number",b:s,r:0};return{aliases:["jsp"],k:r,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{r:0,c:[{b:/\w+@/,r:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",r:0},{cN:"function",b:"("+t+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},c,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("shell",function(s){return{aliases:["console"],c:[{cN:"meta",b:"^\\s{0,3}[\\w\\d\\[\\]()@-]*[>%$#]",starts:{e:"$",sL:"bash"}}]}});hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*#]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment",e:/;/,eW:!0,l:/[\w\.]+/,k:{keyword:"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}}); \ No newline at end of file diff --git a/src/site/resources/js/site.js b/src/site/resources/js/site.js index 902a0dda928..7e37161597e 100644 --- a/src/site/resources/js/site.js +++ b/src/site/resources/js/site.js @@ -18,47 +18,6 @@ limitations under the License. /* Executed on page load. */ $(document).ready(function() { - // - // This is a hack to enable google-code-prettify to work with maven. - // - // The problem is that maven, when building the site, replaces: - //
    ...
    - // with: - //
    ...
    - // - // Effectively, it removes the class parameter from the
     element, which
    -	// is required for google-code-prettify to work.
    -	// 
    -	// This hack restores the class of all 
     elements which are the child of 
    -	// a 
    . - // - $('pre').each(function() { - var parent = $(this).parent(); - - if (parent.hasClass('prettyprint')) { - parent.removeClass('prettyprint'); - $(this).addClass('prettyprint'); - } - - if (parent.hasClass('linenums')) { - parent.removeClass('linenums'); - $(this).addClass('linenums'); - } - - // markdown adds the "source" class instead - if (parent.hasClass('source')) { - parent.removeClass('source'); - $(this).addClass('prettyprint'); - $(this).addClass('linenums'); - } - }); - - // decorator for prettyprint support in asciidoc - $('pre.highlight > code').each(function() { - var parent = $(this).parent(); - parent.addClass('prettyprint') - }); - // Hack to add default visuals to tables $('table').each(function() { if ($(this).hasClass('bodyTable') || $(this).hasClass('tableblock')) { @@ -113,7 +72,4 @@ $(document).ready(function() { // Make external links open in new tab $('a.external').attr('target', '_blank'); - - // Trigger prettyprint - prettyPrint(); }); diff --git a/src/site/site.vm b/src/site/site.vm index a5659ace951..d4933de55d6 100644 --- a/src/site/site.vm +++ b/src/site/site.vm @@ -450,10 +450,12 @@ $title - $project.name + - + + #foreach( $author in $authors ) From 0f4024d202991e7181908892dce1c61423ff563d Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 14:58:16 -0500 Subject: [PATCH 0147/2347] Use better highlighting --- src/site/asciidoc/faq.adoc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/site/asciidoc/faq.adoc b/src/site/asciidoc/faq.adoc index b5cfd784bc6..d9a4629b4f8 100644 --- a/src/site/asciidoc/faq.adoc +++ b/src/site/asciidoc/faq.adoc @@ -140,7 +140,7 @@ well. For example, to use a project with Log4j 2 instead of Log4j 1.x: Dependencies can be globally excluded in Gradle like so: -[source,groovy] +[source,gradle] ---- configurations { all*.exclude group: 'log4j', module: 'log4j' @@ -150,7 +150,7 @@ configurations { The equivalent Gradle config for the above Maven exclusion would look like: -[source,groovy,subs=attributes] +[source,gradle,subs=attributes] ---- dependencies { compile('com.example:example-project:1.0') { @@ -271,17 +271,15 @@ the ``2'' in the file name! (See the link:manual/configuration.html#AutomaticConfiguration[configuration manual page] for more details.) -*From log4j-2.9 onward* - +From log4j-2.9 onward:: From log4j-2.9 onward, log4j2 will print all internal logging to the console if system property `log4j2.debug` is defined (with any or no value). -*Prior to log4j-2.9* - +Prior to log4j-2.9:: Prior to log4j-2.9, there are two places where internal logging can be controlled: - ++ If the configuration file is found correctly, log4j2 internal status logging can be controlled by setting `` in the configuration file. This will display detailed log4j2-internal log @@ -289,7 +287,7 @@ statements on the console about what happens during the configuration process. This may be useful to trouble-shoot configuration issues. By default the status logger level is WARN, so you only see notifications when there is a problem. - ++ If the configuration file is not found correctly, you can still enable log4j2 internal status logging by setting system property `-Dorg.apache.logging.log4j.simplelog.StatusLogger.level=TRACE`. @@ -366,9 +364,11 @@ link:log4j-core/apidocs/org/apache/logging/log4j/core/config/Configurator.html[` from Log4j Core. Be aware that the `Configurator` class is not part of the public API. -[source,xml] +[source,java] ---- -// org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.config.Configurator; + +// ... Configurator.setLevel("com.example.Foo", Level.DEBUG); From be84862bb9530a51df26d98dc0684ffe7b497398 Mon Sep 17 00:00:00 2001 From: Matt Sicker Date: Sat, 7 Apr 2018 15:00:04 -0500 Subject: [PATCH 0148/2347] Remove prettify as it is no longer used --- src/site/resources/js/prettify.js | 1477 ------------------------- src/site/resources/js/prettify.min.js | 41 - 2 files changed, 1518 deletions(-) delete mode 100644 src/site/resources/js/prettify.js delete mode 100644 src/site/resources/js/prettify.min.js diff --git a/src/site/resources/js/prettify.js b/src/site/resources/js/prettify.js deleted file mode 100644 index 037c26da4aa..00000000000 --- a/src/site/resources/js/prettify.js +++ /dev/null @@ -1,1477 +0,0 @@ -// Copyright (C) 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -/** - * @fileoverview - * some functions for browser-side pretty printing of code contained in html. - * - *

    - * For a fairly comprehensive set of languages see the - * README - * file that came with this source. At a minimum, the lexer should work on a - * number of languages including C and friends, Java, Python, Bash, SQL, HTML, - * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk - * and a subset of Perl, but, because of commenting conventions, doesn't work on - * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. - *

    - * Usage:

      - *
    1. include this source file in an html page via - * {@code } - *
    2. define style rules. See the example page for examples. - *
    3. mark the {@code