View Javadoc

1   /*
2   Copyright (c) 2005, CodeSmarts
3    All rights reserved.
4   
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are
7   met:
8   	* 	Redistributions of source code must retain the above copyright
9   notice, this list of conditions and the following disclaimer.
10  	* 	Redistributions in binary form must reproduce the above
11  copyright notice, this list of conditions and the following disclaimer
12  in the documentation and/or other materials provided with the
13  distribution.
14  	* 	Neither the name of the CodeSmarts nor the names of its
15  contributors may be used to endorse or promote products derived from
16  this software without specific prior written permission.
17  
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30  
31  package net.codesmarts.log4j;
32  
33  import org.apache.log4j.AppenderSkeleton;
34  import org.apache.log4j.Layout;
35  import org.apache.log4j.Level;
36  import org.apache.log4j.Priority;
37  import org.apache.log4j.spi.LoggingEvent;
38  import org.apache.log4j.spi.OptionHandler;
39  
40  import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
41  
42  
43  /***
44   * Base class for BugReport Appenders
45   * 
46   * @author Fred McCann
47   */
48  public abstract class AbstractBugReportAppender extends AppenderSkeleton 
49  	implements OptionHandler, BugReportAppender {  
50  
51      /***
52       * Flag to determine if this thread has been registered 
53       * with the controller for this appender
54       */
55      private ThreadLocal _registered = new ThreadLocal() {
56          protected synchronized Object initialValue() {
57              return new Boolean(false);
58          }        
59      };
60      
61      /***
62       * Get a reference to the controller
63       */
64      private static final BugReportController controller = BugReportController.getInstance();
65      
66      /***
67       * Flag specifying if this appender has been initialized
68       */
69      private SynchronizedBoolean _initialized = new SynchronizedBoolean(false);
70      
71      /***
72       * Toggle reporting duplicate reports
73       */
74      private boolean _reportDuplicates = false;
75                              
76      /***
77       * threshold logging priority- an event of this level causes
78       * the buffer to be flushed to output device. Default priority
79       * is ERROR
80       */
81      private Priority _thresholdPriority = Level.ERROR;
82      
83      /***
84       * threshold size
85       */
86      private int _thresholdSize = 100;  
87      
88      /***
89       * Maximum buffer size
90       */
91      private int _maxSize = 200;      
92      
93      /***
94       * Method used to create semiunique hash keys.
95       */      
96      private int _hashMethod = HashUtility.LOCATION;    
97              
98      /***
99       * The maximum number of logging events allowed in a single report. Defaults to 200
100      * @return Returns the _maxSize.
101      */
102     public int getMaxSize() {
103         return _maxSize;
104     }
105     
106     /***
107      * Set the maximum size of the log buffer
108      * @param size The _maxSize to set.
109      */
110     public void setMaxSize(int size) {
111         _maxSize = size;
112     }   
113             
114     /***
115      * The threshold priority is the priority required to generate a bug report.
116      * @return Returns the thresholdLevel.
117      */
118     public Priority getThresholdPriority() {
119         return _thresholdPriority;
120     }
121     
122     /***
123      * Bug Reports are triggered when a logging event of this priority is detected
124      * @param thresholdLevel The thresholdLevel to set.
125      */
126     public void setThresholdPriority(Priority thresholdPriority) {
127         _thresholdPriority = thresholdPriority;
128     }
129 
130     /***
131      * For short running threads (like serlvet requets/reponse handlers), a log report is generated when the
132      * application thread dies. For longer running threads, a threadhold size is used. If a watch thread wakes
133      * from sleep and there are events in the buffer at or greater than the threshold size and there is at least
134      * one event of sufficient priority level, a bug report is generated. This defaults to 100
135      * @return Returns the _thresholdSize.
136      */
137     public int getThresholdSize() {
138         return _thresholdSize;
139     }
140     
141     /***
142      * Set the threadhold size of the event buffer
143      * @param size The _thresholdSize to set.
144      */
145     public void setThresholdSize(int size) {
146         _thresholdSize = size;
147     }
148        
149     /***
150      * @see org.apache.log4j.spi.OptionHandler#activateOptions()
151      */
152     public final synchronized void activateOptions() {
153         super.activateOptions();
154         this.init();
155         _initialized.set(true);
156     }
157     
158     /***
159      * Append an logging event
160      * @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent)
161      */
162     public synchronized void doAppend(LoggingEvent event) {        
163         if (closed) {
164             getErrorHandler().error("Attempted to append to closed appender named ["+name+"].");
165             return;
166         }                
167         
168         // Wait until this appender is initialized before appending messages
169         while (_initialized.get()!=true) {}
170         
171         // If this thread is not yet regisered, register it
172         Boolean reg = (Boolean)_registered.get();
173         if (reg.booleanValue()==false) {
174             _registered.set(new Boolean(true));
175             controller.registerLog(Thread.currentThread(),this);
176         }
177         
178         // Add event to queue
179         event.getThreadName(); /* calling this appears to set the thread name on the event properly */
180         controller.addEvent(Thread.currentThread(),this,event);
181     }
182         
183     /***
184      * Append a bug report
185      */
186     public abstract void append(BugReport report);
187     
188     /***
189      * initialize appender (use this instead of activateOptions)
190      */
191     public abstract void init();    
192 
193     /***
194      * This method does nothing, use append(BugReport)
195      */
196     protected final void append(LoggingEvent event) {        
197     }
198                        
199     /***
200      * @see org.apache.log4j.Appender#close()
201      */
202     public void close() {
203         if (this.closed)
204             return;
205         this.closed = true;
206     }
207 
208     /***
209      * @see org.apache.log4j.Appender#requiresLayout()
210      */
211     public boolean requiresLayout() {
212         return true;
213     }
214     
215     /***
216      * @see org.apache.log4j.Appender#setLayout(org.apache.log4j.Layout)
217      */
218     public void setLayout(Layout layout) {
219         super.setLayout(layout);
220     }
221         
222     /***
223      * This returns true if this appender is configured to file duplicate reports. This defaults
224      * to false
225      * @return Returns the reportDuplicates.
226      */
227     public boolean isReportDuplicates() {
228         return _reportDuplicates;
229     }
230     
231     /***
232      * Set the flag to report duplicate Bug Reports
233      * @param reportDuplicates The reportDuplicates to set.
234      */
235     public void setReportDuplicates(boolean reportDuplicates) {
236         _reportDuplicates = reportDuplicates;
237     }       
238     
239     /***
240      * Set the hash method for creating semiunique keys. Valid options are: LOCATION, CONTENT, and THROWABLE.
241      * Defaults to LOCATION
242      * @param method
243      */
244     public void setHashingMethod(String m) {
245         String hashMethod = m.toLowerCase();
246         
247         if (hashMethod.equals("location"))
248             _hashMethod = HashUtility.LOCATION;
249         else if (hashMethod.equals("content"))
250             _hashMethod = HashUtility.CONTENT;
251         else if (hashMethod.equals("throwable"))
252             _hashMethod = HashUtility.THROWABLE;
253         else {
254             getErrorHandler().error("Invalid hash method: "+m+" for logger "+getClass().getName());
255             close();
256         }
257 
258     }
259        
260     /***
261      * Get the hash method specified by this appender
262      * @return Returns the _hashMethod.
263      */
264     public String getHashingMethod() {
265         switch (_hashMethod) {
266 			case HashUtility.LOCATION: return "Location";
267 			case HashUtility.CONTENT: return "Content";
268 			case HashUtility.THROWABLE: return "Throwable";
269 			default: return "Location";	
270         }
271     }
272 
273     /***
274      * Get the hash method specified by this appender
275      * @return Returns the _hashMethod.
276      */
277     public int getHashMethod() {
278         return _hashMethod;
279     }
280 
281 }