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.FileNotFoundException;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.Serializable;
25 import java.nio.ByteBuffer;
26 import java.nio.channels.FileChannel;
27 import java.nio.channels.FileLock;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 import org.apache.logging.log4j.core.Layout;
32 import org.apache.logging.log4j.core.LoggerContext;
33 import org.apache.logging.log4j.core.config.Configuration;
34 import org.apache.logging.log4j.core.util.Constants;
35
36
37
38
39
40 public class FileManager extends OutputStreamManager {
41
42 private static final FileManagerFactory FACTORY = new FileManagerFactory();
43
44 private final boolean isAppend;
45 private final boolean createOnDemand;
46 private final boolean isLocking;
47 private final String advertiseURI;
48 private final int bufferSize;
49
50
51
52
53 @Deprecated
54 protected FileManager(final String fileName, final OutputStream os, final boolean append, final boolean locking,
55 final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize,
56 final boolean writeHeader) {
57 this(fileName, os, append, locking, advertiseURI, layout, writeHeader, ByteBuffer.wrap(new byte[bufferSize]));
58 }
59
60
61
62
63
64 @Deprecated
65 protected FileManager(final String fileName, final OutputStream os, final boolean append, final boolean locking,
66 final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader,
67 final ByteBuffer buffer) {
68 super(os, fileName, layout, writeHeader, buffer);
69 this.isAppend = append;
70 this.createOnDemand = false;
71 this.isLocking = locking;
72 this.advertiseURI = advertiseURI;
73 this.bufferSize = buffer.capacity();
74 }
75
76
77
78
79 protected FileManager(final LoggerContext loggerContext, final String fileName, final OutputStream os, final boolean append, final boolean locking,
80 final boolean createOnDemand, final String advertiseURI, final Layout<? extends Serializable> layout,
81 final boolean writeHeader, final ByteBuffer buffer) {
82 super(loggerContext, os, fileName, createOnDemand, layout, writeHeader, buffer);
83 this.isAppend = append;
84 this.createOnDemand = createOnDemand;
85 this.isLocking = locking;
86 this.advertiseURI = advertiseURI;
87 this.bufferSize = buffer.capacity();
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 public static FileManager getFileManager(final String fileName, final boolean append, boolean locking,
104 final boolean bufferedIo, final boolean createOnDemand, final String advertiseUri,
105 final Layout<? extends Serializable> layout, final int bufferSize, final Configuration configuration) {
106
107 if (locking && bufferedIo) {
108 locking = false;
109 }
110 return (FileManager) getManager(fileName, new FactoryData(append, locking, bufferedIo, bufferSize,
111 createOnDemand, advertiseUri, layout, configuration), FACTORY);
112 }
113
114 @Override
115 protected OutputStream createOutputStream() throws FileNotFoundException {
116 return new FileOutputStream(getFileName(), isAppend);
117 }
118
119 @Override
120 protected synchronized void write(final byte[] bytes, final int offset, final int length,
121 final boolean immediateFlush) {
122 if (isLocking) {
123 try {
124 @SuppressWarnings("resource")
125 final FileChannel channel = ((FileOutputStream) getOutputStream()).getChannel();
126
127
128
129
130
131
132
133
134 try (final FileLock lock = channel.lock(0, Long.MAX_VALUE, false)) {
135 super.write(bytes, offset, length, immediateFlush);
136 }
137 } catch (final IOException ex) {
138 throw new AppenderLoggingException("Unable to obtain lock on " + getName(), ex);
139 }
140 } else {
141 super.write(bytes, offset, length, immediateFlush);
142 }
143 }
144
145
146
147
148
149 public String getFileName() {
150 return getName();
151 }
152
153
154
155
156
157 public boolean isAppend() {
158 return isAppend;
159 }
160
161
162
163
164
165 public boolean isCreateOnDemand() {
166 return createOnDemand;
167 }
168
169
170
171
172
173 public boolean isLocking() {
174 return isLocking;
175 }
176
177
178
179
180
181
182 public int getBufferSize() {
183 return bufferSize;
184 }
185
186
187
188
189
190
191 @Override
192 public Map<String, String> getContentFormat() {
193 final Map<String, String> result = new HashMap<>(super.getContentFormat());
194 result.put("fileURI", advertiseURI);
195 return result;
196 }
197
198
199
200
201 private static class FactoryData extends ConfigurationFactoryData {
202 private final boolean append;
203 private final boolean locking;
204 private final boolean bufferedIo;
205 private final int bufferSize;
206 private final boolean createOnDemand;
207 private final String advertiseURI;
208 private final Layout<? extends Serializable> layout;
209
210
211
212
213
214
215
216
217
218
219
220
221 public FactoryData(final boolean append, final boolean locking, final boolean bufferedIo, final int bufferSize,
222 final boolean createOnDemand, final String advertiseURI, final Layout<? extends Serializable> layout,
223 final Configuration configuration) {
224 super(configuration);
225 this.append = append;
226 this.locking = locking;
227 this.bufferedIo = bufferedIo;
228 this.bufferSize = bufferSize;
229 this.createOnDemand = createOnDemand;
230 this.advertiseURI = advertiseURI;
231 this.layout = layout;
232 }
233 }
234
235
236
237
238 private static class FileManagerFactory implements ManagerFactory<FileManager, FactoryData> {
239
240
241
242
243
244
245
246 @Override
247 public FileManager createManager(final String name, final FactoryData data) {
248 final File file = new File(name);
249 final File parent = file.getParentFile();
250 if (null != parent && !parent.exists()) {
251 parent.mkdirs();
252 }
253
254 final boolean writeHeader = !data.append || !file.exists();
255 try {
256 final int actualSize = data.bufferedIo ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE;
257 final ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[actualSize]);
258 final FileOutputStream fos = data.createOnDemand ? null : new FileOutputStream(file, data.append);
259 return new FileManager(data.getLoggerContext(), name, fos, data.append, data.locking,
260 data.createOnDemand, data.advertiseURI, data.layout, writeHeader, byteBuffer);
261 } catch (final IOException ex) {
262 LOGGER.error("FileManager (" + name + ") " + ex, ex);
263 }
264 return null;
265 }
266 }
267
268 }