All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.log4j.rolling.RollingFileAppender Maven / Gradle / Ivy

Go to download

Pax Logging backend implementation based on Apache Log4J. It provides Log4J specific implementation of PaxLoggingService interface and Log4J specific configuration methods. Users may customize Log4J behaviour (appenders, layouts) by creating fragment attached to this bundle.

There is a newer version: 2.0.19
Show newest version
/*
 * 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.rolling;

import org.apache.log4j.Appender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.rolling.helper.Action;
import org.apache.log4j.spi.ErrorHandler;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.OptionHandler;
import org.apache.log4j.xml.UnrecognizedElementHandler;
import org.w3c.dom.Element;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Properties;


/**
 * RollingFileAppender extends {@link FileAppender} to backup the log files
 * depending on {@link RollingPolicy} and {@link TriggeringPolicy}.
 *
 * To be of any use, a RollingFileAppender instance must have both
 * a RollingPolicy and a TriggeringPolicy set up.
 * However, if its RollingPolicy also implements the
 * TriggeringPolicy interface, then only the former needs to be
 * set up. For example, {@link TimeBasedRollingPolicy} acts both as a
 * RollingPolicy and a TriggeringPolicy.
 *
 * RollingFileAppender can be configured programattically or
 * using {@link org.apache.log4j.extras.DOMConfigurator} or
 * {@link org.apache.log4j.xml.DOMConfigurator} in log4j 1.2.15 or later. Here is a sample
 * configration file:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration>

<log4j:configuration debug="true">

  <appender name="ROLL" class="org.apache.log4j.rolling.RollingFileAppender">
    <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
      <param name="FileNamePattern" value="/wombat/foo.%d{yyyy-MM}.gz"/>
    </rollingPolicy>

    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%c{1} - %m%n"/>
    </layout>
  </appender>

  <root">
    <appender-ref ref="ROLL"/>
  </root>

</log4j:configuration>
* This configuration file specifies a monthly rollover schedule including * automatic compression of the archived files. See * {@link TimeBasedRollingPolicy} for more details. * * @author Heinz Richter * @author Ceki Gülcü * @since 1.3 * */ public final class RollingFileAppender extends FileAppender implements UnrecognizedElementHandler { /** * Triggering policy. */ private TriggeringPolicy triggeringPolicy; /** * Rolling policy. */ private RollingPolicy rollingPolicy; /** * Length of current active log file. */ private long fileLength = 0; /** * Asynchronous action (like compression) from previous rollover. */ private Action lastRolloverAsyncAction = null; /** * Construct a new instance. */ public RollingFileAppender() { } /** * Prepare instance of use. */ public void activateOptions() { if (rollingPolicy == null) { LogLog.warn( "Please set a rolling policy for the RollingFileAppender named '" + getName() + "'"); return; } // // if no explicit triggering policy and rolling policy is both. // if ( (triggeringPolicy == null) && rollingPolicy instanceof TriggeringPolicy) { triggeringPolicy = (TriggeringPolicy) rollingPolicy; } if (triggeringPolicy == null) { LogLog.warn( "Please set a TriggeringPolicy for the RollingFileAppender named '" + getName() + "'"); return; } Exception exception = null; synchronized (this) { triggeringPolicy.activateOptions(); rollingPolicy.activateOptions(); try { RolloverDescription rollover = rollingPolicy.initialize(getFile(), getAppend()); if (rollover != null) { Action syncAction = rollover.getSynchronous(); if (syncAction != null) { syncAction.execute(); } setFile(rollover.getActiveFileName()); setAppend(rollover.getAppend()); lastRolloverAsyncAction = rollover.getAsynchronous(); if (lastRolloverAsyncAction != null) { Thread runner = new Thread(lastRolloverAsyncAction); runner.start(); } } File activeFile = new File(getFile()); if (getAppend()) { fileLength = activeFile.length(); } else { fileLength = 0; } super.activateOptions(); } catch (Exception ex) { exception = ex; } } if (exception != null) { LogLog.warn( "Exception while initializing RollingFileAppender named '" + getName() + "'", exception); } } private QuietWriter createQuietWriter(final Writer writer) { ErrorHandler handler = errorHandler; if (handler == null) { handler = new DefaultErrorHandler(this); } return new QuietWriter(writer, handler); } /** Implements the usual roll over behaviour.

If MaxBackupIndex is positive, then files {File.1, ..., File.MaxBackupIndex -1} are renamed to {File.2, ..., File.MaxBackupIndex}. Moreover, File is renamed File.1 and closed. A new File is created to receive further log output.

If MaxBackupIndex is equal to zero, then the File is truncated with no backup files created. * @return true if rollover performed. */ public boolean rollover() { // // can't roll without a policy // if (rollingPolicy != null) { Exception exception = null; synchronized (this) { // // if a previous async task is still running //} if (lastRolloverAsyncAction != null) { // // block until complete // lastRolloverAsyncAction.close(); // // or don't block and return to rollover later // //if (!lastRolloverAsyncAction.isComplete()) return false; } try { RolloverDescription rollover = rollingPolicy.rollover(getFile()); if (rollover != null) { if (rollover.getActiveFileName().equals(getFile())) { closeWriter(); boolean success = true; if (rollover.getSynchronous() != null) { success = false; try { success = rollover.getSynchronous().execute(); } catch (Exception ex) { exception = ex; } } if (success) { if (rollover.getAppend()) { fileLength = new File(rollover.getActiveFileName()).length(); } else { fileLength = 0; } if (rollover.getAsynchronous() != null) { lastRolloverAsyncAction = rollover.getAsynchronous(); new Thread(lastRolloverAsyncAction).start(); } setFile( rollover.getActiveFileName(), rollover.getAppend(), bufferedIO, bufferSize); } else { setFile( rollover.getActiveFileName(), true, bufferedIO, bufferSize); if (exception == null) { LogLog.warn("Failure in post-close rollover action"); } else { LogLog.warn( "Exception in post-close rollover action", exception); } } } else { Writer newWriter = createWriter( createFileOutputStream( rollover.getActiveFileName(), rollover.getAppend())); closeWriter(); setFile(rollover.getActiveFileName()); this.qw = createQuietWriter(newWriter); boolean success = true; if (rollover.getSynchronous() != null) { success = false; try { success = rollover.getSynchronous().execute(); } catch (Exception ex) { exception = ex; } } if (success) { if (rollover.getAppend()) { fileLength = new File(rollover.getActiveFileName()).length(); } else { fileLength = 0; } if (rollover.getAsynchronous() != null) { lastRolloverAsyncAction = rollover.getAsynchronous(); new Thread(lastRolloverAsyncAction).start(); } } writeHeader(); } return true; } } catch (Exception ex) { exception = ex; } } if (exception != null) { LogLog.warn( "Exception during rollover, rollover deferred.", exception); } } return false; } /** * Creates a new FileOutputStream of a new log file, possibly creating first all the needed parent directories * * @param newFileName Filename of new log file to be created * @param append If file should be appended * @return newly created FileOutputStream * @throws FileNotFoundException if creating log file or parent directories was unsuccessful */ private FileOutputStream createFileOutputStream(String newFileName, boolean append) throws FileNotFoundException { try { // // attempt to create file // return new FileOutputStream(newFileName, 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(newFileName).getParent(); if (parentName != null) { File parentDir = new File(parentName); if (!parentDir.exists() && parentDir.mkdirs()) { return new FileOutputStream(newFileName, append); } else { throw ex; } } else { throw ex; } } } /** * {@inheritDoc} */ protected void subAppend(final LoggingEvent event) { // The rollover check must precede actual writing. This is the // only correct behavior for time driven triggers. AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { if ( triggeringPolicy.isTriggeringEvent( RollingFileAppender.this, event, getFile(), getFileLength())) { // // wrap rollover request in try block since // rollover may fail in case read access to directory // is not provided. However appender should still be in good // condition and the append should still happen. try { rollover(); } catch (Exception ex) { LogLog.warn("Exception during rollover attempt.", ex); } } return null; } }); super.subAppend(event); } /** * Get rolling policy. * @return rolling policy. */ public RollingPolicy getRollingPolicy() { return rollingPolicy; } /** * Get triggering policy. * @return triggering policy. */ public TriggeringPolicy getTriggeringPolicy() { return triggeringPolicy; } /** * Sets the rolling policy. * @param policy rolling policy. */ public void setRollingPolicy(final RollingPolicy policy) { rollingPolicy = policy; } /** * Set triggering policy. * @param policy triggering policy. */ public void setTriggeringPolicy(final TriggeringPolicy policy) { triggeringPolicy = policy; } /** * Close appender. Waits for any asynchronous file compression actions to be completed. */ public void close() { synchronized (this) { if (lastRolloverAsyncAction != null) { lastRolloverAsyncAction.close(); } } super.close(); } /** Returns an OutputStreamWriter when passed an OutputStream. The encoding used will depend on the value of the encoding property. If the encoding value is specified incorrectly the writer will be opened using the default system encoding (an error message will be printed to the loglog. @param os output stream, may not be null. @return new writer. */ protected OutputStreamWriter createWriter(final OutputStream os) { return super.createWriter(new CountingOutputStream(os, this)); } /** * Get byte length of current active log file. * @return byte length of current active log file. */ public long getFileLength() { return fileLength; } /** * Increments estimated byte length of current active log file. * @param increment additional bytes written to log file. */ public synchronized void incrementFileLength(int increment) { fileLength += increment; } /** * {@inheritDoc} */ public boolean parseUnrecognizedElement(final Element element, final Properties props) throws Exception { final String nodeName = element.getNodeName(); if ("rollingPolicy".equals(nodeName)) { OptionHandler rollingPolicy = org.apache.log4j.extras.DOMConfigurator.parseElement( element, props, RollingPolicy.class); if (rollingPolicy != null) { rollingPolicy.activateOptions(); this.setRollingPolicy((RollingPolicy) rollingPolicy); } return true; } if ("triggeringPolicy".equals(nodeName)) { OptionHandler triggerPolicy = org.apache.log4j.extras.DOMConfigurator.parseElement( element, props, TriggeringPolicy.class); if (triggerPolicy != null) { triggerPolicy.activateOptions(); this.setTriggeringPolicy((TriggeringPolicy) triggerPolicy); } return true; } return false; } /** * Wrapper for OutputStream that will report all write * operations back to this class for file length calculations. */ private static class CountingOutputStream extends OutputStream { /** * Wrapped output stream. */ private final OutputStream os; /** * Rolling file appender to inform of stream writes. */ private final RollingFileAppender rfa; /** * Constructor. * @param os output stream to wrap. * @param rfa rolling file appender to inform. */ public CountingOutputStream( final OutputStream os, final RollingFileAppender rfa) { this.os = os; this.rfa = rfa; } /** * {@inheritDoc} */ public void close() throws IOException { os.close(); } /** * {@inheritDoc} */ public void flush() throws IOException { os.flush(); } /** * {@inheritDoc} */ public void write(final byte[] b) throws IOException { os.write(b); rfa.incrementFileLength(b.length); } /** * {@inheritDoc} */ public void write(final byte[] b, final int off, final int len) throws IOException { os.write(b, off, len); rfa.incrementFileLength(len); } /** * {@inheritDoc} */ public void write(final int b) throws IOException { os.write(b); rfa.incrementFileLength(1); } } private static final class DefaultErrorHandler implements ErrorHandler { private final RollingFileAppender appender; public DefaultErrorHandler(final RollingFileAppender appender) { this.appender = appender; } /**@since 1.2*/ public void setLogger(Logger logger) { } public void error(String message, Exception ioe, int errorCode) { appender.close(); LogLog.error("IO failure for appender named "+ appender.getName(), ioe); } public void error(String message) { } /**@since 1.2*/ public void error(String message, Exception e, int errorCode, LoggingEvent event) { } /**@since 1.2*/ public void setAppender(Appender appender) { } /**@since 1.2*/ public void setBackupAppender(Appender appender) { } public void activateOptions() { } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy