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 org.apache.logging.log4j.core.LogEvent;
20 import org.apache.logging.log4j.core.appender.FileManager;
21 import org.apache.logging.log4j.core.appender.ManagerFactory;
22 import org.apache.logging.log4j.core.appender.rolling.helper.Action;
23 import org.apache.logging.log4j.core.appender.rolling.helper.AbstractAction;
24
25 import java.io.BufferedOutputStream;
26 import java.io.File;
27 import java.io.FileNotFoundException;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.util.concurrent.Semaphore;
32
33
34
35
36 public class RollingFileManager extends FileManager {
37
38 private static RollingFileManagerFactory factory = new RollingFileManagerFactory();
39
40 private long size;
41 private long initialTime;
42 private final PatternProcessor processor;
43 private final Semaphore semaphore = new Semaphore(1);
44
45 protected RollingFileManager(String fileName, String pattern, OutputStream os, boolean append, long size,
46 long time) {
47 super(fileName, os, append, false);
48 this.size = size;
49 this.initialTime = time;
50 processor = new PatternProcessor(pattern);
51 }
52
53
54
55
56
57
58
59
60
61 public static RollingFileManager getFileManager(String fileName, String pattern, boolean append,
62 boolean bufferedIO) {
63
64 return (RollingFileManager) getManager(fileName, new FactoryData(pattern, append,
65 bufferedIO), factory);
66 }
67
68 @Override
69 protected synchronized void write(byte[] bytes, int offset, int length) {
70 size += length;
71 super.write(bytes, offset, length);
72 }
73
74
75
76
77
78 public long getFileSize() {
79 return size;
80 }
81
82
83
84
85
86 public long getFileTime() {
87 return initialTime;
88 }
89
90
91
92
93
94
95
96 public synchronized void checkRollover(LogEvent event, TriggeringPolicy policy, RolloverStrategy strategy) {
97 if (policy.isTriggeringEvent(event) && rollover(strategy)) {
98 try {
99 size = 0;
100 initialTime = System.currentTimeMillis();
101 OutputStream os = new FileOutputStream(getFileName(), isAppend());
102 setOutputStream(os);
103 } catch (FileNotFoundException ex) {
104 LOGGER.error("FileManager (" + getFileName() + ") " + ex);
105 }
106 }
107 }
108
109
110
111
112
113 public PatternProcessor getProcessor() {
114 return processor;
115 }
116
117 private boolean rollover(RolloverStrategy strategy) {
118
119 try {
120
121 semaphore.acquire();
122 } catch (InterruptedException ie) {
123 LOGGER.error("Thread interrupted while attempting to check rollover", ie);
124 return false;
125 }
126
127 boolean success = false;
128 Thread thread = null;
129
130 try {
131 RolloverDescription descriptor = strategy.rollover(this);
132
133 if (descriptor != null) {
134
135 close();
136
137 if (descriptor.getSynchronous() != null) {
138
139 try {
140 success = descriptor.getSynchronous().execute();
141 } catch (Exception ex) {
142 LOGGER.error("Error in synchronous task", ex);
143 }
144 }
145
146 if (success && descriptor.getAsynchronous() != null) {
147 thread = new Thread(new AsyncAction(descriptor.getAsynchronous(), this));
148 thread.start();
149 }
150 return true;
151 }
152 return false;
153 } finally {
154 if (thread == null) {
155 semaphore.release();
156 }
157 }
158
159 }
160
161
162
163
164 private static class AsyncAction extends AbstractAction {
165
166 private final Action action;
167 private final RollingFileManager manager;
168
169
170
171
172
173
174 public AsyncAction(Action act, RollingFileManager manager) {
175 this.action = act;
176 this.manager = manager;
177 }
178
179
180
181
182
183
184
185
186
187 @Override
188 public boolean execute() throws IOException {
189 try {
190 return action.execute();
191 } finally {
192 manager.semaphore.release();
193 }
194 }
195
196
197
198
199 @Override
200 public void close() {
201 action.close();
202 }
203
204
205
206
207
208
209 @Override
210 public boolean isComplete() {
211 return action.isComplete();
212 }
213 }
214
215
216
217
218 private static class FactoryData {
219 private String pattern;
220 private boolean append;
221 private boolean bufferedIO;
222
223
224
225
226
227
228
229 public FactoryData(String pattern, boolean append, boolean bufferedIO) {
230 this.pattern = pattern;
231 this.append = append;
232 this.bufferedIO = bufferedIO;
233 }
234 }
235
236
237
238
239 private static class RollingFileManagerFactory implements ManagerFactory<RollingFileManager, FactoryData> {
240
241
242
243
244
245
246
247 public RollingFileManager createManager(String name, FactoryData data) {
248 File file = new File(name);
249 final File parent = file.getParentFile();
250 if (null != parent && !parent.exists()) {
251 parent.mkdirs();
252 }
253 try {
254 file.createNewFile();
255 } catch (IOException ioe) {
256 LOGGER.error("Unable to create file " + name, ioe);
257 return null;
258 }
259 long size = data.append ? file.length() : 0;
260 long time = file.lastModified();
261
262 OutputStream os;
263 try {
264 os = new FileOutputStream(name, data.append);
265 if (data.bufferedIO) {
266 os = new BufferedOutputStream(os);
267 }
268 return new RollingFileManager(name, data.pattern, os, data.append, size, time);
269 } catch (FileNotFoundException ex) {
270 LOGGER.error("FileManager (" + name + ") " + ex);
271 }
272 return null;
273 }
274 }
275
276 }