下面列出了org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy#org.apache.logging.log4j.core.appender.rolling.action.Action 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static DefaultRolloverStrategy createStrategyByAction(String loggerName, String loggerDir) {
IfFileName ifFileName = IfFileName.createNameCondition(null, loggerName + "\\.\\d{4}-\\d{2}-\\d{2}.*");
IfLastModified ifLastModified = IfLastModified.createAgeCondition(Duration.parse("1d"));
DeleteAction deleteAction = DeleteAction.createDeleteAction(loggerDir, false, 1, false, null,
new PathCondition[] {ifLastModified, ifFileName}, null, config);
Action[] actions = new Action[] {deleteAction};
return DefaultRolloverStrategy.createStrategy("7", "1", null, null, actions, false, config);
}
/**
* Perform the rollover.
* @param manager The RollingFileManager name for current active log file.
* @return A RolloverDescription.
* @throws SecurityException if an error occurs.
*/
@Override
public RolloverDescription rollover(final RollingFileManager manager) throws SecurityException {
if (maxIndex < 0) {
return null;
}
final long start = System.nanoTime();
final int fileIndex = purge(minIndex, maxIndex, manager);
if (fileIndex < 0) {
return null;
}
if (LOGGER.isTraceEnabled()) {
final double duration = (System.nanoTime() - start) / (1000.0 * 1000.0 * 1000.0);
LOGGER.trace("DefaultRolloverStrategy.purge() took {} seconds", duration);
}
final StringBuilder buf = new StringBuilder(255);
manager.getPatternProcessor().formatFileName(subst, buf, fileIndex);
final String currentFileName = manager.getFileName();
String renameTo = buf.toString();
final String compressedName = renameTo;
Action compressAction = null;
if (renameTo.endsWith(EXT_GZIP)) {
renameTo = renameTo.substring(0, renameTo.length() - EXT_GZIP.length());
compressAction = new GzCompressAction(new File(renameTo), new File(compressedName), true);
} else if (renameTo.endsWith(EXT_ZIP)) {
renameTo = renameTo.substring(0, renameTo.length() - EXT_ZIP.length());
compressAction = new ZipCompressAction(new File(renameTo), new File(compressedName), true,
compressionLevel);
}
final FileRenameAction renameAction =
new FileRenameAction(new File(currentFileName), new File(renameTo), false);
return new RolloverDescriptionImpl(currentFileName, false, renameAction, compressAction);
}
/**
* Constructs a new instance.
*
* @param maxFiles The maximum number of files that match the date portion of the pattern to keep.
* @param customActions custom actions to perform asynchronously after rollover
* @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
* @param tempCompressedFilePatternString File pattern of the working file
* used during compression, if null no temporary file are used
*/
protected DirectWriteRolloverStrategy(final int maxFiles, final int compressionLevel,
final StrSubstitutor strSubstitutor, final Action[] customActions,
final boolean stopCustomActionsOnError, final String tempCompressedFilePatternString) {
super(strSubstitutor);
this.maxFiles = maxFiles;
this.compressionLevel = compressionLevel;
this.stopCustomActionsOnError = stopCustomActionsOnError;
this.customActions = customActions == null ? Collections.<Action> emptyList() : Arrays.asList(customActions);
this.tempCompressedFilePattern =
tempCompressedFilePatternString != null ? new PatternProcessor(tempCompressedFilePatternString) : null;
}
protected Action merge(final Action compressAction, final List<Action> custom, final boolean stopOnError) {
if (custom.isEmpty()) {
return compressAction;
}
if (compressAction == null) {
return new CompositeAction(custom, stopOnError);
}
final List<Action> all = new ArrayList<>();
all.add(compressAction);
all.addAll(custom);
return new CompositeAction(all, stopOnError);
}
/**
* Create new instance.
*
* @param activeFileName active log file name after rollover, may not be null.
* @param append true if active log file after rollover should be opened for appending.
* @param synchronous action to be completed after close of current active log file, may be null.
* @param asynchronous action to be completed after close of current active log file and
* before next rollover attempt.
*/
public RolloverDescriptionImpl(final String activeFileName, final boolean append, final Action synchronous,
final Action asynchronous) {
Objects.requireNonNull(activeFileName, "activeFileName");
this.append = append;
this.activeFileName = activeFileName;
this.synchronous = synchronous;
this.asynchronous = asynchronous;
}
/**
* Constructs a new instance.
*
* @param minIndex The minimum index.
* @param maxIndex The maximum index.
* @param customActions custom actions to perform asynchronously after rollover
* @param stopCustomActionsOnError whether to stop executing asynchronous actions if an error occurs
* @param tempCompressedFilePatternString File pattern of the working file
* used during compression, if null no temporary file are used
*/
protected DefaultRolloverStrategy(final int minIndex, final int maxIndex, final boolean useMax,
final int compressionLevel, final StrSubstitutor strSubstitutor, final Action[] customActions,
final boolean stopCustomActionsOnError, final String tempCompressedFilePatternString) {
super(strSubstitutor);
this.minIndex = minIndex;
this.maxIndex = maxIndex;
this.useMax = useMax;
this.compressionLevel = compressionLevel;
this.stopCustomActionsOnError = stopCustomActionsOnError;
this.customActions = customActions == null ? Collections.<Action> emptyList() : Arrays.asList(customActions);
this.tempCompressedFilePattern =
tempCompressedFilePatternString != null ? new PatternProcessor(tempCompressedFilePatternString) : null;
}
/**
* Purge and rename old log files in preparation for rollover. The newest file will have the smallest index, the
* oldest will have the highest.
*
* @param lowIndex low index
* @param highIndex high index. Logger file associated with high index will be deleted if needed.
* @param manager The RollingFileManager
* @return true if purge was successful and rollover should be attempted.
*/
private int purgeDescending(final int lowIndex, final int highIndex, final RollingFileManager manager) {
int suffixLength = 0;
final List<FileRenameAction> renames = new ArrayList<FileRenameAction>();
final StringBuilder buf = new StringBuilder();
// LOG4J2-531: directory scan & rollover must use same format
manager.getPatternProcessor().formatFileName(subst, buf, lowIndex);
String lowFilename = subst.replace(buf);
if (lowFilename.endsWith(EXT_GZIP)) {
suffixLength = EXT_GZIP.length();
} else if (lowFilename.endsWith(EXT_ZIP)) {
suffixLength = EXT_ZIP.length();
}
for (int i = lowIndex; i <= highIndex; i++) {
File toRename = new File(lowFilename);
boolean isBase = false;
if (suffixLength > 0) {
final File toRenameBase =
new File(lowFilename.substring(0, lowFilename.length() - suffixLength));
if (toRename.exists()) {
if (toRenameBase.exists()) {
LOGGER.debug("DefaultRolloverStrategy.purgeDescending deleting {} base of {}.", //
toRenameBase, toRename);
toRenameBase.delete();
}
} else {
toRename = toRenameBase;
isBase = true;
}
}
if (toRename.exists()) {
//
// if at upper index then
// attempt to delete last file
// if that fails then abandon purge
if (i == highIndex) {
LOGGER.debug("DefaultRolloverStrategy.purgeDescending deleting {} at high index {}: all slots full.", //
toRename, i);
if (!toRename.delete()) {
return -1;
}
break;
}
//
// if intermediate index
// add a rename action to the list
buf.setLength(0);
// LOG4J2-531: directory scan & rollover must use same format
manager.getPatternProcessor().formatFileName(subst, buf, i + 1);
final String highFilename = subst.replace(buf);
String renameTo = highFilename;
if (isBase) {
renameTo = highFilename.substring(0, highFilename.length() - suffixLength);
}
renames.add(new FileRenameAction(toRename, new File(renameTo), true));
lowFilename = highFilename;
} else {
break;
}
}
//
// work renames backwards
//
for (int i = renames.size() - 1; i >= 0; i--) {
final Action action = renames.get(i);
try {
LOGGER.debug("DefaultRolloverStrategy.purgeDescending executing {} of {}: {}", //
i, renames.size(), action);
if (!action.execute()) {
return -1;
}
} catch (final Exception ex) {
LOGGER.warn("Exception during purge in RollingFileAppender", ex);
return -1;
}
}
return lowIndex;
}
public void init() throws Exception {
String active = (String) this.systemParams.get(INIT_PROP_LOG_ACTIVE_FILE_OUTPUT);
if (StringUtils.isEmpty(active) || !active.equalsIgnoreCase("true")) {
return;
}
String appenderName = "ENTANDO";
String conversionPattern = (String) this.systemParams.get("log4jConversionPattern");
if (StringUtils.isBlank(conversionPattern)) {
conversionPattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} - %-5p - %c - %m%n";
}
String maxFileSize = (String) this.systemParams.get(INIT_PROP_LOG_FILE_SIZE);
if (StringUtils.isBlank(maxFileSize)) {
maxFileSize = "1MB"; //default size
} else {
long mega = new Long(maxFileSize) / KILOBYTE;
maxFileSize = mega + "KB";
}
String filePattern = (String) this.systemParams.get(INIT_PROP_LOG_FILE_PATTERN);
String filename = (String) this.systemParams.get(INIT_PROP_LOG_NAME);
int maxBackupIndex = Integer.parseInt((String) this.systemParams.get(INIT_PROP_LOG_FILES_COUNT));
String log4jLevelString = (String) this.systemParams.get(INIT_PROP_LOG_LEVEL);
if (StringUtils.isBlank(log4jLevelString)) {
log4jLevelString = "INFO"; //default level
}
Configurator.setRootLevel(Level.getLevel(log4jLevelString));
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
loggerContext.getRootLogger().setLevel(Level.getLevel(log4jLevelString));
Configurator.setAllLevels(loggerContext.getRootLogger().getName(), Level.getLevel(log4jLevelString));
Configuration configuration = loggerContext.getConfiguration();
RollingFileAppender fileAppender = (RollingFileAppender) configuration.getAppender(appenderName);
if (null == fileAppender) {
PathCondition[] pathConditions = new PathCondition[]{IfAccumulatedFileCount.createFileCountCondition(maxBackupIndex)};
String basePath = filePattern.substring(0, filePattern.lastIndexOf(File.separator));
DeleteAction deleteAction = DeleteAction.createDeleteAction(basePath, true, 1, false, null, pathConditions, null, configuration);
SizeBasedTriggeringPolicy policy = SizeBasedTriggeringPolicy.createPolicy(maxFileSize);
PatternLayout layout = PatternLayout.newBuilder().withPattern(conversionPattern).build();
DefaultRolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
.withConfig(configuration).withMax(String.valueOf(maxBackupIndex))
.withCustomActions(new Action[]{deleteAction}).build();
fileAppender = RollingFileAppender.newBuilder()
.withName(appenderName)
.setConfiguration(configuration)
.withLayout(layout)
.withFileName(filename)
.withFilePattern(filePattern)
.withPolicy(policy)
.withStrategy(strategy)
.build();
configuration.addAppender(fileAppender);
Configurator.setLevel(appenderName, Level.getLevel(log4jLevelString));
fileAppender.start();
}
AsyncAppender async = (AsyncAppender) loggerContext.getRootLogger().getAppenders().get("async");
if (null == async) {
AppenderRef ref = AppenderRef.createAppenderRef(appenderName, Level.getLevel(log4jLevelString), null);
async = AsyncAppender.newBuilder().setName("async")
.setConfiguration(configuration)
.setAppenderRefs(new AppenderRef[]{ref}).build();
configuration.addAppender(async);
loggerContext.getRootLogger().addAppender(async);
async.start();
}
loggerContext.updateLoggers();
}
public Action[] getCustomActions() {
return customActions;
}
public List<Action> getCustomActions() {
return customActions;
}
/**
* Performs the rollover.
*
* @param manager The RollingFileManager name for current active log file.
* @return A RolloverDescription.
* @throws SecurityException if an error occurs.
*/
@Override
public RolloverDescription rollover(final RollingFileManager manager) throws SecurityException {
LOGGER.debug("Rolling " + currentFileName);
if (maxFiles < 0) {
return null;
}
final long startNanos = System.nanoTime();
final int fileIndex = purge(manager);
if (LOGGER.isTraceEnabled()) {
final double durationMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos);
LOGGER.trace("DirectWriteRolloverStrategy.purge() took {} milliseconds", durationMillis);
}
Action compressAction = null;
final String sourceName = getCurrentFileName(manager);
String compressedName = sourceName;
currentFileName = null;
nextIndex = fileIndex + 1;
final FileExtension fileExtension = manager.getFileExtension();
if (fileExtension != null) {
compressedName += fileExtension.getExtension();
if (tempCompressedFilePattern != null) {
final StringBuilder buf = new StringBuilder();
tempCompressedFilePattern.formatFileName(strSubstitutor, buf, fileIndex);
final String tmpCompressedName = buf.toString();
final File tmpCompressedNameFile = new File(tmpCompressedName);
final File parentFile = tmpCompressedNameFile.getParentFile();
if (parentFile != null) {
parentFile.mkdirs();
}
compressAction = new CompositeAction(
Arrays.asList(fileExtension.createCompressAction(sourceName, tmpCompressedName,
true, compressionLevel),
new FileRenameAction(tmpCompressedNameFile,
new File(compressedName), true)),
true);
} else {
compressAction = fileExtension.createCompressAction(sourceName, compressedName,
true, compressionLevel);
}
}
if (compressAction != null && manager.isAttributeViewEnabled()) {
// Propagate posix attribute view to compressed file
// @formatter:off
final Action posixAttributeViewAction = PosixViewAttributeAction.newBuilder()
.setBasePath(compressedName)
.setFollowLinks(false)
.setMaxDepth(1)
.setPathConditions(new PathCondition[0])
.setSubst(getStrSubstitutor())
.setFilePermissions(manager.getFilePermissions())
.setFileOwner(manager.getFileOwner())
.setFileGroup(manager.getFileGroup())
.build();
// @formatter:on
compressAction = new CompositeAction(Arrays.asList(compressAction, posixAttributeViewAction), false);
}
final Action asyncAction = merge(compressAction, customActions, stopCustomActionsOnError);
return new RolloverDescriptionImpl(sourceName, false, null, asyncAction);
}
public Action[] getCustomActions() {
return customActions;
}
public List<Action> getCustomActions() {
return customActions;
}
/**
* Purges and renames old log files in preparation for rollover. The oldest file will have the smallest index, the
* newest the highest.
*
* @param lowIndex low index. Log file associated with low index will be deleted if needed.
* @param highIndex high index.
* @param manager The RollingFileManager
* @return true if purge was successful and rollover should be attempted.
*/
private int purgeAscending(final int lowIndex, final int highIndex, final RollingFileManager manager) {
final SortedMap<Integer, Path> eligibleFiles = getEligibleFiles(manager);
final int maxFiles = highIndex - lowIndex + 1;
boolean renameFiles = !eligibleFiles.isEmpty() && eligibleFiles.lastKey() >= maxIndex;
while (eligibleFiles.size() >= maxFiles) {
try {
LOGGER.debug("Eligible files: {}", eligibleFiles);
final Integer key = eligibleFiles.firstKey();
LOGGER.debug("Deleting {}", eligibleFiles.get(key).toFile().getAbsolutePath());
Files.delete(eligibleFiles.get(key));
eligibleFiles.remove(key);
renameFiles = true;
} catch (final IOException ioe) {
LOGGER.error("Unable to delete {}, {}", eligibleFiles.firstKey(), ioe.getMessage(), ioe);
break;
}
}
final StringBuilder buf = new StringBuilder();
if (renameFiles) {
for (final Map.Entry<Integer, Path> entry : eligibleFiles.entrySet()) {
buf.setLength(0);
// LOG4J2-531: directory scan & rollover must use same format
manager.getPatternProcessor().formatFileName(strSubstitutor, buf, entry.getKey() - 1);
final String currentName = entry.getValue().toFile().getName();
String renameTo = buf.toString();
final int suffixLength = suffixLength(renameTo);
if (suffixLength > 0 && suffixLength(currentName) == 0) {
renameTo = renameTo.substring(0, renameTo.length() - suffixLength);
}
final Action action = new FileRenameAction(entry.getValue().toFile(), new File(renameTo), true);
try {
LOGGER.debug("DefaultRolloverStrategy.purgeAscending executing {}", action);
if (!action.execute()) {
return -1;
}
} catch (final Exception ex) {
LOGGER.warn("Exception during purge in RollingFileAppender", ex);
return -1;
}
}
}
return eligibleFiles.size() > 0 ?
(eligibleFiles.lastKey() < highIndex ? eligibleFiles.lastKey() + 1 : highIndex) : lowIndex;
}
/**
* Purges and renames old log files in preparation for rollover. The newest file will have the smallest index, the
* oldest will have the highest.
*
* @param lowIndex low index
* @param highIndex high index. Log file associated with high index will be deleted if needed.
* @param manager The RollingFileManager
* @return true if purge was successful and rollover should be attempted.
*/
private int purgeDescending(final int lowIndex, final int highIndex, final RollingFileManager manager) {
// Retrieve the files in descending order, so the highest key will be first.
final SortedMap<Integer, Path> eligibleFiles = getEligibleFiles(manager, false);
final int maxFiles = highIndex - lowIndex + 1;
LOGGER.debug("Eligible files: {}", eligibleFiles);
while (eligibleFiles.size() >= maxFiles) {
try {
final Integer key = eligibleFiles.firstKey();
Files.delete(eligibleFiles.get(key));
eligibleFiles.remove(key);
} catch (final IOException ioe) {
LOGGER.error("Unable to delete {}, {}", eligibleFiles.firstKey(), ioe.getMessage(), ioe);
break;
}
}
final StringBuilder buf = new StringBuilder();
for (final Map.Entry<Integer, Path> entry : eligibleFiles.entrySet()) {
buf.setLength(0);
// LOG4J2-531: directory scan & rollover must use same format
manager.getPatternProcessor().formatFileName(strSubstitutor, buf, entry.getKey() + 1);
final String currentName = entry.getValue().toFile().getName();
String renameTo = buf.toString();
final int suffixLength = suffixLength(renameTo);
if (suffixLength > 0 && suffixLength(currentName) == 0) {
renameTo = renameTo.substring(0, renameTo.length() - suffixLength);
}
final Action action = new FileRenameAction(entry.getValue().toFile(), new File(renameTo), true);
try {
LOGGER.debug("DefaultRolloverStrategy.purgeDescending executing {}", action);
if (!action.execute()) {
return -1;
}
} catch (final Exception ex) {
LOGGER.warn("Exception during purge in RollingFileAppender", ex);
return -1;
}
}
return lowIndex;
}
/**
* Performs the rollover.
*
* @param manager The RollingFileManager name for current active log file.
* @return A RolloverDescription.
* @throws SecurityException if an error occurs.
*/
@Override
public RolloverDescription rollover(final RollingFileManager manager) throws SecurityException {
int fileIndex;
final StringBuilder buf = new StringBuilder(255);
if (minIndex == Integer.MIN_VALUE) {
final SortedMap<Integer, Path> eligibleFiles = getEligibleFiles(manager);
fileIndex = eligibleFiles.size() > 0 ? eligibleFiles.lastKey() + 1 : 1;
manager.getPatternProcessor().formatFileName(strSubstitutor, buf, fileIndex);
} else {
if (maxIndex < 0) {
return null;
}
final long startNanos = System.nanoTime();
fileIndex = purge(minIndex, maxIndex, manager);
if (fileIndex < 0) {
return null;
}
manager.getPatternProcessor().formatFileName(strSubstitutor, buf, fileIndex);
if (LOGGER.isTraceEnabled()) {
final double durationMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos);
LOGGER.trace("DefaultRolloverStrategy.purge() took {} milliseconds", durationMillis);
}
}
final String currentFileName = manager.getFileName();
String renameTo = buf.toString();
final String compressedName = renameTo;
Action compressAction = null;
final FileExtension fileExtension = manager.getFileExtension();
if (fileExtension != null) {
final File renameToFile = new File(renameTo);
renameTo = renameTo.substring(0, renameTo.length() - fileExtension.length());
if (tempCompressedFilePattern != null) {
buf.delete(0, buf.length());
tempCompressedFilePattern.formatFileName(strSubstitutor, buf, fileIndex);
final String tmpCompressedName = buf.toString();
final File tmpCompressedNameFile = new File(tmpCompressedName);
final File parentFile = tmpCompressedNameFile.getParentFile();
if (parentFile != null) {
parentFile.mkdirs();
}
compressAction = new CompositeAction(
Arrays.asList(fileExtension.createCompressAction(renameTo, tmpCompressedName,
true, compressionLevel),
new FileRenameAction(tmpCompressedNameFile,
renameToFile, true)),
true);
} else {
compressAction = fileExtension.createCompressAction(renameTo, compressedName,
true, compressionLevel);
}
}
if (currentFileName.equals(renameTo)) {
LOGGER.warn("Attempt to rename file {} to itself will be ignored", currentFileName);
return new RolloverDescriptionImpl(currentFileName, false, null, null);
}
if (compressAction != null && manager.isAttributeViewEnabled()) {
// Propagate posix attribute view to compressed file
// @formatter:off
final Action posixAttributeViewAction = PosixViewAttributeAction.newBuilder()
.setBasePath(compressedName)
.setFollowLinks(false)
.setMaxDepth(1)
.setPathConditions(new PathCondition[0])
.setSubst(getStrSubstitutor())
.setFilePermissions(manager.getFilePermissions())
.setFileOwner(manager.getFileOwner())
.setFileGroup(manager.getFileGroup())
.build();
// @formatter:on
compressAction = new CompositeAction(Arrays.asList(compressAction, posixAttributeViewAction), false);
}
final FileRenameAction renameAction = new FileRenameAction(new File(currentFileName), new File(renameTo),
manager.isRenameEmptyFiles());
final Action asyncAction = merge(compressAction, customActions, stopCustomActionsOnError);
return new RolloverDescriptionImpl(currentFileName, false, renameAction, asyncAction);
}
/**
* Defines custom actions.
*
* @param customActions custom actions to perform asynchronously after rollover
* @return This builder for chaining convenience
*/
public Builder setCustomActions(final Action... customActions) {
this.customActions = customActions;
return this;
}
/**
* Action to be completed after close of current active log file
* before returning control to caller.
*
* @return action, may be null.
*/
Action getSynchronous();
/**
* Action to be completed after close of current active log file
* and before next rollover attempt, may be executed asynchronously.
*
* @return action, may be null.
*/
Action getAsynchronous();
/**
* Action to be completed after close of current active log file
* before returning control to caller.
*
* @return action, may be null.
*/
@Override
public Action getSynchronous() {
return synchronous;
}
/**
* Action to be completed after close of current active log file
* and before next rollover attempt, may be executed asynchronously.
*
* @return action, may be null.
*/
@Override
public Action getAsynchronous() {
return asynchronous;
}
/**
* 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;
}
/**
* Defines custom actions.
*
* @param customActions custom actions to perform asynchronously after rollover
* @return This builder for chaining convenience
*/
public Builder setCustomActions(final Action... customActions) {
this.customActions = customActions;
return this;
}