View Javadoc

1   /* 
2    * Copyright (c) 2009-2010 Robert Elliot
3    * All rights reserved.
4    * 
5    * Permission is hereby granted, free  of charge, to any person obtaining
6    * a  copy  of this  software  and  associated  documentation files  (the
7    * "Software"), to  deal in  the Software without  restriction, including
8    * without limitation  the rights to  use, copy, modify,  merge, publish,
9    * distribute,  sublicense, and/or sell  copies of  the Software,  and to
10   * permit persons to whom the Software  is furnished to do so, subject to
11   * the following conditions:
12   * 
13   * The  above  copyright  notice  and  this permission  notice  shall  be
14   * included in all copies or substantial portions of the Software.
15   * 
16   * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
17   * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
18   * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
19   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21   * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
22   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23   */
24  
25  package uk.org.lidalia.sysoutslf4j.system;
26  
27  import java.io.ByteArrayOutputStream;
28  import java.io.IOException;
29  import java.io.PrintStream;
30  import java.util.Locale;
31  
32  import uk.org.lidalia.sysoutslf4j.common.LoggerAppender;
33  import uk.org.lidalia.sysoutslf4j.common.SLF4JPrintStream;
34  
35  /**
36   * 
37   * @author Robert Elliot
38   * 
39   *         <p>
40   *         Instances of this class wrap the existing {@link System#out} or
41   *         {@link System#err} {@link PrintStream}s. They intercept all calls to
42   *         System.out and System.err and log them at info (for System.out) or
43   *         error (for System.err) level on a logger named after the class which
44   *         made the call, via an SLF4J {@link org.slf4j.Logger}.
45   *         </p>
46   * 
47   *         <p>
48   *         The sole exceptions are calls to {@link #write(byte[])},
49   *         {@link #write(int)} and {@link #write(byte[], int, int)}, which pass
50   *         the calls through to the original PrintStream on the basis that these
51   *         methods are highly unlikely to be used for "normal" printing to the
52   *         Console but are used by major logging frameworks in their Console
53   *         appenders. This allows this interceptor to have a minimal impact for
54   *         most logging frameworks when sending output to the Console.
55   *         </p>
56   * 
57   *         <p>
58   *         Instances should only be created and assigned by the
59   *         {@link uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J} helper class.
60   *         </p>
61   * 
62   *         <p>
63   *         Calls to {@link Throwable#printStackTrace()} and
64   *         {@link Throwable#printStackTrace(PrintStream)} (in the case that the
65   *         PrintStream passed to the latter is either the {@link System#out} or
66   *         the {@link System#err} {@link PrintStream}) are handled by
67   *         calculating the name of the class which called printStackTrace and
68   *         logging using a logger named after that class.
69   *         </p>
70   * 
71   *         <p>
72   *         It is important to note that there are performance overheads for
73   *         every call to the methods other than write on System.out and
74   *         System.err using this proxy. It is intended for use with legacy
75   *         compiled code that has a few calls to System.out/err; it is not
76   *         intended to encourage use of System.out/err in preference to Loggers
77   *         in new code. The assumption is that no legacy code prints to
78   *         System.out or System.err on such a regular basis that the performance
79   *         hit is heavy, otherwise that code would be rendering the console
80   *         unusable and itself be a performance drain.
81   *         </p>
82   * 
83   *         <p>
84   *         There should be hardly any performance implications for calls to the
85   *         write methods on System.out/err. LogBack, Log4J and JULI
86   *         ConsoleAppenders all use the write methods on System.out/err, and so
87   *         there should be minimal performance overhead for them.
88   *         </p>
89   * 
90   *         <p>
91   *         Where an existing logging system needs to use println on
92   *         System.out/err, this is handled without redirecting that call back to
93   *         SLF4J, though a performance hit will occur.
94   *         </p>
95   */
96  public final class SLF4JPrintStreamImpl extends PrintStream implements SLF4JPrintStream { // NOPMD superclass has too many methods
97  
98  	private final PrintStream originalPrintStream;
99  	private final SLF4JPrintStreamDelegate delegate;
100 
101 	SLF4JPrintStreamImpl(final PrintStream originalPrintStream, final SLF4JPrintStreamDelegate delegate) {
102 		// This ByteArrayOutputStream will be unused - we aren't going to touch
103 		// the super class.
104 		super(new ByteArrayOutputStream());
105 		this.originalPrintStream = originalPrintStream;
106 		this.delegate = delegate;
107 	}
108 
109 	@Override
110 	public synchronized void println(final String string) {
111 		delegate.delegatePrintln(string);
112 	}
113 
114 	@Override
115 	public synchronized void println(final Object object) {
116 		delegate.delegatePrintln(String.valueOf(object));
117 	}
118 
119 	@Override
120 	public synchronized void println() {
121 		delegate.delegatePrintln("");
122 	}
123 
124 	@Override
125 	public synchronized void println(final boolean bool) {
126 		delegate.delegatePrintln(String.valueOf(bool));
127 	}
128 
129 	@Override
130 	public synchronized void println(final char character) {
131 		delegate.delegatePrintln(String.valueOf(character));
132 	}
133 
134 	@Override
135 	public synchronized void println(final char[] charArray) {
136 		delegate.delegatePrintln(String.valueOf(charArray));
137 	}
138 
139 	@Override
140 	public synchronized void println(final double doub) {
141 		delegate.delegatePrintln(String.valueOf(doub));
142 	}
143 
144 	@Override
145 	public synchronized void println(final float floa) {
146 		delegate.delegatePrintln(String.valueOf(floa));
147 	}
148 
149 	@Override
150 	public synchronized void println(final int integer) {
151 		delegate.delegatePrintln(String.valueOf(integer));
152 	}
153 
154 	@Override
155 	public synchronized void println(final long lon) {
156 		delegate.delegatePrintln(String.valueOf(lon));
157 	}
158 
159 	@Override
160 	public synchronized PrintStream append(final char character) {
161 		delegate.delegatePrint(String.valueOf(character));
162 		return this;
163 	}
164 
165 	@Override
166 	public synchronized PrintStream append(final CharSequence csq, final int start, final int end) {
167 		delegate.delegatePrint(csq.subSequence(start, end).toString());
168 		return this;
169 	}
170 
171 	@Override
172 	public synchronized PrintStream append(final CharSequence csq) {
173 		delegate.delegatePrint(csq.toString());
174 		return this;
175 	}
176 
177 	@Override
178 	public boolean checkError() {
179 		return originalPrintStream.checkError();
180 	}
181 
182 	@Override
183 	protected void setError() {
184 		originalPrintStream.println("WARNING - calling setError on SLFJPrintStream does nothing");
185 	}
186 
187 	@Override
188 	public void close() {
189 		originalPrintStream.close();
190 	}
191 
192 	@Override
193 	public void flush() {
194 		originalPrintStream.flush();
195 	}
196 
197 	@Override
198 	public synchronized PrintStream format(final Locale locale, final String format, final Object... args) {
199 		final String string = String.format(locale, format, args);
200 		delegate.delegatePrint(string);
201 		return this;
202 	}
203 
204 	@Override
205 	public synchronized PrintStream format(final String format, final Object... args) {
206 		return format(Locale.getDefault(), format, args);
207 	}
208 
209 	@Override
210 	public synchronized void print(final boolean bool) {
211 		delegate.delegatePrint(String.valueOf(bool));
212 	}
213 
214 	@Override
215 	public synchronized void print(final char character) {
216 		delegate.delegatePrint(String.valueOf(character));
217 	}
218 
219 	@Override
220 	public synchronized void print(final char[] charArray) {
221 		delegate.delegatePrint(String.valueOf(charArray));
222 	}
223 
224 	@Override
225 	public synchronized void print(final double doubl) {
226 		delegate.delegatePrint(String.valueOf(doubl));
227 	}
228 
229 	@Override
230 	public synchronized void print(final float floa) {
231 		delegate.delegatePrint(String.valueOf(floa));
232 	}
233 
234 	@Override
235 	public synchronized void print(final int integer) {
236 		delegate.delegatePrint(String.valueOf(integer));
237 	}
238 
239 	@Override
240 	public synchronized void print(final long lon) {
241 		delegate.delegatePrint(String.valueOf(lon));
242 	}
243 
244 	@Override
245 	public synchronized void print(final Object object) {
246 		delegate.delegatePrint(String.valueOf(object));
247 	}
248 
249 	@Override
250 	public synchronized void print(final String string) {
251 		delegate.delegatePrint(String.valueOf(string));
252 	}
253 
254 	@Override
255 	public synchronized PrintStream printf(final Locale locale, final String format, final Object... args) {
256 		return format(locale, format, args);
257 	}
258 
259 	@Override
260 	public synchronized PrintStream printf(final String format, final Object... args) {
261 		return format(format, args);
262 	}
263 
264 	@Override
265 	public void write(final byte[] buf, final int off, final int len) {
266 		originalPrintStream.write(buf, off, len);
267 	}
268 
269 	@Override
270 	public void write(final int integer) {
271 		originalPrintStream.write(integer);
272 	}
273 
274 	@Override
275 	public void write(final byte[] bytes) throws IOException {
276 		originalPrintStream.write(bytes);
277 	}
278 
279 	@Override
280 	public void registerLoggerAppender(final Object loggerAppenderObject) {
281 		final LoggerAppender loggerAppender = LoggerAppenderProxy.wrap(loggerAppenderObject);
282 		delegate.registerLoggerAppender(loggerAppender);
283 	}
284 
285 	@Override
286 	public void deregisterLoggerAppender() {
287 		delegate.deregisterLoggerAppender();
288 	}
289 
290 	@Override
291 	public PrintStream getOriginalPrintStream() {
292 		return originalPrintStream;
293 	}
294 }