You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2022/01/14 18:33:15 UTC
[logging-log4j2] 01/02: Add classes for BC.
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit c959ef9de38cc697c311f3efaaaac31fa302a7a0
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jan 14 13:32:17 2022 -0500
Add classes for BC.
---
.../main/java/org/apache/log4j/FileAppender.java | 306 +++++++++++++++++++++
.../java/org/apache/log4j/RollingFileAppender.java | 253 +++++++++++++++++
2 files changed, 559 insertions(+)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/FileAppender.java b/log4j-1.2-api/src/main/java/org/apache/log4j/FileAppender.java
new file mode 100644
index 0000000..40f46a9
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/FileAppender.java
@@ -0,0 +1,306 @@
+/*
+ * 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.log4j;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.Writer;
+
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.helpers.QuietWriter;
+import org.apache.log4j.spi.ErrorCode;
+
+/**
+ * FileAppender appends log events to a file.
+ * <p>
+ * Support for <code>java.io.Writer</code> and console appending has been deprecated and then removed. See the
+ * replacement solutions: {@link WriterAppender} and {@link ConsoleAppender}.
+ * </p>
+ */
+public class FileAppender extends WriterAppender {
+
+ /**
+ * Controls file truncatation. The default value for this variable is <code>true</code>, meaning that by default a
+ * <code>FileAppender</code> will append to an existing file and not truncate it.
+ * <p>
+ * This option is meaningful only if the FileAppender opens the file.
+ * </p>
+ */
+ protected boolean fileAppend = true;
+
+ /**
+ * The name of the log file.
+ */
+ protected String fileName = null;
+
+ /**
+ * Do we do bufferedIO?
+ */
+ protected boolean bufferedIO = false;
+
+ /**
+ * Determines the size of IO buffer be. Default is 8K.
+ */
+ protected int bufferSize = 8 * 1024;
+
+ /**
+ * The default constructor does not do anything.
+ */
+ public FileAppender() {
+ }
+
+ /**
+ * Constructs a FileAppender and open the file designated by <code>filename</code>. The opened filename will become the
+ * output destination for this appender.
+ * <p>
+ * The file will be appended to.
+ * </p>
+ */
+ public FileAppender(Layout layout, String filename) throws IOException {
+ this(layout, filename, true);
+ }
+
+ /**
+ * Constructs a FileAppender and open the file designated by <code>filename</code>. The opened filename will become the
+ * output destination for this appender.
+ * <p>
+ * If the <code>append</code> parameter is true, the file will be appended to. Otherwise, the file designated by
+ * <code>filename</code> will be truncated before being opened.
+ * </p>
+ */
+ public FileAppender(Layout layout, String filename, boolean append) throws IOException {
+ this.layout = layout;
+ this.setFile(filename, append, false, bufferSize);
+ }
+
+ /**
+ * Constructs a <code>FileAppender</code> and open the file designated by <code>filename</code>. The opened filename
+ * will become the output destination for this appender.
+ * <p>
+ * If the <code>append</code> parameter is true, the file will be appended to. Otherwise, the file designated by
+ * <code>filename</code> will be truncated before being opened.
+ * </p>
+ * <p>
+ * If the <code>bufferedIO</code> parameter is <code>true</code>, then buffered IO will be used to write to the output
+ * file.
+ * </p>
+ */
+ public FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO, int bufferSize) throws IOException {
+ this.layout = layout;
+ this.setFile(filename, append, bufferedIO, bufferSize);
+ }
+
+ /**
+ * If the value of <b>File</b> is not <code>null</code>, then {@link #setFile} is called with the values of <b>File</b>
+ * and <b>Append</b> properties.
+ *
+ * @since 0.8.1
+ */
+ public void activateOptions() {
+ if (fileName != null) {
+ try {
+ setFile(fileName, fileAppend, bufferedIO, bufferSize);
+ } catch (java.io.IOException e) {
+ errorHandler.error("setFile(" + fileName + "," + fileAppend + ") call failed.", e, ErrorCode.FILE_OPEN_FAILURE);
+ }
+ } else {
+ // LogLog.error("File option not set for appender ["+name+"].");
+ LogLog.warn("File option not set for appender [" + name + "].");
+ LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
+ }
+ }
+
+ /**
+ * Closes the previously opened file.
+ */
+ protected void closeFile() {
+ if (this.qw != null) {
+ try {
+ this.qw.close();
+ } catch (java.io.IOException e) {
+ if (e instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ // Exceptionally, it does not make sense to delegate to an
+ // ErrorHandler. Since a closed appender is basically dead.
+ LogLog.error("Could not close " + qw, e);
+ }
+ }
+ }
+
+ /**
+ * Returns the value of the <b>Append</b> option.
+ */
+ public boolean getAppend() {
+ return fileAppend;
+ }
+
+ /**
+ * Get the value of the <b>BufferedIO</b> option.
+ *
+ * <p>
+ * BufferedIO will significatnly increase performance on heavily loaded systems.
+ * </p>
+ */
+ public boolean getBufferedIO() {
+ return this.bufferedIO;
+ }
+
+ /**
+ * Get the size of the IO buffer.
+ */
+ public int getBufferSize() {
+ return this.bufferSize;
+ }
+
+ /** Returns the value of the <b>File</b> option. */
+ public String getFile() {
+ return fileName;
+ }
+
+ /**
+ * Close any previously opened file and call the parent's <code>reset</code>.
+ */
+ protected void reset() {
+ closeFile();
+ this.fileName = null;
+ super.reset();
+ }
+
+ /**
+ * The <b>Append</b> option takes a boolean value. It is set to <code>true</code> by default. If true, then
+ * <code>File</code> will be opened in append mode by {@link #setFile setFile} (see above). Otherwise, {@link #setFile
+ * setFile} will open <code>File</code> in truncate mode.
+ *
+ * <p>
+ * Note: Actual opening of the file is made when {@link #activateOptions} is called, not when the options are set.
+ * </p>
+ */
+ public void setAppend(boolean flag) {
+ fileAppend = flag;
+ }
+
+ /**
+ * The <b>BufferedIO</b> option takes a boolean value. It is set to <code>false</code> by default. If true, then
+ * <code>File</code> will be opened and the resulting {@link java.io.Writer} wrapped around a {@link BufferedWriter}.
+ *
+ * BufferedIO will significatnly increase performance on heavily loaded systems.
+ *
+ */
+ public void setBufferedIO(boolean bufferedIO) {
+ this.bufferedIO = bufferedIO;
+ if (bufferedIO) {
+ immediateFlush = false;
+ }
+ }
+
+ /**
+ * Set the size of the IO buffer.
+ */
+ public void setBufferSize(int bufferSize) {
+ this.bufferSize = bufferSize;
+ }
+
+ /**
+ * The <b>File</b> property takes a string value which should be the name of the file to append to.
+ * <p>
+ * <font color="#DD0044"><b>Note that the special values "System.out" or "System.err" are no longer honored.</b></font>
+ * </p>
+ * <p>
+ * Note: Actual opening of the file is made when {@link #activateOptions} is called, not when the options are set.
+ * </p>
+ */
+ public void setFile(String file) {
+ // Trim spaces from both ends. The users probably does not want
+ // trailing spaces in file names.
+ String val = file.trim();
+ fileName = val;
+ }
+
+ /**
+ * Sets and <i>opens</i> the file where the log output will go. The specified file must be writable.
+ * <p>
+ * If there was already an opened file, then the previous file is closed first.
+ * </p>
+ * <p>
+ * <b>Do not use this method directly. To configure a FileAppender or one of its subclasses, set its properties one by
+ * one and then call activateOptions.</b>
+ * </p>
+ *
+ * @param fileName The path to the log file.
+ * @param append If true will append to fileName. Otherwise will truncate fileName.
+ */
+ public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException {
+ LogLog.debug("setFile called: " + fileName + ", " + append);
+
+ // It does not make sense to have immediate flush and bufferedIO.
+ if (bufferedIO) {
+ setImmediateFlush(false);
+ }
+
+ reset();
+ FileOutputStream ostream = null;
+ try {
+ //
+ // attempt to create file
+ //
+ ostream = new FileOutputStream(fileName, append);
+ } catch (FileNotFoundException ex) {
+ //
+ // if parent directory does not exist then
+ // attempt to create it and try to create file
+ // see bug 9150
+ //
+ String parentName = new File(fileName).getParent();
+ if (parentName != null) {
+ File parentDir = new File(parentName);
+ if (!parentDir.exists() && parentDir.mkdirs()) {
+ ostream = new FileOutputStream(fileName, append);
+ } else {
+ throw ex;
+ }
+ } else {
+ throw ex;
+ }
+ }
+ Writer fw = createWriter(ostream);
+ if (bufferedIO) {
+ fw = new BufferedWriter(fw, bufferSize);
+ }
+ this.setQWForFiles(fw);
+ this.fileName = fileName;
+ this.fileAppend = append;
+ this.bufferedIO = bufferedIO;
+ this.bufferSize = bufferSize;
+ writeHeader();
+ LogLog.debug("setFile ended");
+ }
+
+ /**
+ * Sets the quiet writer being used.
+ *
+ * This method is overriden by {@link RollingFileAppender}.
+ */
+ protected void setQWForFiles(Writer writer) {
+ this.qw = new QuietWriter(writer, errorHandler);
+ }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/RollingFileAppender.java b/log4j-1.2-api/src/main/java/org/apache/log4j/RollingFileAppender.java
new file mode 100644
index 0000000..964c519
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/RollingFileAppender.java
@@ -0,0 +1,253 @@
+/*
+ * 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.log4j;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.io.File;
+import java.io.InterruptedIOException;
+
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.helpers.CountingQuietWriter;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * RollingFileAppender extends FileAppender to backup the log files when they reach a certain size.
+ *
+ * The log4j extras companion includes alternatives which should be considered for new deployments and which are
+ * discussed in the documentation for org.apache.log4j.rolling.RollingFileAppender.
+ */
+public class RollingFileAppender extends FileAppender {
+
+ /**
+ * The default maximum file size is 10MB.
+ */
+ protected long maxFileSize = 10 * 1024 * 1024;
+
+ /**
+ * There is one backup file by default.
+ */
+ protected int maxBackupIndex = 1;
+
+ private long nextRollover = 0;
+
+ /**
+ * The default constructor simply calls its {@link FileAppender#FileAppender parents constructor}.
+ */
+ public RollingFileAppender() {
+ super();
+ }
+
+ /**
+ * Constructs a RollingFileAppender and open the file designated by <code>filename</code>. The opened filename will
+ * become the ouput destination for this appender.
+ *
+ * <p>
+ * If the <code>append</code> parameter is true, the file will be appended to. Otherwise, the file desginated by
+ * <code>filename</code> will be truncated before being opened.
+ * </p>
+ */
+ public RollingFileAppender(Layout layout, String filename, boolean append) throws IOException {
+ super(layout, filename, append);
+ }
+
+ /**
+ * Constructs a FileAppender and open the file designated by <code>filename</code>. The opened filename will become the
+ * output destination for this appender.
+ *
+ * <p>
+ * The file will be appended to.
+ * </p>
+ */
+ public RollingFileAppender(Layout layout, String filename) throws IOException {
+ super(layout, filename);
+ }
+
+ /**
+ * Gets the value of the <b>MaxBackupIndex</b> option.
+ */
+ public int getMaxBackupIndex() {
+ return maxBackupIndex;
+ }
+
+ /**
+ * Gets the maximum size that the output file is allowed to reach before being rolled over to backup files.
+ *
+ * @since 1.1
+ */
+ public long getMaximumFileSize() {
+ return maxFileSize;
+ }
+
+ /**
+ * Implements the usual roll over behaviour.
+ * <p>
+ * If <code>MaxBackupIndex</code> is positive, then files {<code>File.1</code>, ...,
+ * <code>File.MaxBackupIndex -1</code>} are renamed to {<code>File.2</code>, ..., <code>File.MaxBackupIndex</code>}.
+ * Moreover, <code>File</code> is renamed <code>File.1</code> and closed. A new <code>File</code> is created to receive
+ * further log output.
+ * </p>
+ * <p>
+ * If <code>MaxBackupIndex</code> is equal to zero, then the <code>File</code> is truncated with no backup files
+ * created.
+ * </p>
+ */
+ public // synchronization not necessary since doAppend is alreasy synched
+ void rollOver() {
+ File target;
+ File file;
+
+ if (qw != null) {
+ long size = ((CountingQuietWriter) qw).getCount();
+ LogLog.debug("rolling over count=" + size);
+ // if operation fails, do not roll again until
+ // maxFileSize more bytes are written
+ nextRollover = size + maxFileSize;
+ }
+ LogLog.debug("maxBackupIndex=" + maxBackupIndex);
+
+ boolean renameSucceeded = true;
+ // If maxBackups <= 0, then there is no file renaming to be done.
+ if (maxBackupIndex > 0) {
+ // Delete the oldest file, to keep Windows happy.
+ file = new File(fileName + '.' + maxBackupIndex);
+ if (file.exists())
+ renameSucceeded = file.delete();
+
+ // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
+ for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
+ file = new File(fileName + "." + i);
+ if (file.exists()) {
+ target = new File(fileName + '.' + (i + 1));
+ LogLog.debug("Renaming file " + file + " to " + target);
+ renameSucceeded = file.renameTo(target);
+ }
+ }
+
+ if (renameSucceeded) {
+ // Rename fileName to fileName.1
+ target = new File(fileName + "." + 1);
+
+ this.closeFile(); // keep windows happy.
+
+ file = new File(fileName);
+ LogLog.debug("Renaming file " + file + " to " + target);
+ renameSucceeded = file.renameTo(target);
+ //
+ // if file rename failed, reopen file with append = true
+ //
+ if (!renameSucceeded) {
+ try {
+ this.setFile(fileName, true, bufferedIO, bufferSize);
+ } catch (IOException e) {
+ if (e instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ LogLog.error("setFile(" + fileName + ", true) call failed.", e);
+ }
+ }
+ }
+ }
+
+ //
+ // if all renames were successful, then
+ //
+ if (renameSucceeded) {
+ try {
+ // This will also close the file. This is OK since multiple
+ // close operations are safe.
+ this.setFile(fileName, false, bufferedIO, bufferSize);
+ nextRollover = 0;
+ } catch (IOException e) {
+ if (e instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ LogLog.error("setFile(" + fileName + ", false) call failed.", e);
+ }
+ }
+ }
+
+ public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException {
+ super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
+ if (append) {
+ File f = new File(fileName);
+ ((CountingQuietWriter) qw).setCount(f.length());
+ }
+ }
+
+ /**
+ * Sets the maximum number of backup files to keep around.
+ *
+ * <p>
+ * The <b>MaxBackupIndex</b> option determines how many backup files are kept before the oldest is erased. This option
+ * takes a positive integer value. If set to zero, then there will be no backup files and the log file will be truncated
+ * when it reaches <code>MaxFileSize</code>.
+ * </p>
+ */
+ public void setMaxBackupIndex(int maxBackups) {
+ this.maxBackupIndex = maxBackups;
+ }
+
+ /**
+ * Sets the maximum size that the output file is allowed to reach before being rolled over to backup files.
+ *
+ * <p>
+ * This method is equivalent to {@link #setMaxFileSize} except that it is required for differentiating the setter taking
+ * a <code>long</code> argument from the setter taking a <code>String</code> argument by the JavaBeans
+ * {@link java.beans.Introspector Introspector}.
+ * </p>
+ *
+ * @see #setMaxFileSize(String)
+ */
+ public void setMaximumFileSize(long maxFileSize) {
+ this.maxFileSize = maxFileSize;
+ }
+
+ /**
+ * Sets the maximum size that the output file is allowed to reach before being rolled over to backup files.
+ *
+ * <p>
+ * In configuration files, the <b>MaxFileSize</b> option takes an long integer in the range 0 - 2^63. You can specify
+ * the value with the suffixes "KB", "MB" or "GB" so that the integer is interpreted being expressed respectively in
+ * kilobytes, megabytes or gigabytes. For example, the value "10KB" will be interpreted as 10240.
+ * </p>
+ */
+ public void setMaxFileSize(String value) {
+ maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
+ }
+
+ protected void setQWForFiles(Writer writer) {
+ this.qw = new CountingQuietWriter(writer, errorHandler);
+ }
+
+ /**
+ * This method differentiates RollingFileAppender from its super class.
+ *
+ * @since 0.9.0
+ */
+ protected void subAppend(LoggingEvent event) {
+ super.subAppend(event);
+ if (fileName != null && qw != null) {
+ long size = ((CountingQuietWriter) qw).getCount();
+ if (size >= maxFileSize && size >= nextRollover) {
+ rollOver();
+ }
+ }
+ }
+}