diff --git a/log4j-core/LOG4J2-807.log b/log4j-core/LOG4J2-807.log new file mode 100644 index 0000000..bc8b50b --- /dev/null +++ b/log4j-core/LOG4J2-807.log @@ -0,0 +1,16 @@ +2014-09-10 09:45:25,340 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j configured, will be reconfigured in aprox. 5 sec +2014-09-10 09:45:26,341 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:45:27,341 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:45:28,341 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:45:29,341 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:45:30,341 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:45:31,341 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:45:32,343 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:50:43,715 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j configured, will be reconfigured in aprox. 5 sec +2014-09-10 09:50:44,717 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:50:45,717 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:50:46,717 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:50:47,717 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:50:48,717 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:50:49,717 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration +2014-09-10 09:50:50,718 INFO [o.a.l.l.c.a.AsyncRootReloadTest] Log4j waiting for reconfiguration diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/AbstractClock.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/AbstractClock.java new file mode 100644 index 0000000..fcf675f --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/AbstractClock.java @@ -0,0 +1,27 @@ +/* + * 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; + +public abstract class AbstractClock implements Clock { + + @Override + public void stop() { + // do notthing + } + +} 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/util/CachedClock.java index c4324c7..7670e7a 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/util/CachedClock.java @@ -31,22 +31,30 @@ private static final CachedClock instance = new CachedClock(); private volatile long millis = System.currentTimeMillis(); private volatile short count = 0; + + private final class UpdateThread extends StopFlagThread { - private CachedClock() { - final Thread updater = new Thread(new Runnable() { - @Override - public void run() { - while (true) { - final long time = System.currentTimeMillis(); - millis = time; + UpdateThread() { + super("Log4j CachedClock Thread"); + } - // avoid explicit dependency on sun.misc.Util - LockSupport.parkNanos(1000 * 1000); - } + @Override + public void run() { + while (!getStopFlag()) { + final long time = System.currentTimeMillis(); + millis = time; + + // avoid explicit dependency on sun.misc.Util + LockSupport.parkNanos(1000 * 1000); } - }, "Clock Updater Thread"); - updater.setDaemon(true); - updater.start(); + } + } + + private UpdateThread updateThread = new UpdateThread(); + + private CachedClock() { + updateThread.setDaemon(true); + updateThread.start(); } public static CachedClock instance() { @@ -71,4 +79,11 @@ } return millis; } + + @Override + public void stop() { + updateThread.setStopFlag(); + updateThread = null; + } + } 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 87457dc..8afe914 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 @@ -26,4 +26,10 @@ * @return the time in milliseconds since the epoch */ long currentTimeMillis(); + + /** + * Requests this clock stops. May have no effect or a delayed effect depending on the implementation (requesting + * threads end for example). + */ + void stop(); } 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/util/CoarseCachedClock.java index 77ffa4d..ab5ccc5 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/util/CoarseCachedClock.java @@ -23,27 +23,34 @@ * the cost of some accuracy. */ public final class CoarseCachedClock implements Clock { - private static final CoarseCachedClock instance = new CoarseCachedClock(); - // ignore IDE complaints; volatile long is fine - private volatile long millis = System.currentTimeMillis(); + private final class UpdateThread extends StopFlagThread { - private final Thread updater = new Thread("Clock Updater Thread") { + UpdateThread() { + super("Log4j CoarseCachedClock Thread"); + } + @Override public void run() { - while (true) { + while (!getStopFlag()) { millis = System.currentTimeMillis(); // avoid explicit dependency on sun.misc.Util LockSupport.parkNanos(1000 * 1000); } } - }; - - private CoarseCachedClock() { - updater.setDaemon(true); - updater.start(); } + private static final CoarseCachedClock instance = new CoarseCachedClock(); + // ignore IDE complaints; volatile long is fine + private volatile long millis = System.currentTimeMillis(); + + private UpdateThread updateThread = new UpdateThread(); + + private CoarseCachedClock() { + updateThread.setDaemon(true); + updateThread.start(); + } + /** * Returns the singleton instance. * @@ -64,4 +71,10 @@ public long currentTimeMillis() { return millis; } + + @Override + public void stop() { + updateThread.setStopFlag(); + updateThread = null; + } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/StopFlagThread.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/StopFlagThread.java new file mode 100644 index 0000000..86cbbca --- /dev/null +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/StopFlagThread.java @@ -0,0 +1,34 @@ +/* + * 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; + +public class StopFlagThread extends Thread { + private volatile boolean stopFlag; + + public StopFlagThread(String name) { + super(name); + } + + public boolean getStopFlag() { + return stopFlag; + } + + public void setStopFlag() { + stopFlag = true; + } +} 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/util/SystemClock.java index 6dab557..791739b 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/util/SystemClock.java @@ -19,7 +19,7 @@ /** * Implementation of the {@code Clock} interface that returns the system time. */ -public final class SystemClock implements Clock { +public final class SystemClock extends AbstractClock { /** * Returns the system time. 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 f3dbc2d..1332e3d 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 @@ -16,7 +16,13 @@ */ package org.apache.logging.log4j.core; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.List; + import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.util.AbstractClock; import org.apache.logging.log4j.core.util.Clock; import org.apache.logging.log4j.core.util.ClockFactory; import org.apache.logging.log4j.core.util.Constants; @@ -25,11 +31,11 @@ import org.apache.logging.log4j.message.TimestampMessage; import org.apache.logging.log4j.test.appender.ListAppender; import org.apache.logging.log4j.util.Strings; -import org.junit.*; - -import java.util.List; - -import static org.junit.Assert.*; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; /** * Confirms that if you log a {@link TimestampMessage} then there are no unnecessary calls to {@link Clock}. @@ -69,7 +75,7 @@ assertEquals("123456789000 Message with embedded timestamp" + NL, msgs.get(0)); } - public static class PoisonClock implements Clock { + public static class PoisonClock extends AbstractClock { @Override public long currentTimeMillis() { throw new RuntimeException("This should not have been called"); 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 3cfd0b5..a95ed9e 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 @@ -16,10 +16,18 @@ */ package org.apache.logging.log4j.core.async; +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 org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.util.AbstractClock; import org.apache.logging.log4j.core.util.Clock; import org.apache.logging.log4j.core.util.ClockFactory; import org.apache.logging.log4j.core.util.Constants; @@ -29,12 +37,6 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; - -import static org.junit.Assert.*; /** * Confirms that if you log a {@link TimestampMessage} then there are no unnecessary calls to {@link Clock}. @@ -77,7 +79,7 @@ assertTrue("line1 correct", line1.equals("123456789000 Async logger msg with embedded timestamp")); } - public static class PoisonClock implements Clock { + public static class PoisonClock extends AbstractClock { @Override public long currentTimeMillis() { throw new RuntimeException("This should not have been called"); 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 e6b4dde..71f2a5c 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 @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.core.impl; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -26,7 +30,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.core.util.Clock; +import org.apache.logging.log4j.core.util.AbstractClock; import org.apache.logging.log4j.core.util.ClockFactory; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.SimpleMessage; @@ -35,12 +39,10 @@ import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; - public class Log4jLogEventTest { /** Helper class */ - public static class FixedTimeClock implements Clock { + public static class FixedTimeClock extends AbstractClock { public static final long FIXED_TIME = 1234567890L; /* 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/util/ClockFactoryTest.java index 1b69a16..fde2102 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/util/ClockFactoryTest.java @@ -64,7 +64,7 @@ assertSame(CoarseCachedClock.class, ClockFactory.getClock().getClass()); } - public static class MyClock implements Clock { + public static class MyClock extends AbstractClock { @Override public long currentTimeMillis() { return 42; 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 83a0442..21c5221 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 @@ -19,6 +19,7 @@ import java.util.concurrent.TimeUnit; +import org.apache.logging.log4j.core.util.AbstractClock; import org.apache.logging.log4j.core.util.CachedClock; import org.apache.logging.log4j.core.util.Clock; import org.apache.logging.log4j.core.util.CoarseCachedClock; @@ -111,7 +112,7 @@ return fixedFinalClock.currentTimeMillis(); } - private static final class FixedTimeClock implements Clock { + private static final class FixedTimeClock extends AbstractClock { private long fixedTime; public FixedTimeClock(long fixedTime) { @@ -124,7 +125,7 @@ } } - private static final class FixedFinalTimeClock implements Clock { + private static final class FixedFinalTimeClock extends AbstractClock { private final long fixedFinalTime; public FixedFinalTimeClock(long fixedTime) { diff --git a/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java b/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java index 826ecd2..8b1274a 100644 --- a/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java +++ b/log4j-web/src/main/java/org/apache/logging/log4j/web/Log4jWebInitializerImpl.java @@ -20,6 +20,7 @@ import java.net.URL; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + import javax.servlet.ServletContext; import org.apache.logging.log4j.LogManager; @@ -33,6 +34,7 @@ import org.apache.logging.log4j.core.lookup.StrSubstitutor; import org.apache.logging.log4j.core.selector.ContextSelector; import org.apache.logging.log4j.core.selector.NamedContextSelector; +import org.apache.logging.log4j.core.util.ClockFactory; import org.apache.logging.log4j.core.util.FileUtils; import org.apache.logging.log4j.core.util.Loader; import org.apache.logging.log4j.core.util.NetUtils; @@ -216,6 +218,8 @@ this.loggerContext.stop(); this.loggerContext.setExternalContext(null); this.loggerContext = null; + // Should this be in the loggerContext stop() method? + ClockFactory.getClock().stop(); } this.setStopped(); }