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