KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > server > logging > SystemOutandErrHandler


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.server.logging;
25 import com.sun.enterprise.J2EESecurityManager;
26
27 import java.util.logging.Logger JavaDoc;
28 import java.util.logging.Level JavaDoc;
29 import java.util.logging.Handler JavaDoc;
30 import java.util.logging.Filter JavaDoc;
31 import java.util.logging.ConsoleHandler JavaDoc;
32 import java.util.logging.ErrorManager JavaDoc;
33 import java.util.logging.LogManager JavaDoc;
34
35 import java.io.*;
36 import java.util.*;
37
38 import com.sun.logging.LogDomains;
39
40
41 /**
42  * Class SystemOutandErrHandler extends PrintStream & is for use within the
43  * Application Server. The init is called from PEMain and this creates 2
44  * instances of this class - one for Err & other for Out.
45  *
46  * This is not expected to be performance intensive and hence more defensive
47  * programming is done to reduce risk.
48  */

49 public class SystemOutandErrHandler {
50
51     private static final String JavaDoc SYSTEMERR_LOGGER = "javax.enterprise.system.stream.err";
52     private static final String JavaDoc SYSTEMOUT_LOGGER = "javax.enterprise.system.stream.out";
53     private static PrintStream originalSystemErr;
54     private static Logger JavaDoc soLogger = null;
55     private static Logger JavaDoc seLogger = null;
56     private static Level JavaDoc errLogLevel = Level.WARNING;
57     private static Level JavaDoc outLogLevel = Level.INFO;
58     private static String JavaDoc lineSeparator;
59     private static int lineSeparatorSize;
60     private LoggingPrintStream lout, lerr;
61
62     public SystemOutandErrHandler() {
63         if (originalSystemErr != null) {
64         RuntimeException JavaDoc e = new RuntimeException JavaDoc("recursivecall");
65                 originalSystemErr.println("recursive call into SystemOutandErrhandler");
66                 e.printStackTrace(originalSystemErr);
67         return;
68         }
69
70         LoggingByteArrayOutputStream buf = new LoggingByteArrayOutputStream();
71         // Initialise logger and set new systemout
72
seLogger = java.util.logging.Logger.getLogger(SYSTEMERR_LOGGER);
73         // seLogger = LogDomains.getLogger(LogDomains.SYSTEMERR_LOGGER, false);
74
buf.setLogger(seLogger, errLogLevel);
75             originalSystemErr = System.err;
76         lerr = (new LoggingPrintStream(buf));
77             lerr.setLogger(seLogger);
78         System.setErr(lerr);
79
80         buf = new LoggingByteArrayOutputStream();
81         // Initialise logger and set new systemout
82
soLogger = java.util.logging.Logger.getLogger(SYSTEMOUT_LOGGER);
83         buf.setLogger(soLogger, outLogLevel);
84         lout = (new LoggingPrintStream(buf));
85             lout.setLogger(soLogger);
86         System.setOut(lout);
87
88         lineSeparator = (String JavaDoc) java.security.AccessController.doPrivileged(
89         new sun.security.action.GetPropertyAction("line.separator"));
90         lineSeparatorSize = lineSeparator.length();
91
92     }
93
94 /*
95  * LoggingPrintStream creates a PrintStream with a
96  * LoggingByteArrayOutputStream as its OutputStream. Once it is
97  * set as the System.out or System.err, all outputs to these
98  * PrintStreams will end up in LoggingByteArrayOutputStream
99  * which will log these on a flush.
100  * This simple behavious has a negative side effect that
101  * stack traces are logged with each line being a new log record.
102  * The reason for above is that printStackTrace converts each line
103  * into a separate println, causing a flush at the end of each.
104  * One option that was thought of to smooth this over was to see
105  * if the caller of println is Throwable.[some set of methods].
106  * Unfortunately, there are others who interpose on System.out and err
107  * (like jasper) which makes that check untenable.
108  * Hence the logic currently used is to see if there is a println(Throwable)
109  * and do a printStackTrace and log the complete StackTrace ourselves.
110  * If this is followed by a series of printlns, then we keep ignoring
111  * those printlns as long as they were the same as that recorded by
112  * the stackTrace. This needs to be captured on a per thread basis
113  * to take care of potentially parallel operations.
114  * Care is taken to optimise the frequently used path where exceptions
115  * are not being printed.
116  */

117
118     private class LoggingPrintStream extends PrintStream {
119         private ByteArrayOutputStream bufOut;
120             private Logger JavaDoc logger=null;
121             LogManager JavaDoc logManager=null;
122         private ThreadLocal JavaDoc perThreadStObjects = new ThreadLocal JavaDoc();
123
124
125         public LoggingPrintStream(LoggingByteArrayOutputStream buf) {
126         // create printStream with autoflush set to true
127
super(buf, true);
128         bufOut = buf;
129                 logManager = LogManager.getLogManager( );
130         }
131
132             public void setLogger(Logger JavaDoc l) {
133                 logger=l;
134             }
135
136         public void println(Object JavaDoc x) {
137                 if (!checkLocks()) return;
138
139             StackTraceObjects sTO;
140
141         if ( (sTO = (StackTraceObjects) perThreadStObjects.get()) != null ) {
142             /*
143              * should not happen, but being safe.
144              * Only case under which we can come here is if there is
145              * code which does synchronized(System.err) and then does
146              * System.err.println(Throwable) without printing stackTrace
147              * other than java.lang.Throwable. We could have done
148              * this check prior to the check on holdsLock, but since
149              * that is the most common path, let us avoid any overhead
150              * println(String) will also do above check and hence there
151              * is no danger of missing out on valid printlns
152              */

153             perThreadStObjects.set(null);
154         }
155
156         if ( !(x instanceof java.lang.Throwable JavaDoc) ) {
157             // No special processing if it is not an exception.
158
super.println(x);
159             return;
160         }
161
162         // if we pass all these checks, then we log the stacktrace
163
sTO = new StackTraceObjects((Throwable JavaDoc)x);
164         perThreadStObjects.set(sTO);
165         super.println(sTO.toString());
166         }
167         public void println(String JavaDoc str) {
168                 if (!checkLocks()) return;
169
170             StackTraceObjects sTO;
171         sTO = (StackTraceObjects) perThreadStObjects.get();
172         if ( sTO == null ) {
173             // lets get done with the common case fast
174
super.println(str);
175             return;
176         }
177
178         if ( !sTO.ignorePrintln(str) ) {
179             perThreadStObjects.set(null);
180             super.println(str);
181             return;
182         }
183
184         if (sTO.checkCompletion()) {
185             perThreadStObjects.set(null);
186             return;
187         }
188         }
189
190             public void print(String JavaDoc x) {
191                 if (checkLocks())
192                     super.print(x);
193             }
194
195
196             public void print(Object JavaDoc x) {
197                 if (checkLocks())
198                     super.print(x);
199             }
200
201             public void print(boolean x) {
202                 if (checkLocks()) {
203                 super.print(x);
204                 }
205             }
206             public void println(boolean x) {
207                 if (checkLocks())
208                     super.println(x);
209             }
210
211             public void print(char x) {
212                 if (checkLocks()) {
213                super.print(x);
214                 }
215             }
216             public void println(char x) {
217                 if (checkLocks())
218                    super.println(x);
219             }
220
221             public void print(int x) {
222                 if (checkLocks()) {
223                 super.print(x);
224                 }
225             }
226             public void println(int x) {
227                 if (checkLocks())
228                     super.println(x);
229             }
230
231             public void print(long x) {
232                 if (checkLocks()) {
233                 super.print(x);
234                 }
235             }
236             public void println(long x) {
237                 if (checkLocks())
238                     super.println(x);
239             }
240
241             public void print(float x) {
242                 if (checkLocks()) {
243                 super.print(x);
244                 }
245             }
246             public void println(float x) {
247                 if (checkLocks())
248                     super.println(x);
249             }
250
251             public void print(double x) {
252                 if (checkLocks()) {
253                 super.print(x);
254                 }
255             }
256             public void println(double x) {
257                 if (checkLocks())
258                     super.println(x);
259             }
260  
261             public void print(char[] x) {
262                 if (checkLocks()) {
263                 super.print(x);
264                 }
265             }
266             public void println(char[] x) {
267                 if (checkLocks())
268                     super.println(x);
269             }
270
271
272             public void println() {
273                 if (checkLocks()) {
274                 super.println();
275                 }
276             }
277         
278             public void write(byte[] buf, int off, int len) {
279                 if (checkLocks()) {
280                 super.write(buf,off,len);
281                 }
282             }
283
284             public void write(int b) {
285                 if (checkLocks()) {
286                 super.write(b);
287                 }
288             }
289         
290             /*
291               LoggingPrintStream class is to support the java System.err and System.out
292               redirection to Appserver log file--server.log.
293               When Java IO is redirected and System.out.println(...) is invoked by a thread with
294               LogManager or Logger(SYSTEMERR_LOGGER,SYSTEOUT_LOGGER) locked, all kind of dead
295               locks among threads will happen.
296               These dead locks are easily reproduced when jvm system properties
297               "-Djava.security.manager" and "-Djava.security.debug=access,failure" are defined.
298               These dead lcoks are basically because each thread has its own sequence of
299               acquiring lock objects(LogManager,Logger,FileandSysLogHandler, the buffer inside
300               LoggingPrintStream).
301               There is no obvious way to define the lock hierarchy and control the lock sequence;
302               Trylock is not a strightforward solution either.Beside they both create heavy
303               dependence on the detail implementation of JDK and Appserver.
304               
305               This method(checkLocks) is to find which locks current thread has and
306               LoggingPrintStream object will decide whether to continue to do printing or
307               give ip up to avoid the dead lock.
308              */

309             private boolean checkLocks() {
310                 Thread JavaDoc t = Thread.currentThread();
311                 if ( !t.holdsLock(logger) && !t.holdsLock(logManager) ) {
312                    return true;
313                 }
314                 return false;
315             }
316     }
317
318
319 /*
320  * Creates an OutputStream in which we capture the output and log
321  * to the logfile on a flush call
322  */

323     private class LoggingByteArrayOutputStream extends ByteArrayOutputStream {
324         private Level JavaDoc logLevel;
325         private Logger JavaDoc logger;
326         private boolean recursiveWarnIssued = false;
327         private boolean inFlush = false;
328
329         public LoggingByteArrayOutputStream() {
330             super();
331         }
332         public void flush() throws IOException {
333             if (super.size() == 0) {
334             // avoid empty lines on multiple flushes
335
return;
336             }
337             if ((super.size() == lineSeparatorSize) &&
338             super.toString().equals(lineSeparator)) {
339             // avoid empty lineseparator on multiple flushes
340
return;
341             }
342             synchronized (this) {
343             if (inFlush) {
344                         //originalSystemErr.println(this.toString()); //originalSystemErr IS System.err.
345
if (!recursiveWarnIssued) {
346                 RuntimeException JavaDoc e = new RuntimeException JavaDoc("recursivecall");
347                         originalSystemErr.println("recursive call into SystemOutandErrhandler");
348                         e.printStackTrace(originalSystemErr);
349                 recursiveWarnIssued = true;
350                 }
351                 return;
352             }
353             inFlush = true;
354             super.flush();
355             logger.log(logLevel, this.toString());
356             inFlush = false;
357             super.reset();
358                     }
359         }
360         public void setLogger(Logger JavaDoc systemlogger, Level JavaDoc loglevel) {
361             logger = systemlogger;
362             logLevel = loglevel;
363         }
364     }
365     
366
367 /*
368  * StackTraceObjects keeps track of StackTrace printed
369  * by a thread as a result of println(Throwable) and
370  * it keeps track of subsequent println(String) to
371  * avoid duplicate logging of stacktrace
372  */

373     private class StackTraceObjects {
374
375         private ByteArrayOutputStream stackTraceBuf;
376         private PrintStream stStream;
377         private String JavaDoc stString;
378         private ByteArrayOutputStream comparisonBuf;
379         private int comparisonBufIndex = 0;
380         private PrintStream cbStream;
381         private int stackTraceBufBytes = 0;
382         private int charsIgnored = 0;
383
384         private StackTraceObjects(Throwable JavaDoc x) {
385         // alloc buffer for getting stack trace.
386
stackTraceBuf = new ByteArrayOutputStream();
387         stStream = new PrintStream(stackTraceBuf, true);
388         comparisonBuf = new ByteArrayOutputStream();
389         cbStream = new PrintStream(comparisonBuf, true);
390         ((Throwable JavaDoc)x).printStackTrace(stStream);
391         stString = stackTraceBuf.toString();
392         stackTraceBufBytes = stackTraceBuf.size();
393         // helps keep our stack trace skipping logic simpler.
394
cbStream.println(x);
395         }
396
397         public String JavaDoc toString() {
398         return stString;
399         }
400
401         boolean ignorePrintln(String JavaDoc str) {
402         String JavaDoc cbString;
403         int cbLen;
404         cbStream.println(str);
405         cbString = comparisonBuf.toString();
406         cbLen = cbString.length();
407         if (stString.regionMatches(charsIgnored, cbString, 0, cbLen)) {
408             charsIgnored+= cbLen;
409             comparisonBuf.reset();
410             return true;
411         }
412
413         return false;
414
415         }
416
417         boolean checkCompletion() {
418         if ( charsIgnored >= stackTraceBufBytes ) {
419             return true;
420         } else {
421             return false;
422         }
423         }
424     }
425 }
426
Popular Tags