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