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