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