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