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