blob: 92c133688c66c3730801db9658834542086e40c2 [file] [log] [blame]
/*
* 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 org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.FileManager;
import org.apache.logging.log4j.core.appender.ManagerFactory;
import org.apache.logging.log4j.core.appender.rolling.helper.Action;
import org.apache.logging.log4j.core.appender.rolling.helper.ActionBase;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.Semaphore;
/**
* The Rolling File Manager.
*/
public class RollingFileManager extends FileManager {
private static ManagerFactory factory = new RollingFileManagerFactory();
private long size;
private long initialTime;
private PatternProcessor processor;
private final Semaphore semaphore = new Semaphore(1);
protected RollingFileManager(String fileName, String pattern, OutputStream os, boolean append, long size,
long time) {
super(fileName, os, append, false);
this.size = size;
this.initialTime = time;
processor = new PatternProcessor(pattern);
}
/**
* Return 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.
* @return A RollingFileManager.
*/
public static RollingFileManager getFileManager(String fileName, String pattern, boolean append,
boolean bufferedIO) {
return (RollingFileManager) getManager(fileName, factory, new FactoryData(pattern, append,
bufferedIO));
}
protected synchronized void write(byte[] bytes, int offset, int length) {
size += length;
super.write(bytes, offset, length);
}
/**
* Return the current size of the file.
* @return The size of the file in bytes.
*/
public long getFileSize() {
return size;
}
/**
* Return the time the file was created.
* @return The time the file was created.
*/
public long getFileTime() {
return initialTime;
}
/**
* Determine if a rollover should occur.
* @param event The LogEvent.
* @param policy The TriggeringPolicy.
* @param strategy The RolloverStrategy.
*/
public synchronized void checkRollover(LogEvent event, TriggeringPolicy policy, RolloverStrategy strategy) {
if (policy.isTriggeringEvent(event) && rollover(strategy)) {
try {
size = 0;
initialTime = System.currentTimeMillis();
OutputStream os = new FileOutputStream(getFileName(), isAppend());
setOutputStream(os);
} catch (FileNotFoundException ex) {
LOGGER.error("FileManager (" + getFileName() + ") " + ex);
}
}
}
/**
* Return the pattern processor.
* @return The PatternProcessor.
*/
public PatternProcessor getProcessor() {
return processor;
}
private boolean rollover(RolloverStrategy strategy) {
try {
// Block until the asynchronous operation is completed.
semaphore.acquire();
} catch (InterruptedException ie) {
LOGGER.error("Thread interrupted while attempting to check rollover", ie);
return false;
}
boolean success = false;
Thread thread = null;
try {
RolloverDescription descriptor = strategy.rollover(this);
if (descriptor != null) {
close();
if (descriptor.getSynchronous() != null) {
try {
success = descriptor.getSynchronous().execute();
} catch (Exception ex) {
LOGGER.error("Error in synchronous task", ex);
}
}
if (success) {
thread = new Thread(new AsyncAction(descriptor.getAsynchronous(), this));
thread.start();
}
return true;
}
return false;
} finally {
if (thread == null) {
semaphore.release();
}
}
}
/**
* Performs actions asynchronously.
*/
private static class AsyncAction extends ActionBase {
private final Action action;
private final RollingFileManager manager;
/**
* Constructor.
* @param act The action to perform.
* @param manager The manager.
*/
public AsyncAction(Action act, RollingFileManager manager) {
this.action = act;
this.manager = manager;
}
/**
* Perform 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.
*/
public boolean execute() throws IOException {
try {
return action.execute();
} finally {
manager.semaphore.release();
}
}
/**
* Cancels the action if not already initialized or waits till completion.
*/
public void close() {
action.close();
}
/**
* Determines if action has been completed.
*
* @return true if action is complete.
*/
public boolean isComplete() {
return action.isComplete();
}
}
/**
* Factory data.
*/
private static class FactoryData {
private String pattern;
private boolean append;
private boolean bufferedIO;
/**
* Create the data for the factory.
* @param pattern The pattern.
* @param append The append flag.
* @param bufferedIO The bufferedIO flag.
*/
public FactoryData(String pattern, boolean append, boolean bufferedIO) {
this.pattern = pattern;
this.append = append;
this.bufferedIO = bufferedIO;
}
}
/**
* Factory to create a RollingFileManager.
*/
private static class RollingFileManagerFactory implements ManagerFactory<RollingFileManager, FactoryData> {
/**
* Create the RollingFileManager.
* @param name The name of the entity to manage.
* @param data The data required to create the entity.
* @return a RollingFileManager.
*/
public RollingFileManager createManager(String name, FactoryData data) {
File file = new File(name);
final File parent = file.getParentFile();
if (null != parent && !parent.exists()) {
parent.mkdirs();
}
try {
file.createNewFile();
} catch (IOException ioe) {
LOGGER.error("Unable to create file " + name, ioe);
return null;
}
long size = data.append ? file.length() : 0;
long time = file.lastModified();
OutputStream os;
try {
os = new FileOutputStream(name, data.append);
if (data.bufferedIO) {
os = new BufferedOutputStream(os);
}
return new RollingFileManager(name, data.pattern, os, data.append, size, time);
} catch (FileNotFoundException ex) {
LOGGER.error("FileManager (" + name + ") " + ex);
}
return null;
}
}
}