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 org.apache.logging.log4j.core.Layout;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.RandomAccessFile;
25 import java.nio.ByteBuffer;
26 import java.util.HashMap;
27 import java.util.Map;
28
29
30
31
32
33
34 public class FastFileManager extends OutputStreamManager {
35 private static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
36
37 private static final FastFileManagerFactory FACTORY = new FastFileManagerFactory();
38
39 private final boolean isImmediateFlush;
40 private final String advertiseURI;
41 private final RandomAccessFile randomAccessFile;
42 private final ByteBuffer buffer;
43 private ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<Boolean>();
44
45 protected FastFileManager(final RandomAccessFile file, final String fileName,
46 final OutputStream os, final boolean immediateFlush, final String advertiseURI,
47 final Layout layout) {
48 super(os, fileName, layout);
49 this.isImmediateFlush = immediateFlush;
50 this.randomAccessFile = file;
51 this.advertiseURI = advertiseURI;
52 isEndOfBatch.set(Boolean.FALSE);
53
54
55 buffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
56 }
57
58
59
60
61
62
63
64
65
66
67
68 public static FastFileManager getFileManager(final String fileName, final boolean append,
69 final boolean isFlush, final String advertiseURI,
70 final Layout layout) {
71 return (FastFileManager) getManager(fileName, new FactoryData(append, isFlush, advertiseURI, layout), FACTORY);
72 }
73
74 public Boolean isEndOfBatch() {
75 return isEndOfBatch.get();
76 }
77
78 public void setEndOfBatch(boolean isEndOfBatch) {
79 this.isEndOfBatch.set(Boolean.valueOf(isEndOfBatch));
80 }
81
82 @Override
83 protected synchronized void write(byte[] bytes, int offset, int length) {
84 super.write(bytes, offset, length);
85
86 if (length > buffer.remaining()) {
87 flush();
88 }
89 buffer.put(bytes, offset, length);
90 if (isImmediateFlush || isEndOfBatch.get() == Boolean.TRUE) {
91 flush();
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
122
123 public String getFileName() {
124 return getName();
125 }
126
127
128 private static class DummyOutputStream extends OutputStream {
129 @Override
130 public void write(int b) throws IOException {
131 }
132
133 @Override
134 public void write(byte[] b, int off, int len) throws IOException {
135 }
136 }
137
138
139
140
141
142
143
144
145 @Override
146 public Map<String, String> getContentFormat() {
147 Map<String, String> result = new HashMap<String, String>(
148 super.getContentFormat());
149 result.put("fileURI", advertiseURI);
150 return result;
151 }
152
153
154
155
156 private static class FactoryData {
157 private final boolean append;
158 private final boolean immediateFlush;
159 private final String advertiseURI;
160 private final Layout layout;
161
162
163
164
165
166
167 public FactoryData(final boolean append, final boolean immediateFlush, final String advertiseURI,
168 final Layout layout) {
169 this.append = append;
170 this.immediateFlush = immediateFlush;
171 this.advertiseURI = advertiseURI;
172 this.layout = layout;
173 }
174 }
175
176
177
178
179 private static class FastFileManagerFactory implements ManagerFactory<FastFileManager, FactoryData> {
180
181
182
183
184
185
186
187
188 @Override
189 public FastFileManager createManager(String name, FactoryData data) {
190 File file = new File(name);
191 final File parent = file.getParentFile();
192 if (null != parent && !parent.exists()) {
193 parent.mkdirs();
194 }
195 if (!data.append) {
196 file.delete();
197 }
198
199 OutputStream os = new DummyOutputStream();
200 RandomAccessFile raf;
201 try {
202 raf = new RandomAccessFile(name, "rw");
203 return new FastFileManager(raf, name, os, data.immediateFlush, data.advertiseURI, data.layout);
204 } catch (Exception ex) {
205 LOGGER.error("FastFileManager (" + name + ") " + ex);
206 }
207 return null;
208 }
209 }
210
211 }