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.tomcat.util.log;
18
19 import java.io.IOException;
20 import java.io.PrintStream;
21 import java.util.EmptyStackException;
22 import java.util.Stack;
23
24 /**
25  * This helper class may be used to do sophisticated redirection of
26  * System.out and System.err on a per Thread basis.
27  *
28  * A stack is implemented per Thread so that nested startCapture
29  * and stopCapture can be used.
30  *
31  * @author Remy Maucherat
32  * @author Glenn L. Nielsen
33  */

34 public class SystemLogHandler extends PrintStream {
35
36
37     // ----------------------------------------------------------- Constructors
38
39
40     /**
41      * Construct the handler to capture the output of the given steam.
42      *
43      * @param wrapped The stream to capture
44      */

45     public SystemLogHandler(PrintStream wrapped) {
46         super(wrapped);
47         out = wrapped;
48     }
49
50
51     // ----------------------------------------------------- Instance Variables
52
53
54     /**
55      * Wrapped PrintStream.
56      */

57     private final PrintStream out;
58
59
60     /**
61      * Thread <-> CaptureLog associations.
62      */

63     private static final ThreadLocal<Stack<CaptureLog>> logs = new ThreadLocal<>();
64
65
66     /**
67      * Spare CaptureLog ready for reuse.
68      */

69     private static final Stack<CaptureLog> reuse = new Stack<>();
70
71
72     // --------------------------------------------------------- Public Methods
73
74
75     /**
76      * Start capturing thread's output.
77      */

78     public static void startCapture() {
79         CaptureLog log = null;
80         if (!reuse.isEmpty()) {
81             try {
82                 log = reuse.pop();
83             } catch (EmptyStackException e) {
84                 log = new CaptureLog();
85             }
86         } else {
87             log = new CaptureLog();
88         }
89         Stack<CaptureLog> stack = logs.get();
90         if (stack == null) {
91             stack = new Stack<>();
92             logs.set(stack);
93         }
94         stack.push(log);
95     }
96
97
98     /**
99      * Stop capturing thread's output.
100      *
101      * @return The captured data
102      */

103     public static String stopCapture() {
104         Stack<CaptureLog> stack = logs.get();
105         if (stack == null || stack.isEmpty()) {
106             return null;
107         }
108         CaptureLog log = stack.pop();
109         if (log == null) {
110             return null;
111         }
112         String capture = log.getCapture();
113         log.reset();
114         reuse.push(log);
115         return capture;
116     }
117
118
119     // ------------------------------------------------------ Protected Methods
120
121
122     /**
123      * Find PrintStream to which the output must be written to.
124      * @return the print stream
125      */

126     protected PrintStream findStream() {
127         Stack<CaptureLog> stack = logs.get();
128         if (stack != null && !stack.isEmpty()) {
129             CaptureLog log = stack.peek();
130             if (log != null) {
131                 PrintStream ps = log.getStream();
132                 if (ps != null) {
133                     return ps;
134                 }
135             }
136         }
137         return out;
138     }
139
140
141     // ---------------------------------------------------- PrintStream Methods
142
143
144     @Override
145     public void flush() {
146         findStream().flush();
147     }
148
149     @Override
150     public void close() {
151         findStream().close();
152     }
153
154     @Override
155     public boolean checkError() {
156         return findStream().checkError();
157     }
158
159     @Override
160     protected void setError() {
161         //findStream().setError();
162     }
163
164     @Override
165     public void write(int b) {
166         findStream().write(b);
167     }
168
169     @Override
170     public void write(byte[] b)
171         throws IOException {
172         findStream().write(b);
173     }
174
175     @Override
176     public void write(byte[] buf, int off, int len) {
177         findStream().write(buf, off, len);
178     }
179
180     @Override
181     public void print(boolean b) {
182         findStream().print(b);
183     }
184
185     @Override
186     public void print(char c) {
187         findStream().print(c);
188     }
189
190     @Override
191     public void print(int i) {
192         findStream().print(i);
193     }
194
195     @Override
196     public void print(long l) {
197         findStream().print(l);
198     }
199
200     @Override
201     public void print(float f) {
202         findStream().print(f);
203     }
204
205     @Override
206     public void print(double d) {
207         findStream().print(d);
208     }
209
210     @Override
211     public void print(char[] s) {
212         findStream().print(s);
213     }
214
215     @Override
216     public void print(String s) {
217         findStream().print(s);
218     }
219
220     @Override
221     public void print(Object obj) {
222         findStream().print(obj);
223     }
224
225     @Override
226     public void println() {
227         findStream().println();
228     }
229
230     @Override
231     public void println(boolean x) {
232         findStream().println(x);
233     }
234
235     @Override
236     public void println(char x) {
237         findStream().println(x);
238     }
239
240     @Override
241     public void println(int x) {
242         findStream().println(x);
243     }
244
245     @Override
246     public void println(long x) {
247         findStream().println(x);
248     }
249
250     @Override
251     public void println(float x) {
252         findStream().println(x);
253     }
254
255     @Override
256     public void println(double x) {
257         findStream().println(x);
258     }
259
260     @Override
261     public void println(char[] x) {
262         findStream().println(x);
263     }
264
265     @Override
266     public void println(String x) {
267         findStream().println(x);
268     }
269
270     @Override
271     public void println(Object x) {
272         findStream().println(x);
273     }
274
275 }
276