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.IOException;
20 import java.io.OutputStream;
21 import java.nio.ByteBuffer;
22 import java.util.Objects;
23
24 import org.apache.logging.log4j.core.Layout;
25 import org.apache.logging.log4j.core.layout.ByteBufferDestination;
26 import org.apache.logging.log4j.core.util.Constants;
27
28
29
30
31
32 public class OutputStreamManager extends AbstractManager implements ByteBufferDestination {
33 protected final Layout<?> layout;
34 protected ByteBuffer byteBuffer;
35 private volatile OutputStream os;
36 private boolean skipFooter;
37
38 protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
39 final boolean writeHeader) {
40 this(os, streamName, layout, writeHeader, ByteBuffer.wrap(new byte[Constants.ENCODER_BYTE_BUFFER_SIZE]));
41 }
42
43
44
45
46
47
48
49
50
51
52 protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
53 final boolean writeHeader, final ByteBuffer byteBuffer) {
54 super(streamName);
55 this.os = os;
56 this.layout = layout;
57 if (writeHeader && layout != null) {
58 final byte[] header = layout.getHeader();
59 if (header != null) {
60 try {
61 this.os.write(header, 0, header.length);
62 } catch (final IOException e) {
63 logError("Unable to write header", e);
64 }
65 }
66 }
67 this.byteBuffer = Objects.requireNonNull(byteBuffer, "byteBuffer");
68 }
69
70
71
72
73
74
75
76
77
78
79 public static <T> OutputStreamManager getManager(final String name, final T data,
80 final ManagerFactory<? extends OutputStreamManager, T> factory) {
81 return AbstractManager.getManager(name, factory, data);
82 }
83
84
85
86
87
88 public void skipFooter(final boolean skipFooter) {
89 this.skipFooter = skipFooter;
90 }
91
92
93
94
95 @Override
96 public void releaseSub() {
97 writeFooter();
98 close();
99 }
100
101
102
103
104 protected void writeFooter() {
105 if (layout == null || skipFooter) {
106 return;
107 }
108 final byte[] footer = layout.getFooter();
109 if (footer != null) {
110 write(footer);
111 }
112 }
113
114
115
116
117
118 public boolean isOpen() {
119 return getCount() > 0;
120 }
121
122 protected OutputStream getOutputStream() {
123 return os;
124 }
125
126 protected void setOutputStream(final OutputStream os) {
127 final byte[] header = layout.getHeader();
128 if (header != null) {
129 try {
130 os.write(header, 0, header.length);
131 this.os = os;
132 } catch (final IOException ioe) {
133 logError("Unable to write header", ioe);
134 }
135 } else {
136 this.os = os;
137 }
138 }
139
140
141
142
143
144
145 protected void write(final byte[] bytes) {
146 write(bytes, 0, bytes.length, false);
147 }
148
149
150
151
152
153
154
155 protected void write(final byte[] bytes, final boolean immediateFlush) {
156 write(bytes, 0, bytes.length, immediateFlush);
157 }
158
159
160
161
162
163
164
165
166
167 protected void write(final byte[] bytes, final int offset, final int length) {
168 write(bytes, offset, length, false);
169 }
170
171
172
173
174
175
176
177
178
179
180 protected synchronized void write(final byte[] bytes, final int offset, final int length, final boolean immediateFlush) {
181 if (immediateFlush && byteBuffer.position() == 0) {
182 writeToDestination(bytes, offset, length);
183 flushDestination();
184 return;
185 }
186 if (length >= byteBuffer.capacity()) {
187
188 flush();
189 writeToDestination(bytes, offset, length);
190 } else {
191 if (length > byteBuffer.remaining()) {
192 flush();
193 }
194 byteBuffer.put(bytes, offset, length);
195 }
196 if (immediateFlush) {
197 flush();
198 }
199 }
200
201
202
203
204
205
206
207
208
209 protected synchronized void writeToDestination(final byte[] bytes, final int offset, final int length) {
210 try {
211 os.write(bytes, offset, length);
212 } catch (final IOException ex) {
213 final String msg = "Error writing to stream " + getName();
214 throw new AppenderLoggingException(msg, ex);
215 }
216 }
217
218
219
220
221
222 protected synchronized void flushDestination() {
223 try {
224 os.flush();
225 } catch (final IOException ex) {
226 final String msg = "Error flushing stream " + getName();
227 throw new AppenderLoggingException(msg, ex);
228 }
229 }
230
231
232
233
234
235
236
237
238
239 protected synchronized void flushBuffer(final ByteBuffer buf) {
240 buf.flip();
241 if (buf.limit() > 0) {
242 writeToDestination(buf.array(), 0, buf.limit());
243 }
244 buf.clear();
245 }
246
247
248
249
250 public synchronized void flush() {
251 flushBuffer(byteBuffer);
252 flushDestination();
253 }
254
255 protected synchronized void close() {
256 flush();
257 final OutputStream stream = os;
258 if (stream == System.out || stream == System.err) {
259 return;
260 }
261 try {
262 stream.close();
263 } catch (final IOException ex) {
264 logError("Unable to close stream", ex);
265 }
266 }
267
268
269
270
271
272
273 @Override
274 public ByteBuffer getByteBuffer() {
275 return byteBuffer;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295 @Override
296 public ByteBuffer drain(final ByteBuffer buf) {
297 flushBuffer(buf);
298 return buf;
299 }
300 }