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