Restore binary compatibility for TriggerPolicy. Add TODO comment for 3.0. Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/4d84bd58 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/4d84bd58 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/4d84bd58
Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext Commit: 4d84bd581ae1c7262f1ecab25d5947a4bfdd139a Parents: 6e79360 Author: Gary Gregory <ggreg...@apache.org> Authored: Thu Sep 8 15:17:21 2016 -0700 Committer: Gary Gregory <ggreg...@apache.org> Committed: Thu Sep 8 15:17:21 2016 -0700 ---------------------------------------------------------------------- .../rolling/CompositeTriggeringPolicy.java | 5 +- .../appender/rolling/RollingFileManager.java | 962 ++++++++++--------- .../core/appender/rolling/TriggeringPolicy.java | 3 +- 3 files changed, 488 insertions(+), 482 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4d84bd58/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CompositeTriggeringPolicy.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CompositeTriggeringPolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CompositeTriggeringPolicy.java index 6d49435..5e967a6 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CompositeTriggeringPolicy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CompositeTriggeringPolicy.java @@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender.rolling; import java.util.Arrays; import java.util.concurrent.TimeUnit; +import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginElement; @@ -82,7 +83,9 @@ public final class CompositeTriggeringPolicy extends AbstractTriggeringPolicy { setStopping(); boolean stopped = true; for (final TriggeringPolicy triggeringPolicy : triggeringPolicies) { - stopped &= triggeringPolicy.stop(timeout, timeUnit); + if (triggeringPolicy instanceof LifeCycle) { + stopped &= ((LifeCycle) triggeringPolicy).stop(timeout, timeUnit); + } } setStopped(); return stopped; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4d84bd58/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java index db6e9ae..2ec6645 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java @@ -1,479 +1,483 @@ -/* - * 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.rolling; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.Serializable; -import java.nio.ByteBuffer; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; - -import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.LogEvent; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.ConfigurationFactoryData; -import org.apache.logging.log4j.core.appender.FileManager; -import org.apache.logging.log4j.core.appender.ManagerFactory; -import org.apache.logging.log4j.core.appender.rolling.action.AbstractAction; -import org.apache.logging.log4j.core.appender.rolling.action.Action; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.util.Constants; - -/** - * The Rolling File Manager. - */ -public class RollingFileManager extends FileManager { - - private static RollingFileManagerFactory factory = new RollingFileManagerFactory(); - - protected long size; - private long initialTime; - private final PatternProcessor patternProcessor; - private final Semaphore semaphore = new Semaphore(1); - private volatile TriggeringPolicy triggeringPolicy; - private volatile RolloverStrategy rolloverStrategy; - private volatile boolean renameEmptyFiles = false; - - private static final AtomicReferenceFieldUpdater<RollingFileManager, TriggeringPolicy> triggeringPolicyUpdater = - AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, TriggeringPolicy.class, "triggeringPolicy"); - - private static final AtomicReferenceFieldUpdater<RollingFileManager, RolloverStrategy> rolloverStrategyUpdater = - AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, RolloverStrategy.class, "rolloverStrategy"); - - @Deprecated - protected RollingFileManager(final String fileName, final String pattern, final OutputStream os, - final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy, - final RolloverStrategy rolloverStrategy, final String advertiseURI, - final Layout<? extends Serializable> layout, final int bufferSize, final boolean writeHeader) { - this(fileName, pattern, os, append, size, time, triggeringPolicy, rolloverStrategy, advertiseURI, layout, - writeHeader, ByteBuffer.wrap(new byte[Constants.ENCODER_BYTE_BUFFER_SIZE])); - } - - @Deprecated - protected RollingFileManager(final String fileName, final String pattern, final OutputStream os, - final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy, - final RolloverStrategy rolloverStrategy, final String advertiseURI, - final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) { - super(fileName, os, append, false, advertiseURI, layout, writeHeader, buffer); - this.size = size; - this.initialTime = time; - this.triggeringPolicy = triggeringPolicy; - this.rolloverStrategy = rolloverStrategy; - this.patternProcessor = new PatternProcessor(pattern); - this.patternProcessor.setPrevFileTime(time); - } - - /** - * @since 2.7 - */ - protected RollingFileManager(final LoggerContext loggerContext, final String fileName, final String pattern, final OutputStream os, - final boolean append, final boolean createOnDemand, final long size, final long time, - final TriggeringPolicy triggeringPolicy, final RolloverStrategy rolloverStrategy, - final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) { - super(loggerContext, fileName, os, append, false, createOnDemand, advertiseURI, layout, writeHeader, buffer); - this.size = size; - this.initialTime = time; - this.triggeringPolicy = triggeringPolicy; - this.rolloverStrategy = rolloverStrategy; - this.patternProcessor = new PatternProcessor(pattern); - this.patternProcessor.setPrevFileTime(time); - } - - public void initialize() { - triggeringPolicy.initialize(this); - } - - /** - * Returns a RollingFileManager. - * @param fileName The file name. - * @param pattern The pattern for rolling file. - * @param append true if the file should be appended to. - * @param bufferedIO true if data should be buffered. - * @param policy The TriggeringPolicy. - * @param strategy The RolloverStrategy. - * @param advertiseURI the URI to use when advertising the file - * @param layout The Layout. - * @param bufferSize buffer size to use if bufferedIO is true - * @param immediateFlush flush on every write or not - * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.) - * @param configuration The configuration. - * @return A RollingFileManager. - */ - public static RollingFileManager getFileManager(final String fileName, final String pattern, final boolean append, - final boolean bufferedIO, final TriggeringPolicy policy, final RolloverStrategy strategy, - final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize, - final boolean immediateFlush, final boolean createOnDemand, final Configuration configuration) { - - return (RollingFileManager) getManager(fileName, new FactoryData(pattern, append, - bufferedIO, policy, strategy, advertiseURI, layout, bufferSize, immediateFlush, createOnDemand, configuration), factory); - } - - // override to make visible for unit tests - @Override - protected synchronized void write(final byte[] bytes, final int offset, final int length, - final boolean immediateFlush) { - super.write(bytes, offset, length, immediateFlush); - } - - @Override - protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) { - size += length; - super.writeToDestination(bytes, offset, length); - } - - public boolean isRenameEmptyFiles() { - return renameEmptyFiles; - } - - public void setRenameEmptyFiles(final boolean renameEmptyFiles) { - this.renameEmptyFiles = renameEmptyFiles; - } - - /** - * Returns the current size of the file. - * @return The size of the file in bytes. - */ - public long getFileSize() { - return size + byteBuffer.position(); - } - - /** - * Returns the time the file was created. - * @return The time the file was created. - */ - public long getFileTime() { - return initialTime; - } - - /** - * Determines if a rollover should occur. - * @param event The LogEvent. - */ - public synchronized void checkRollover(final LogEvent event) { - if (triggeringPolicy.isTriggeringEvent(event)) { - rollover(); - } - } - - @Override - public boolean releaseSub(final long timeout, final TimeUnit timeUnit) { - boolean stopped = triggeringPolicy.stop(timeout, timeUnit); - return stopped && super.releaseSub(timeout, timeUnit); - } - - public synchronized void rollover() { - if (rollover(rolloverStrategy)) { - try { - size = 0; - initialTime = System.currentTimeMillis(); - createFileAfterRollover(); - } catch (final IOException e) { - logError("Failed to create file after rollover", e); - } - } - } - - protected void createFileAfterRollover() throws IOException { - setOutputStream(new FileOutputStream(getFileName(), isAppend())); - } - - /** - * Returns the pattern processor. - * @return The PatternProcessor. - */ - public PatternProcessor getPatternProcessor() { - return patternProcessor; - } - - public void setTriggeringPolicy(final TriggeringPolicy triggeringPolicy) { - triggeringPolicy.initialize(this); - triggeringPolicyUpdater.compareAndSet(this, this.triggeringPolicy, triggeringPolicy); - } - - public void setRolloverStrategy(final RolloverStrategy rolloverStrategy) { - rolloverStrategyUpdater.compareAndSet(this, this.rolloverStrategy, rolloverStrategy); - } - - /** - * Returns the triggering policy. - * @param <T> TriggeringPolicy type - * @return The TriggeringPolicy - */ - @SuppressWarnings("unchecked") - public <T extends TriggeringPolicy> T getTriggeringPolicy() { - // TODO We could parameterize this class with a TriggeringPolicy instead of type casting here. - return (T) this.triggeringPolicy; - } - - /** - * Returns the rollover strategy. - * @return The RolloverStrategy - */ - public RolloverStrategy getRolloverStrategy() { - return this.rolloverStrategy; - } - - private boolean rollover(final RolloverStrategy strategy) { - - try { - // Block until the asynchronous operation is completed. - semaphore.acquire(); - } catch (final InterruptedException e) { - logError("Thread interrupted while attempting to check rollover", e); - return false; - } - - boolean success = false; - Future<?> future = null; - - try { - final RolloverDescription descriptor = strategy.rollover(this); - if (descriptor != null) { - writeFooter(); - closeOutputStream(); - if (descriptor.getSynchronous() != null) { - LOGGER.debug("RollingFileManager executing synchronous {}", descriptor.getSynchronous()); - try { - success = descriptor.getSynchronous().execute(); - } catch (final Exception ex) { - logError("Caught error in synchronous task", ex); - } - } - - if (success && descriptor.getAsynchronous() != null) { - LOGGER.debug("RollingFileManager executing async {}", descriptor.getAsynchronous()); - future = LoggerContext.getContext(false).submit(new AsyncAction(descriptor.getAsynchronous(), this)); - } - return true; - } - return false; - } finally { - if (future == null || future.isDone() || future.isCancelled()) { - semaphore.release(); - } - } - - } - - /** - * Performs actions asynchronously. - */ - private static class AsyncAction extends AbstractAction { - - private final Action action; - private final RollingFileManager manager; - - /** - * Constructor. - * @param act The action to perform. - * @param manager The manager. - */ - public AsyncAction(final Action act, final RollingFileManager manager) { - this.action = act; - this.manager = manager; - } - - /** - * Executes an action. - * - * @return true if action was successful. A return value of false will cause - * the rollover to be aborted if possible. - * @throws java.io.IOException if IO error, a thrown exception will cause the rollover - * to be aborted if possible. - */ - @Override - public boolean execute() throws IOException { - try { - return action.execute(); - } finally { - manager.semaphore.release(); - } - } - - /** - * Cancels the action if not already initialized or waits till completion. - */ - @Override - public void close() { - action.close(); - } - - /** - * Determines if action has been completed. - * - * @return true if action is complete. - */ - @Override - public boolean isComplete() { - return action.isComplete(); - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append(super.toString()); - builder.append("[action="); - builder.append(action); - builder.append(", manager="); - builder.append(manager); - builder.append(", isComplete()="); - builder.append(isComplete()); - builder.append(", isInterrupted()="); - builder.append(isInterrupted()); - builder.append("]"); - return builder.toString(); - } - } - - /** - * Factory data. - */ - private static class FactoryData extends ConfigurationFactoryData { - private final String pattern; - private final boolean append; - private final boolean bufferedIO; - private final int bufferSize; - private final boolean immediateFlush; - private final boolean createOnDemand; - private final TriggeringPolicy policy; - private final RolloverStrategy strategy; - private final String advertiseURI; - private final Layout<? extends Serializable> layout; - - /** - * Creates the data for the factory. - * @param pattern The pattern. - * @param append The append flag. - * @param bufferedIO The bufferedIO flag. - * @param advertiseURI - * @param layout The Layout. - * @param bufferSize the buffer size - * @param immediateFlush flush on every write or not - * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.) - * @param configuration The configuration - */ - public FactoryData(final String pattern, final boolean append, final boolean bufferedIO, - final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI, - final Layout<? extends Serializable> layout, final int bufferSize, final boolean immediateFlush, - final boolean createOnDemand, final Configuration configuration) { - super(configuration); - this.pattern = pattern; - this.append = append; - this.bufferedIO = bufferedIO; - this.bufferSize = bufferSize; - this.policy = policy; - this.strategy = strategy; - this.advertiseURI = advertiseURI; - this.layout = layout; - this.immediateFlush = immediateFlush; - this.createOnDemand = createOnDemand; - } - - public TriggeringPolicy getTriggeringPolicy() - { - return this.policy; - } - - public RolloverStrategy getRolloverStrategy() - { - return this.strategy; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append(super.toString()); - builder.append("[pattern="); - builder.append(pattern); - builder.append(", append="); - builder.append(append); - builder.append(", bufferedIO="); - builder.append(bufferedIO); - builder.append(", bufferSize="); - builder.append(bufferSize); - builder.append(", policy="); - builder.append(policy); - builder.append(", strategy="); - builder.append(strategy); - builder.append(", advertiseURI="); - builder.append(advertiseURI); - builder.append(", layout="); - builder.append(layout); - builder.append("]"); - return builder.toString(); - } - } - - @Override - public void updateData(final Object data) - { - final FactoryData factoryData = (FactoryData) data; - setRolloverStrategy(factoryData.getRolloverStrategy()); - setTriggeringPolicy(factoryData.getTriggeringPolicy()); - } - - /** - * Factory to create a RollingFileManager. - */ - private static class RollingFileManagerFactory implements ManagerFactory<RollingFileManager, FactoryData> { - - /** - * Creates a RollingFileManager. - * @param name The name of the entity to manage. - * @param data The data required to create the entity. - * @return a RollingFileManager. - */ - @Override - public RollingFileManager createManager(final String name, final FactoryData data) { - final File file = new File(name); - final File parent = file.getParentFile(); - if (null != parent && !parent.exists()) { - parent.mkdirs(); - } - // LOG4J2-1140: check writeHeader before creating the file - final boolean writeHeader = !data.append || !file.exists(); - try { - final boolean created = data.createOnDemand ? false : file.createNewFile(); - LOGGER.trace("New file '{}' created = {}", name, created); - } catch (final IOException ioe) { - LOGGER.error("Unable to create file " + name, ioe); - return null; - } - final long size = data.append ? file.length() : 0; - - try { - final int actualSize = data.bufferedIO ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE; - final ByteBuffer buffer = ByteBuffer.wrap(new byte[actualSize]); - final OutputStream os = data.createOnDemand ? null : new FileOutputStream(name, data.append); - final long time = data.createOnDemand? System.currentTimeMillis() : file.lastModified(); // LOG4J2-531 create file first so time has valid value - - return new RollingFileManager(data.getLoggerContext(), name, data.pattern, os, - data.append, data.createOnDemand, size, time, data.policy, data.strategy, data.advertiseURI, - data.layout, writeHeader, buffer); - } catch (final IOException ex) { - LOGGER.error("RollingFileManager (" + name + ") " + ex, ex); - } - return null; - } - } - -} +/* + * 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.rolling; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LifeCycle; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.ConfigurationFactoryData; +import org.apache.logging.log4j.core.appender.FileManager; +import org.apache.logging.log4j.core.appender.ManagerFactory; +import org.apache.logging.log4j.core.appender.rolling.action.AbstractAction; +import org.apache.logging.log4j.core.appender.rolling.action.Action; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.util.Constants; + +/** + * The Rolling File Manager. + */ +public class RollingFileManager extends FileManager { + + private static RollingFileManagerFactory factory = new RollingFileManagerFactory(); + + protected long size; + private long initialTime; + private final PatternProcessor patternProcessor; + private final Semaphore semaphore = new Semaphore(1); + private volatile TriggeringPolicy triggeringPolicy; + private volatile RolloverStrategy rolloverStrategy; + private volatile boolean renameEmptyFiles = false; + + private static final AtomicReferenceFieldUpdater<RollingFileManager, TriggeringPolicy> triggeringPolicyUpdater = + AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, TriggeringPolicy.class, "triggeringPolicy"); + + private static final AtomicReferenceFieldUpdater<RollingFileManager, RolloverStrategy> rolloverStrategyUpdater = + AtomicReferenceFieldUpdater.newUpdater(RollingFileManager.class, RolloverStrategy.class, "rolloverStrategy"); + + @Deprecated + protected RollingFileManager(final String fileName, final String pattern, final OutputStream os, + final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy, + final RolloverStrategy rolloverStrategy, final String advertiseURI, + final Layout<? extends Serializable> layout, final int bufferSize, final boolean writeHeader) { + this(fileName, pattern, os, append, size, time, triggeringPolicy, rolloverStrategy, advertiseURI, layout, + writeHeader, ByteBuffer.wrap(new byte[Constants.ENCODER_BYTE_BUFFER_SIZE])); + } + + @Deprecated + protected RollingFileManager(final String fileName, final String pattern, final OutputStream os, + final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy, + final RolloverStrategy rolloverStrategy, final String advertiseURI, + final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) { + super(fileName, os, append, false, advertiseURI, layout, writeHeader, buffer); + this.size = size; + this.initialTime = time; + this.triggeringPolicy = triggeringPolicy; + this.rolloverStrategy = rolloverStrategy; + this.patternProcessor = new PatternProcessor(pattern); + this.patternProcessor.setPrevFileTime(time); + } + + /** + * @since 2.7 + */ + protected RollingFileManager(final LoggerContext loggerContext, final String fileName, final String pattern, final OutputStream os, + final boolean append, final boolean createOnDemand, final long size, final long time, + final TriggeringPolicy triggeringPolicy, final RolloverStrategy rolloverStrategy, + final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader, final ByteBuffer buffer) { + super(loggerContext, fileName, os, append, false, createOnDemand, advertiseURI, layout, writeHeader, buffer); + this.size = size; + this.initialTime = time; + this.triggeringPolicy = triggeringPolicy; + this.rolloverStrategy = rolloverStrategy; + this.patternProcessor = new PatternProcessor(pattern); + this.patternProcessor.setPrevFileTime(time); + } + + public void initialize() { + triggeringPolicy.initialize(this); + } + + /** + * Returns a RollingFileManager. + * @param fileName The file name. + * @param pattern The pattern for rolling file. + * @param append true if the file should be appended to. + * @param bufferedIO true if data should be buffered. + * @param policy The TriggeringPolicy. + * @param strategy The RolloverStrategy. + * @param advertiseURI the URI to use when advertising the file + * @param layout The Layout. + * @param bufferSize buffer size to use if bufferedIO is true + * @param immediateFlush flush on every write or not + * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.) + * @param configuration The configuration. + * @return A RollingFileManager. + */ + public static RollingFileManager getFileManager(final String fileName, final String pattern, final boolean append, + final boolean bufferedIO, final TriggeringPolicy policy, final RolloverStrategy strategy, + final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize, + final boolean immediateFlush, final boolean createOnDemand, final Configuration configuration) { + + return (RollingFileManager) getManager(fileName, new FactoryData(pattern, append, + bufferedIO, policy, strategy, advertiseURI, layout, bufferSize, immediateFlush, createOnDemand, configuration), factory); + } + + // override to make visible for unit tests + @Override + protected synchronized void write(final byte[] bytes, final int offset, final int length, + final boolean immediateFlush) { + super.write(bytes, offset, length, immediateFlush); + } + + @Override + protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) { + size += length; + super.writeToDestination(bytes, offset, length); + } + + public boolean isRenameEmptyFiles() { + return renameEmptyFiles; + } + + public void setRenameEmptyFiles(final boolean renameEmptyFiles) { + this.renameEmptyFiles = renameEmptyFiles; + } + + /** + * Returns the current size of the file. + * @return The size of the file in bytes. + */ + public long getFileSize() { + return size + byteBuffer.position(); + } + + /** + * Returns the time the file was created. + * @return The time the file was created. + */ + public long getFileTime() { + return initialTime; + } + + /** + * Determines if a rollover should occur. + * @param event The LogEvent. + */ + public synchronized void checkRollover(final LogEvent event) { + if (triggeringPolicy.isTriggeringEvent(event)) { + rollover(); + } + } + + @Override + public boolean releaseSub(final long timeout, final TimeUnit timeUnit) { + boolean stopped = true; + if (triggeringPolicy instanceof LifeCycle) { + stopped &= ((LifeCycle) triggeringPolicy).stop(timeout, timeUnit); + } + return stopped && super.releaseSub(timeout, timeUnit); + } + + public synchronized void rollover() { + if (rollover(rolloverStrategy)) { + try { + size = 0; + initialTime = System.currentTimeMillis(); + createFileAfterRollover(); + } catch (final IOException e) { + logError("Failed to create file after rollover", e); + } + } + } + + protected void createFileAfterRollover() throws IOException { + setOutputStream(new FileOutputStream(getFileName(), isAppend())); + } + + /** + * Returns the pattern processor. + * @return The PatternProcessor. + */ + public PatternProcessor getPatternProcessor() { + return patternProcessor; + } + + public void setTriggeringPolicy(final TriggeringPolicy triggeringPolicy) { + triggeringPolicy.initialize(this); + triggeringPolicyUpdater.compareAndSet(this, this.triggeringPolicy, triggeringPolicy); + } + + public void setRolloverStrategy(final RolloverStrategy rolloverStrategy) { + rolloverStrategyUpdater.compareAndSet(this, this.rolloverStrategy, rolloverStrategy); + } + + /** + * Returns the triggering policy. + * @param <T> TriggeringPolicy type + * @return The TriggeringPolicy + */ + @SuppressWarnings("unchecked") + public <T extends TriggeringPolicy> T getTriggeringPolicy() { + // TODO We could parameterize this class with a TriggeringPolicy instead of type casting here. + return (T) this.triggeringPolicy; + } + + /** + * Returns the rollover strategy. + * @return The RolloverStrategy + */ + public RolloverStrategy getRolloverStrategy() { + return this.rolloverStrategy; + } + + private boolean rollover(final RolloverStrategy strategy) { + + try { + // Block until the asynchronous operation is completed. + semaphore.acquire(); + } catch (final InterruptedException e) { + logError("Thread interrupted while attempting to check rollover", e); + return false; + } + + boolean success = false; + Future<?> future = null; + + try { + final RolloverDescription descriptor = strategy.rollover(this); + if (descriptor != null) { + writeFooter(); + closeOutputStream(); + if (descriptor.getSynchronous() != null) { + LOGGER.debug("RollingFileManager executing synchronous {}", descriptor.getSynchronous()); + try { + success = descriptor.getSynchronous().execute(); + } catch (final Exception ex) { + logError("Caught error in synchronous task", ex); + } + } + + if (success && descriptor.getAsynchronous() != null) { + LOGGER.debug("RollingFileManager executing async {}", descriptor.getAsynchronous()); + future = LoggerContext.getContext(false).submit(new AsyncAction(descriptor.getAsynchronous(), this)); + } + return true; + } + return false; + } finally { + if (future == null || future.isDone() || future.isCancelled()) { + semaphore.release(); + } + } + + } + + /** + * Performs actions asynchronously. + */ + private static class AsyncAction extends AbstractAction { + + private final Action action; + private final RollingFileManager manager; + + /** + * Constructor. + * @param act The action to perform. + * @param manager The manager. + */ + public AsyncAction(final Action act, final RollingFileManager manager) { + this.action = act; + this.manager = manager; + } + + /** + * Executes an action. + * + * @return true if action was successful. A return value of false will cause + * the rollover to be aborted if possible. + * @throws java.io.IOException if IO error, a thrown exception will cause the rollover + * to be aborted if possible. + */ + @Override + public boolean execute() throws IOException { + try { + return action.execute(); + } finally { + manager.semaphore.release(); + } + } + + /** + * Cancels the action if not already initialized or waits till completion. + */ + @Override + public void close() { + action.close(); + } + + /** + * Determines if action has been completed. + * + * @return true if action is complete. + */ + @Override + public boolean isComplete() { + return action.isComplete(); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(super.toString()); + builder.append("[action="); + builder.append(action); + builder.append(", manager="); + builder.append(manager); + builder.append(", isComplete()="); + builder.append(isComplete()); + builder.append(", isInterrupted()="); + builder.append(isInterrupted()); + builder.append("]"); + return builder.toString(); + } + } + + /** + * Factory data. + */ + private static class FactoryData extends ConfigurationFactoryData { + private final String pattern; + private final boolean append; + private final boolean bufferedIO; + private final int bufferSize; + private final boolean immediateFlush; + private final boolean createOnDemand; + private final TriggeringPolicy policy; + private final RolloverStrategy strategy; + private final String advertiseURI; + private final Layout<? extends Serializable> layout; + + /** + * Creates the data for the factory. + * @param pattern The pattern. + * @param append The append flag. + * @param bufferedIO The bufferedIO flag. + * @param advertiseURI + * @param layout The Layout. + * @param bufferSize the buffer size + * @param immediateFlush flush on every write or not + * @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.) + * @param configuration The configuration + */ + public FactoryData(final String pattern, final boolean append, final boolean bufferedIO, + final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI, + final Layout<? extends Serializable> layout, final int bufferSize, final boolean immediateFlush, + final boolean createOnDemand, final Configuration configuration) { + super(configuration); + this.pattern = pattern; + this.append = append; + this.bufferedIO = bufferedIO; + this.bufferSize = bufferSize; + this.policy = policy; + this.strategy = strategy; + this.advertiseURI = advertiseURI; + this.layout = layout; + this.immediateFlush = immediateFlush; + this.createOnDemand = createOnDemand; + } + + public TriggeringPolicy getTriggeringPolicy() + { + return this.policy; + } + + public RolloverStrategy getRolloverStrategy() + { + return this.strategy; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(super.toString()); + builder.append("[pattern="); + builder.append(pattern); + builder.append(", append="); + builder.append(append); + builder.append(", bufferedIO="); + builder.append(bufferedIO); + builder.append(", bufferSize="); + builder.append(bufferSize); + builder.append(", policy="); + builder.append(policy); + builder.append(", strategy="); + builder.append(strategy); + builder.append(", advertiseURI="); + builder.append(advertiseURI); + builder.append(", layout="); + builder.append(layout); + builder.append("]"); + return builder.toString(); + } + } + + @Override + public void updateData(final Object data) + { + final FactoryData factoryData = (FactoryData) data; + setRolloverStrategy(factoryData.getRolloverStrategy()); + setTriggeringPolicy(factoryData.getTriggeringPolicy()); + } + + /** + * Factory to create a RollingFileManager. + */ + private static class RollingFileManagerFactory implements ManagerFactory<RollingFileManager, FactoryData> { + + /** + * Creates a RollingFileManager. + * @param name The name of the entity to manage. + * @param data The data required to create the entity. + * @return a RollingFileManager. + */ + @Override + public RollingFileManager createManager(final String name, final FactoryData data) { + final File file = new File(name); + final File parent = file.getParentFile(); + if (null != parent && !parent.exists()) { + parent.mkdirs(); + } + // LOG4J2-1140: check writeHeader before creating the file + final boolean writeHeader = !data.append || !file.exists(); + try { + final boolean created = data.createOnDemand ? false : file.createNewFile(); + LOGGER.trace("New file '{}' created = {}", name, created); + } catch (final IOException ioe) { + LOGGER.error("Unable to create file " + name, ioe); + return null; + } + final long size = data.append ? file.length() : 0; + + try { + final int actualSize = data.bufferedIO ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE; + final ByteBuffer buffer = ByteBuffer.wrap(new byte[actualSize]); + final OutputStream os = data.createOnDemand ? null : new FileOutputStream(name, data.append); + final long time = data.createOnDemand? System.currentTimeMillis() : file.lastModified(); // LOG4J2-531 create file first so time has valid value + + return new RollingFileManager(data.getLoggerContext(), name, data.pattern, os, + data.append, data.createOnDemand, size, time, data.policy, data.strategy, data.advertiseURI, + data.layout, writeHeader, buffer); + } catch (final IOException ex) { + LOGGER.error("RollingFileManager (" + name + ") " + ex, ex); + } + return null; + } + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4d84bd58/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java index f6fea59..ed6a3f1 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/TriggeringPolicy.java @@ -16,7 +16,6 @@ */ package org.apache.logging.log4j.core.appender.rolling; -import org.apache.logging.log4j.core.LifeCycle; import org.apache.logging.log4j.core.LogEvent; /** @@ -26,7 +25,7 @@ import org.apache.logging.log4j.core.LogEvent; * * @see AbstractTriggeringPolicy */ -public interface TriggeringPolicy extends LifeCycle { +public interface TriggeringPolicy /* TODO 3.0: extends LifeCycle */ { /** * Initializes this triggering policy.