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