View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.spi;
18  
19  import org.apache.logging.log4j.Level;
20  import org.apache.logging.log4j.Marker;
21  import org.apache.logging.log4j.message.Message;
22  
23  import java.io.ByteArrayOutputStream;
24  import java.io.IOException;
25  import java.io.PrintStream;
26  import java.util.Locale;
27  
28  /**
29   * Output stream that logs each line written to a pre-defined level. Can also
30   * be configured with a Marker. This class provides an interface that follows
31   * the {@link java.io.PrintStream} methods in spirit, but doesn't output to
32   * any external stream. This class should <em>not</em> be used as a stream for an
33   * underlying logger unless it's being used as a bridge. Otherwise, infinite
34   * loops may occur!
35   */
36  public class LoggerStream extends PrintStream {
37  
38      final PrintStream stream;
39  
40      public LoggerStream(final AbstractLogger logger, final Level level) {
41          super(System.out);
42          stream = new PrintStream(new HelperStream(logger, null, level), true);
43      }
44  
45      public LoggerStream(final AbstractLogger logger, final Marker marker, final Level level) {
46          super(System.out);
47          stream = new PrintStream(new HelperStream(logger, marker, level), true);
48      }
49  
50      @Override
51      public void write(int b) {
52          stream.write(b);
53      }
54  
55      @Override
56      public void write(byte[] b) throws IOException {
57          stream.write(b);
58      }
59  
60      @Override
61      public void write(byte[] b, int off, int len) {
62          stream.write(b, off, len);
63      }
64  
65      @Override
66      public void flush() {
67          stream.flush();
68      }
69  
70      @Override
71      public void close() {
72          stream.close();
73      }
74  
75      @Override
76      public void print(boolean b) {
77          stream.print(b);
78      }
79  
80      @Override
81      public void print(char c) {
82          stream.print(c);
83      }
84  
85      @Override
86      public void print(int i) {
87          stream.print(i);
88      }
89  
90      @Override
91      public void print(long l) {
92          stream.print(l);
93      }
94  
95      @Override
96      public void print(float f) {
97          stream.print(f);
98      }
99  
100     @Override
101     public void print(double d) {
102         stream.print(d);
103     }
104 
105     @Override
106     public void print(char[] s) {
107         stream.print(s);
108     }
109 
110     @Override
111     public void print(String s) {
112         stream.print(s);
113     }
114 
115     @Override
116     public void print(Object obj) {
117         stream.print(obj);
118     }
119 
120     @Override
121     public void println() {
122         stream.println();
123     }
124 
125     @Override
126     public void println(boolean x) {
127         stream.println(x);
128     }
129 
130     @Override
131     public void println(char x) {
132         stream.println(x);
133     }
134 
135     @Override
136     public void println(int x) {
137         stream.println(x);
138     }
139 
140     @Override
141     public void println(long x) {
142         stream.println(x);
143     }
144 
145     @Override
146     public void println(float x) {
147         stream.println(x);
148     }
149 
150     @Override
151     public void println(double x) {
152         stream.println(x);
153     }
154 
155     @Override
156     public void println(char[] x) {
157         stream.println(x);
158     }
159 
160     @Override
161     public void println(String x) {
162         stream.println(x);
163     }
164 
165     @Override
166     public void println(Object x) {
167         stream.println(x);
168     }
169 
170     @Override
171     public LoggerStream printf(String format, Object... args) {
172         stream.printf(format, args);
173         return this;
174     }
175 
176     @Override
177     public LoggerStream printf(Locale l, String format, Object... args) {
178         stream.printf(l, format, args);
179         return this;
180     }
181 
182     @Override
183     public LoggerStream append(char c) {
184         stream.append(c);
185         return this;
186     }
187 
188     @Override
189     public LoggerStream append(CharSequence csq) {
190         stream.append(csq);
191         return this;
192     }
193 
194     @Override
195     public LoggerStream append(CharSequence csq, int start, int end) {
196         stream.append(csq, start, end);
197         return this;
198     }
199 
200     @Override
201     public LoggerStream format(String format, Object... args) {
202         stream.format(format, args);
203         return this;
204     }
205 
206     @Override
207     public LoggerStream format(Locale l, String format, Object... args) {
208         stream.format(l, format, args);
209         return this;
210     }
211 
212     @Override
213     public boolean checkError() {
214         return stream.checkError();
215     }
216 
217     @Override
218     public String toString() {
219         return "LoggerStream{" +
220                 "stream=" + stream +
221                 '}';
222     }
223 
224     @Override
225     public boolean equals(Object other) {
226         return this == other
227                 || !(other == null || getClass() != other.getClass())
228                 && stream.equals(((LoggerStream) other).stream);
229     }
230 
231     @Override
232     public int hashCode() {
233         return stream.hashCode();
234     }
235 
236     private static class HelperStream extends ByteArrayOutputStream {
237         private static final String FQCN = LoggerStream.class.getName();
238         private final AbstractLogger logger;
239         private final Level level;
240         private final Marker marker;
241 
242         private HelperStream(AbstractLogger logger, Marker marker, Level level) {
243             this.logger = logger;
244             this.marker = marker;
245             this.level = level;
246         }
247 
248         private void log(int upTo) {
249             if (upTo < 0 || upTo >= count) {
250                 throw new IndexOutOfBoundsException();
251             }
252             final Message message = logger.getMessageFactory().newMessage(extractLine(upTo));
253             logger.log(marker, FQCN, level, message, null);
254         }
255 
256         private String extractLine(int upTo) {
257             final String line = new String(buf, 0, upTo);
258             leftShiftBuffer(upTo + 1);
259             return line;
260         }
261 
262         private void leftShiftBuffer(int numBytes) {
263             int remaining = count - numBytes;
264             if (remaining > 0) {
265                 System.arraycopy(buf, numBytes, buf, 0, remaining);
266                 count = remaining + 1;
267             } else {
268                 reset();
269             }
270         }
271 
272         @Override
273         public synchronized void write(int b) {
274             if (b == '\r') {
275                 return;
276             }
277             super.write(b);
278             if (b == '\n') {
279                 log(count - 1);
280             }
281         }
282 
283         @Override
284         public synchronized void write(byte[] b, int off, int len) {
285             for (int i = 0; i < len; ++i) {
286                 write(b[off + i]);
287             }
288         }
289     }
290 }