1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.io;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.nio.ByteBuffer;
24 import java.nio.charset.Charset;
25
26 import org.apache.logging.log4j.Level;
27 import org.apache.logging.log4j.Marker;
28 import org.apache.logging.log4j.spi.ExtendedLogger;
29
30
31
32
33
34 public class ByteStreamLogger {
35 private class ByteBufferInputStream extends InputStream {
36
37 @Override
38 public int read() throws IOException {
39 ByteStreamLogger.this.buf.flip();
40 int result = -1;
41 if (ByteStreamLogger.this.buf.limit() > 0) {
42 result = ByteStreamLogger.this.buf.get() & 0xFF;
43 }
44 ByteStreamLogger.this.buf.compact();
45 return result;
46 }
47
48 @Override
49 public int read(final byte[] bytes, final int off, final int len) throws IOException {
50 ByteStreamLogger.this.buf.flip();
51 int result = -1;
52 if (ByteStreamLogger.this.buf.limit() > 0) {
53 result = Math.min(len, ByteStreamLogger.this.buf.limit());
54 ByteStreamLogger.this.buf.get(bytes, off, result);
55 }
56 ByteStreamLogger.this.buf.compact();
57 return result;
58 }
59 }
60
61 private static final int BUFFER_SIZE = 1024;
62 private final ExtendedLogger logger;
63 private final Level level;
64 private final Marker marker;
65 private final InputStreamReader reader;
66 private final char[] msgBuf = new char[BUFFER_SIZE];
67 private final StringBuilder msg = new StringBuilder();
68 private boolean closed;
69
70 private final ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE);
71
72 public ByteStreamLogger(final ExtendedLogger logger, final Level level, final Marker marker, final Charset charset) {
73 this.logger = logger;
74 this.level = level == null ? logger.getLevel() : level;
75 this.marker = marker;
76 this.reader = new InputStreamReader(new ByteBufferInputStream(),
77 charset == null ? Charset.defaultCharset() : charset);
78 }
79
80 public void close(final String fqcn) {
81 synchronized (this.msg) {
82 this.closed = true;
83 logEnd(fqcn);
84 }
85 }
86
87 private void extractMessages(final String fqcn) throws IOException {
88 if (this.closed) {
89 return;
90 }
91 int read = this.reader.read(this.msgBuf);
92 while (read > 0) {
93 int off = 0;
94 for (int pos = 0; pos < read; pos++) {
95 switch (this.msgBuf[pos]) {
96 case '\r':
97 this.msg.append(this.msgBuf, off, pos - off);
98 off = pos + 1;
99 break;
100 case '\n':
101 this.msg.append(this.msgBuf, off, pos - off);
102 off = pos + 1;
103 log(fqcn);
104 break;
105 }
106 }
107 this.msg.append(this.msgBuf, off, read - off);
108 read = this.reader.read(this.msgBuf);
109 }
110 }
111
112 private void log(final String fqcn) {
113
114 this.logger.logIfEnabled(fqcn, this.level, this.marker, this.msg.toString());
115 this.msg.setLength(0);
116 }
117
118 private void logEnd(final String fqcn) {
119 if (this.msg.length() > 0) {
120 log(fqcn);
121 }
122 }
123
124 public void put(final String fqcn, final byte[] b, final int off, final int len) throws IOException {
125 int curOff = off;
126 int curLen = len;
127 if (curLen >= 0) {
128 synchronized (this.msg) {
129 while (curLen > this.buf.remaining()) {
130 final int remaining = this.buf.remaining();
131 this.buf.put(b, curOff, remaining);
132 curLen -= remaining;
133 curOff += remaining;
134 extractMessages(fqcn);
135 }
136 this.buf.put(b, curOff, curLen);
137 extractMessages(fqcn);
138 }
139 } else {
140 logEnd(fqcn);
141 }
142 }
143
144 public void put(final String fqcn, final int b) throws IOException {
145 if (b >= 0) {
146 synchronized (this.msg) {
147 this.buf.put((byte) (b & 0xFF));
148 extractMessages(fqcn);
149 }
150 } else {
151 logEnd(fqcn);
152 }
153 }
154 }