1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender.rolling;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.file.DirectoryStream;
22 import java.nio.file.Files;
23 import java.nio.file.Path;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.SortedMap;
27 import java.util.TreeMap;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30
31 import org.apache.logging.log4j.Logger;
32 import org.apache.logging.log4j.LoggingException;
33 import org.apache.logging.log4j.core.appender.rolling.action.Action;
34 import org.apache.logging.log4j.core.appender.rolling.action.CompositeAction;
35 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
36 import org.apache.logging.log4j.core.pattern.NotANumber;
37 import org.apache.logging.log4j.status.StatusLogger;
38
39
40
41
42 public abstract class AbstractRolloverStrategy implements RolloverStrategy {
43
44
45
46
47 protected static final Logger LOGGER = StatusLogger.getLogger();
48
49 public static final Pattern PATTERN_COUNTER= Pattern.compile(".*%((?<ZEROPAD>0)?(?<PADDING>\\d+))?i.*");
50
51 protected final StrSubstitutor strSubstitutor;
52
53 protected AbstractRolloverStrategy(final StrSubstitutor strSubstitutor) {
54 this.strSubstitutor = strSubstitutor;
55 }
56
57
58 public StrSubstitutor getStrSubstitutor() {
59 return strSubstitutor;
60 }
61
62 protected Action merge(final Action compressAction, final List<Action> custom, final boolean stopOnError) {
63 if (custom.isEmpty()) {
64 return compressAction;
65 }
66 if (compressAction == null) {
67 return new CompositeAction(custom, stopOnError);
68 }
69 final List<Action> all = new ArrayList<>();
70 all.add(compressAction);
71 all.addAll(custom);
72 return new CompositeAction(all, stopOnError);
73 }
74
75 protected int suffixLength(final String lowFilename) {
76 for (final FileExtension extension : FileExtension.values()) {
77 if (extension.isExtensionFor(lowFilename)) {
78 return extension.length();
79 }
80 }
81 return 0;
82 }
83
84
85 protected SortedMap<Integer, Path> getEligibleFiles(final RollingFileManager manager) {
86 return getEligibleFiles(manager, true);
87 }
88
89 protected SortedMap<Integer, Path> getEligibleFiles(final RollingFileManager manager,
90 final boolean isAscending) {
91 final StringBuilder buf = new StringBuilder();
92 final String pattern = manager.getPatternProcessor().getPattern();
93 manager.getPatternProcessor().formatFileName(strSubstitutor, buf, NotANumber.NAN);
94 final String fileName = manager.isDirectWrite() ? "" : manager.getFileName();
95 return getEligibleFiles(fileName, buf.toString(), pattern, isAscending);
96 }
97
98 protected SortedMap<Integer, Path> getEligibleFiles(final String path, final String pattern) {
99 return getEligibleFiles("", path, pattern, true);
100 }
101
102 @Deprecated
103 protected SortedMap<Integer, Path> getEligibleFiles(final String path, final String logfilePattern,
104 final boolean isAscending) {
105 return getEligibleFiles("", path, logfilePattern, isAscending);
106 }
107
108 protected SortedMap<Integer, Path> getEligibleFiles(final String currentFile, final String path,
109 final String logfilePattern, final boolean isAscending) {
110 final TreeMap<Integer, Path> eligibleFiles = new TreeMap<>();
111 final File file = new File(path);
112 File parent = file.getParentFile();
113 if (parent == null) {
114 parent = new File(".");
115 } else {
116 parent.mkdirs();
117 }
118 if (!PATTERN_COUNTER.matcher(logfilePattern).matches()) {
119 return eligibleFiles;
120 }
121 final Path dir = parent.toPath();
122 String fileName = file.getName();
123 final int suffixLength = suffixLength(fileName);
124 if (suffixLength > 0) {
125 fileName = fileName.substring(0, fileName.length() - suffixLength) + ".*";
126 }
127 final String filePattern = fileName.replaceFirst("0?\\u0000", "(0?\\\\d+)");
128 final Pattern pattern = Pattern.compile(filePattern);
129 final Path current = currentFile.length() > 0 ? new File(currentFile).toPath() : null;
130 LOGGER.debug("Current file: {}", currentFile);
131
132 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
133 for (final Path entry: stream) {
134 final Matcher matcher = pattern.matcher(entry.toFile().getName());
135 if (matcher.matches() && !entry.equals(current)) {
136 try {
137 final Integer index = Integer.parseInt(matcher.group(1));
138 eligibleFiles.put(index, entry);
139 } catch (NumberFormatException ex) {
140 LOGGER.debug("Ignoring file {} which matches pattern but the index is invalid.",
141 entry.toFile().getName());
142 }
143 }
144 }
145 } catch (final IOException ioe) {
146 throw new LoggingException("Error reading folder " + dir + " " + ioe.getMessage(), ioe);
147 }
148 return isAscending? eligibleFiles : eligibleFiles.descendingMap();
149 }
150 }