1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
169 while (_initialized.get()!=true) {}
170
171
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
179 event.getThreadName();
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 }