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.File;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.io.RandomAccessFile;
24 import java.nio.ByteBuffer;
25
26 import org.apache.logging.log4j.core.Layout;
27 import org.apache.logging.log4j.core.appender.AppenderRuntimeException;
28 import org.apache.logging.log4j.core.appender.ManagerFactory;
29
30
31
32
33
34
35 public class FastRollingFileManager extends RollingFileManager {
36 private static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
37
38 private static final FastRollingFileManagerFactory FACTORY = new FastRollingFileManagerFactory();
39
40 private final boolean isImmediateFlush;
41 private RandomAccessFile randomAccessFile;
42 private final ByteBuffer buffer;
43 private ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<Boolean>();
44
45 public FastRollingFileManager(final RandomAccessFile raf, final String fileName,
46 final String pattern, final OutputStream os, final boolean append,
47 final boolean immediateFlush, final long size, final long time,
48 final TriggeringPolicy policy, final RolloverStrategy strategy,
49 final String advertiseURI, final Layout layout) {
50 super(fileName, pattern, os, append, size, time, policy, strategy, advertiseURI, layout);
51 this.isImmediateFlush = immediateFlush;
52 this.randomAccessFile = raf;
53 isEndOfBatch.set(Boolean.FALSE);
54
55
56 buffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
57 }
58
59 public static FastRollingFileManager getFastRollingFileManager(final String fileName, final String filePattern,
60 final boolean isAppend, final boolean immediateFlush, final TriggeringPolicy policy,
61 final RolloverStrategy strategy, final String advertiseURI, final Layout layout) {
62 return (FastRollingFileManager) getManager(fileName, new FactoryData(filePattern, isAppend, immediateFlush,
63 policy, strategy, advertiseURI, layout), FACTORY);
64 }
65
66 public Boolean isEndOfBatch() {
67 return isEndOfBatch.get();
68 }
69
70 public void setEndOfBatch(boolean isEndOfBatch) {
71 this.isEndOfBatch.set(Boolean.valueOf(isEndOfBatch));
72 }
73
74 @Override
75 protected synchronized void write(byte[] bytes, int offset, int length) {
76 super.write(bytes, offset, length);
77
78 if (length > buffer.remaining()) {
79 flush();
80 }
81 buffer.put(bytes, offset, length);
82 if (isImmediateFlush || isEndOfBatch.get() == Boolean.TRUE) {
83 flush();
84 }
85 }
86
87 @Override
88 protected void createFileAfterRollover() throws IOException {
89 this.randomAccessFile = new RandomAccessFile(getFileName(), "rw");
90 if (isAppend()) {
91 randomAccessFile.seek(randomAccessFile.length());
92 }
93 }
94
95 @Override
96 public void flush() {
97 buffer.flip();
98 try {
99 randomAccessFile.write(buffer.array(), 0, buffer.limit());
100 } catch (IOException ex) {
101 String msg = "Error writing to RandomAccessFile " + getName();
102 throw new AppenderRuntimeException(msg, ex);
103 }
104 buffer.clear();
105 }
106
107 @Override
108 public void close() {
109 flush();
110 try {
111 randomAccessFile.close();
112 } catch (final IOException ex) {
113 LOGGER.error("Unable to close RandomAccessFile " + getName() + ". "
114 + ex);
115 }
116 }
117
118
119
120
121 private static class FastRollingFileManagerFactory implements ManagerFactory<FastRollingFileManager, FactoryData> {
122
123
124
125
126
127
128
129
130 @Override
131 public FastRollingFileManager createManager(String name, FactoryData data) {
132 File file = new File(name);
133 final File parent = file.getParentFile();
134 if (null != parent && !parent.exists()) {
135 parent.mkdirs();
136 }
137 if (!data.append) {
138 file.delete();
139 }
140 long size = data.append ? file.length() : 0;
141 long time = file.lastModified();
142
143 RandomAccessFile raf;
144 try {
145 raf = new RandomAccessFile(name, "rw");
146 return new FastRollingFileManager(raf, name, data.pattern, new DummyOutputStream(), data.append,
147 data.immediateFlush, size, time, data.policy, data.strategy, data.advertiseURI, data.layout);
148 } catch (FileNotFoundException ex) {
149 LOGGER.error("FastRollingFileManager (" + name + ") " + ex);
150 }
151 return null;
152 }
153 }
154
155
156 private static class DummyOutputStream extends OutputStream {
157 @Override
158 public void write(int b) throws IOException {
159 }
160
161 @Override
162 public void write(byte[] b, int off, int len) throws IOException {
163 }
164 }
165
166
167
168
169 private static class FactoryData {
170 private final String pattern;
171 private final boolean append;
172 private final boolean immediateFlush;
173 private final TriggeringPolicy policy;
174 private final RolloverStrategy strategy;
175 private final String advertiseURI;
176 private final Layout layout;
177
178
179
180
181
182
183
184
185 public FactoryData(final String pattern, final boolean append, final boolean immediateFlush,
186 final TriggeringPolicy policy, final RolloverStrategy strategy, final String advertiseURI,
187 final Layout layout) {
188 this.pattern = pattern;
189 this.append = append;
190 this.immediateFlush = immediateFlush;
191 this.policy = policy;
192 this.strategy = strategy;
193 this.advertiseURI = advertiseURI;
194 this.layout = layout;
195 }
196 }
197
198 }