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