LOG4J2-1928 - Add support for DirectWriteRolloverStrategy to RollingRandomAcessFileAppender
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/0b37ee74 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/0b37ee74 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/0b37ee74 Branch: refs/heads/LOG4J2-1431 Commit: 0b37ee7466284d6a012a092f7284d15c53b75803 Parents: 4aa719a Author: Ralph Goers <[email protected]> Authored: Thu Aug 24 09:20:17 2017 -0700 Committer: Ralph Goers <[email protected]> Committed: Thu Aug 24 09:20:29 2017 -0700 ---------------------------------------------------------------------- .../RollingRandomAccessFileAppender.java | 25 ++++-- .../rolling/RollingRandomAccessFileManager.java | 93 ++++++++++++-------- .../RollingRandomAppenderDirectWriteTest.java | 66 ++++++++++++++ .../resources/log4j-rolling-random-direct.xml | 50 +++++++++++ src/changes/changes.xml | 3 + 5 files changed, 192 insertions(+), 45 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0b37ee74/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java index 6148dec..f43ccd0 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/RollingRandomAccessFileAppender.java @@ -28,6 +28,8 @@ 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.rolling.DefaultRolloverStrategy; +import org.apache.logging.log4j.core.appender.rolling.DirectFileRolloverStrategy; +import org.apache.logging.log4j.core.appender.rolling.DirectWriteRolloverStrategy; import org.apache.logging.log4j.core.appender.rolling.RollingRandomAccessFileManager; import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy; import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy; @@ -95,8 +97,20 @@ public final class RollingRandomAccessFileAppender extends AbstractOutputStreamA return null; } - if (fileName == null) { - LOGGER.error("No filename was provided for FileAppender with name " + name); + if (strategy == null) { + if (fileName != null) { + strategy = DefaultRolloverStrategy.newBuilder() + .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION)) + .withConfig(getConfiguration()) + .build(); + } else { + strategy = DirectWriteRolloverStrategy.newBuilder() + .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION)) + .withConfig(getConfiguration()) + .build(); + } + } else if (fileName == null && !(strategy instanceof DirectFileRolloverStrategy)) { + LOGGER.error("RollingFileAppender '{}': When no file name is provided a DirectFilenameRolloverStrategy must be configured"); return null; } @@ -110,13 +124,6 @@ public final class RollingRandomAccessFileAppender extends AbstractOutputStreamA return null; } - if (strategy == null) { - strategy = DefaultRolloverStrategy.newBuilder() - .withCompressionLevelStr(String.valueOf(Deflater.DEFAULT_COMPRESSION)) - .withConfig(getConfiguration()) - .build(); - } - final Layout<? extends Serializable> layout = getOrCreateLayout(); final boolean immediateFlush = isImmediateFlush(); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0b37ee74/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAccessFileManager.java ---------------------------------------------------------------------- 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 6d69bd9..0d60483 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 @@ -105,7 +105,8 @@ public class RollingRandomAccessFileManager extends RollingFileManager { LOGGER.error("The fileName attribute must not be specified with the DirectWriteRolloverStrategy"); return null; } - return narrow(RollingRandomAccessFileManager.class, getManager(fileName, new FactoryData(filePattern, isAppend, + final String name = fileName == null ? filePattern : fileName; + return narrow(RollingRandomAccessFileManager.class, getManager(name, new FactoryData(fileName, filePattern, isAppend, immediateFlush, bufferSize, policy, strategy, advertiseURI, layout, filePermissions, fileOwner, fileGroup, configuration), FACTORY)); } @@ -128,6 +129,12 @@ public class RollingRandomAccessFileManager extends RollingFileManager { @Override protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) { try { + if (randomAccessFile == null) { + String fileName = getFileName(); + File file = new File(fileName); + FileUtils.makeParentDirs(file); + createFileAfterRollover(fileName); + } randomAccessFile.write(bytes, offset, length); size += length; } catch (final IOException ex) { @@ -138,7 +145,11 @@ public class RollingRandomAccessFileManager extends RollingFileManager { @Override protected void createFileAfterRollover() throws IOException { - this.randomAccessFile = new RandomAccessFile(getFileName(), "rw"); + createFileAfterRollover(getFileName()); + } + + private void createFileAfterRollover(String fileName) throws IOException { + this.randomAccessFile = new RandomAccessFile(fileName, "rw"); if (isAppend()) { randomAccessFile.seek(randomAccessFile.length()); } @@ -187,45 +198,52 @@ public class RollingRandomAccessFileManager extends RollingFileManager { */ @Override public RollingRandomAccessFileManager createManager(final String name, final FactoryData data) { - final File file = new File(name); - - if (!data.append) { - file.delete(); - } - final long size = data.append ? file.length() : 0; - final long time = file.exists() ? file.lastModified() : System.currentTimeMillis(); - - final boolean writeHeader = !data.append || !file.exists(); + File file = null; + long size = 0; + long time = System.currentTimeMillis(); RandomAccessFile raf = null; - try { - FileUtils.makeParentDirs(file); - raf = new RandomAccessFile(name, "rw"); - if (data.append) { - final long length = raf.length(); - LOGGER.trace("RandomAccessFile {} seek to {}", name, length); - raf.seek(length); - } else { - LOGGER.trace("RandomAccessFile {} set length to 0", name); - raf.setLength(0); + if (data.fileName != null) { + file = new File(name); + + if (!data.append) { + file.delete(); } - final RollingRandomAccessFileManager rrm = new RollingRandomAccessFileManager(data.getLoggerContext(), raf, name, data.pattern, - NullOutputStream.getInstance(), data.append, data.immediateFlush, data.bufferSize, size, time, data.policy, - data.strategy, data.advertiseURI, data.layout, data.filePermissions, data.fileOwner, data.fileGroup, writeHeader); - if (rrm.isAttributeViewEnabled()) { - rrm.defineAttributeView(file.toPath()); + size = data.append ? file.length() : 0; + if (file.exists()) { + time = file.lastModified(); } - return rrm; - } catch (final IOException ex) { - LOGGER.error("Cannot access RandomAccessFile " + ex, ex); - if (raf != null) { - try { - raf.close(); - } catch (final IOException e) { - LOGGER.error("Cannot close RandomAccessFile {}", name, e); + try { + FileUtils.makeParentDirs(file); + raf = new RandomAccessFile(name, "rw"); + if (data.append) { + final long length = raf.length(); + LOGGER.trace("RandomAccessFile {} seek to {}", name, length); + raf.seek(length); + } else { + LOGGER.trace("RandomAccessFile {} set length to 0", name); + raf.setLength(0); + } + } catch (final IOException ex) { + LOGGER.error("Cannot access RandomAccessFile " + ex, ex); + if (raf != null) { + try { + raf.close(); + } catch (final IOException e) { + LOGGER.error("Cannot close RandomAccessFile {}", name, e); + } } + return null; } } - return null; + final boolean writeHeader = !data.append || file == null || !file.exists(); + + final RollingRandomAccessFileManager rrm = new RollingRandomAccessFileManager(data.getLoggerContext(), raf, name, data.pattern, + NullOutputStream.getInstance(), data.append, data.immediateFlush, data.bufferSize, size, time, data.policy, + data.strategy, data.advertiseURI, data.layout, data.filePermissions, data.fileOwner, data.fileGroup, writeHeader); + if (rrm.isAttributeViewEnabled()) { + rrm.defineAttributeView(file.toPath()); + } + return rrm; } } @@ -233,6 +251,7 @@ public class RollingRandomAccessFileManager extends RollingFileManager { * Factory data. */ private static class FactoryData extends ConfigurationFactoryData { + private final String fileName; private final String pattern; private final boolean append; private final boolean immediateFlush; @@ -248,6 +267,7 @@ public class RollingRandomAccessFileManager extends RollingFileManager { /** * Create the data for the factory. * + * @param fileName The file name. * @param pattern The pattern. * @param append The append flag. * @param immediateFlush @@ -261,12 +281,13 @@ public class RollingRandomAccessFileManager extends RollingFileManager { * @param fileGroup File group * @param configuration */ - public FactoryData(final String pattern, final boolean append, final boolean immediateFlush, + public FactoryData(final String fileName, final String pattern, final boolean append, final boolean immediateFlush, final int bufferSize, final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI, final Layout<? extends Serializable> layout, final String filePermissions, final String fileOwner, final String fileGroup, final Configuration configuration) { super(configuration); + this.fileName = fileName; this.pattern = pattern; this.append = append; this.immediateFlush = immediateFlush; http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0b37ee74/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java new file mode 100644 index 0000000..3aba52e --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingRandomAppenderDirectWriteTest.java @@ -0,0 +1,66 @@ +/* + * 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 org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.junit.LoggerContextRule; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import static org.apache.logging.log4j.hamcrest.Descriptors.that; +import static org.apache.logging.log4j.hamcrest.FileMatchers.hasName; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.hasItemInArray; +import static org.junit.Assert.*; + +/** + * + */ +public class RollingRandomAppenderDirectWriteTest { + + private static final String CONFIG = "log4j-rolling-random-direct.xml"; + + private static final String DIR = "target/rolling-random-direct"; + + public static LoggerContextRule loggerContextRule = LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG); + + @Rule + public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR); + + private Logger logger; + + @Before + public void setUp() throws Exception { + this.logger = loggerContextRule.getLogger(RollingRandomAppenderDirectWriteTest.class.getName()); + } + + @Test + public void testAppender() throws Exception { + for (int i=0; i < 100; ++i) { + logger.debug("This is test message number " + i); + } + Thread.sleep(50); + final File dir = new File(DIR); + assertTrue("Directory not created", dir.exists() && dir.listFiles().length > 0); + final File[] files = dir.listFiles(); + assertNotNull(files); + assertThat(files, hasItemInArray(that(hasName(that(endsWith(".gz")))))); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0b37ee74/log4j-core/src/test/resources/log4j-rolling-random-direct.xml ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/resources/log4j-rolling-random-direct.xml b/log4j-core/src/test/resources/log4j-rolling-random-direct.xml new file mode 100644 index 0000000..4be5b62 --- /dev/null +++ b/log4j-core/src/test/resources/log4j-rolling-random-direct.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. + +--> +<Configuration status="WARN" name="XMLConfigTest"> + <Properties> + <Property name="logDir">target/rolling-random-direct</Property> + </Properties> + <ThresholdFilter level="debug"/> + + <Appenders> + <Console name="STDOUT"> + <PatternLayout pattern="%m%n"/> + </Console> + <RollingRandomAccessFile name="RollingFile" filePattern="${logDir}/test1-%d{MM-dd-yy-HH-mm}-%i.log.gz"> + <PatternLayout> + <Pattern>%d %p %C{1.} [%t] %m%n</Pattern> + </PatternLayout> + <Policies> + <TimeBasedTriggeringPolicy /> + <SizeBasedTriggeringPolicy size="500" /> + </Policies> + </RollingRandomAccessFile> + </Appenders> + + <Loggers> + <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false"> + <AppenderRef ref="RollingFile"/> + </Logger>> + + <Root level="error"> + <AppenderRef ref="STDOUT"/> + </Root> + </Loggers> + +</Configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0b37ee74/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 79e9177..12f4938 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -31,6 +31,9 @@ - "remove" - Removed --> <release version="2.9.0" date="2017-MM-DD" description="GA Release 2.9.0"> + <action issue="LOG4J2-1928" dev="rgoers" type="update"> + Add support for DirectWriteRolloverStrategy to RollingRandomAcessFileAppender. + </action> <action issue="LOG4J2-1833" dev="rgoers" type="fix"> Prevent NullPointerException when a file name is specified with the DirectWriteRolloverStrategy. </action>
