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