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