Source code: konspire/common/log/Log.java
1 package konspire.common.log;
2
3 import java.util.*;
4 import java.text.*;
5
6
7 /**
8 * <code>Log</code> is the base class which defines
9 * all of the logging constants and implements any
10 * general logging responsibilities. It dispatches the actual
11 * logging information over to a concrete subclass of
12 * <code>AbstractLoggingMechanism</code> to do the work of writing
13 * out the log information. <p>
14 *
15 * This class could be extended to do application-specific behavior,
16 * or better yet you could create a class "wrapper" like <code>AppLog</code>
17 * to make instances well-known Singletons with handy static/class methods.
18 *
19 * @author Todd Lauinger
20 * @version $Revision: 1.3 $
21 *
22 * @see AbstractLoggingMechanism
23 * @see AppLog
24 */
25 public class Log {
26
27 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 // Constants section
29
30 // The following constants are levels for logging an error,
31 // with the lowest number the most detailed
32 // (and least critical) and the highest number the least detailed
33 // (and most critical).
34
35 /**
36 * Turns the log off, no messages are logged
37 */
38 public static final int DEACTIVATE_LEVEL = 0;
39
40 /**
41 * The system encountered a critical error at this logging level,
42 * which affects the accuracy, integrity, reliability, or
43 * capability of the system. Someone should be paged to address
44 * the error as soon as possible.
45 */
46 public static final int CRITICAL_ERROR_LEVEL = 1;
47
48 /**
49 * The system encountered an unexpected error at this logging level,
50 * which probably means the code intercepted an error it cannot handle.
51 * This error is not of a critical nature and can be recovered from
52 * automatically.
53 * Someone should probably be emailed to resolve the error in the near
54 * future to increase the reliability of the product.
55 */
56 public static final int ERROR_LEVEL = 2;
57
58 /**
59 * The system encountered an expected error situation. The system
60 * recovered from it but the fact that it happened should be recorded
61 * to see how frequent it happens.
62 */
63 public static final int WARNING_LEVEL = 3;
64
65 /**
66 * Normal logging level. All interesting periodic events should
67 * be logged at this level so someone looking through the log can
68 * see the amount and kind of processing happening in the system.
69 */
70 public static final int INFO_LEVEL = 4;
71
72 /**
73 * Moderately detailed logging level to be used to help debug
74 * typical problems in the system. Not so detailed that the
75 * big picture gets lost.
76 */
77 public static final int DETAIL_LEVEL = 5;
78
79 /**
80 * Most detailed logging level. Everything
81 * sent to the log will be logged. Use this level to
82 * trace system execution for really nasty problems.
83 */
84 public static final int TRACE_LEVEL = 6;
85
86
87 // The following constants define different output log mechanisms a log
88 // can accommodate.
89
90 /**
91 * Logging mechanism to log all messages to System.err
92 */
93 public static final String STANDARD_ERR_MECHANISM = StandardErrLoggingMechanism.class.getName();
94
95 /**
96 * Logging mechanism to log all messages to a unique file
97 * specific to that <code>Log</code> instance. Reuse the same
98 * log file name (append to it) if it already exists.
99 */
100 public static final String UNIQUE_FILE_MECHANISM = UniqueFileLoggingMechanism.class.getName();
101
102 /**
103 * Logging mechanism to log all messages to a unique
104 * file specific to that <code>Log</code> instance. Don't append
105 * to an existing log, instead create a new one with a date stamp.
106 */
107 public static final String UNIQUE_DATED_FILE_MECHANISM = UniqueDatedFileLoggingMechanism.class.getName();
108
109 /**
110 * Logging mechanism to log all messages to a shared
111 * file for any <code>Log</code> instances using this mechanism.
112 * Append to an existing log, if it already exists.
113 */
114 public static final String SHARED_FILE_MECHANISM = SharedFileLoggingMechanism.class.getName();
115
116 /**
117 * Logging mechanism to log all messages to a shared file
118 * for any <code>Log</code> instances using this mechanism.
119 * Don't append to an existing log, instead create a new one with a
120 * date stamp.
121 */
122 public static final String SHARED_DATED_FILE_MECHANISM = SharedDatedFileLoggingMechanism.class.getName();
123
124 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125 // Constructor section
126
127 /**
128 * Class constructor to properly create and register a new log. All other
129 * constructors and subclasses should eventually call this method!
130 */
131 protected Log() {
132
133 // Add the new Log instance to LogManager
134 LogManager.getInstance().addElement(this);
135 }
136
137 /**
138 * Public constructor to register a new log with a particular name.
139 * The name of the log is very important. It is used as a key into
140 * the log properties file to find settings for how the log is to
141 * be opened.
142 */
143 public Log(String name) {
144 this();
145 this.name = name;
146
147 // Get logging level and field separator from properties file
148 currentLoggingLevel =
149 LogProperties.getInstance().getLoggingLevel(this);
150 logFieldSeparator =
151 LogProperties.getInstance().getLogFieldSeparator(this);
152
153 System.out.println("Initializing log named " + name +
154 " at logging level " + currentLoggingLevel +
155 " with separator " + logFieldSeparator);
156
157 // Get a list of all of the mechanism names and open them
158 String mechanismName = null;
159 Enumeration e = LogProperties.getInstance().
160 getLoggingMechanismNames(this).elements();
161 while (e.hasMoreElements()) {
162 mechanismName = (String) e.nextElement();
163 addLoggingMechanism(mechanismName);
164 }
165
166 }
167
168
169 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170 // Instance Variable section
171
172 /**
173 * Keeps the name of the Log instance.
174 */
175 protected String name = "Log";
176
177 /**
178 * Keep the logging level the log is currently operating at.
179 */
180 protected int currentLoggingLevel;
181
182 /**
183 * Keeps a collection of logging mechanisms to use when
184 * writing out the log.
185 */
186 protected Vector loggingMechanisms = new Vector(10);
187
188 /**
189 * Keeps the date the log opened
190 */
191 protected Date dateOpened = new Date();
192
193
194 /**
195 * Keeps a string demarking fields within the log file.
196 */
197 protected String logFieldSeparator =
198 LogProperties.DEFAULT_LOG_FIELD_SEPARATOR;
199
200 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
201 // Instance method section
202
203 /**
204 * Gets the logging level of the current log.
205 */
206 public int getLoggingLevel() {
207
208 return currentLoggingLevel;
209 }
210
211 /**
212 * Changes the logging level of the current log.
213 *
214 * Use this method to activate, deactivate, or change the logging
215 * detail level of an active log.
216 */
217 synchronized public void setLoggingLevel(int newLoggingLevel) {
218
219 AbstractLoggingMechanism currentLoggingMechanism = null;
220
221 // See if we have to open or close the log
222 if (newLoggingLevel == Log.DEACTIVATE_LEVEL) {
223
224 if (currentLoggingLevel != Log.DEACTIVATE_LEVEL) {
225
226 // Must close the log.
227 // Close/deregister with all logging mechanisms
228 for (Enumeration e = loggingMechanisms.elements();
229 e.hasMoreElements(); ) {
230
231 currentLoggingMechanism = (AbstractLoggingMechanism)
232 e.nextElement();
233 currentLoggingMechanism.closeForLog(this);
234 }
235 }
236
237 } // Activating the log, see if we need to open it first
238 else if (currentLoggingLevel == Log.DEACTIVATE_LEVEL) {
239
240 // Open/register with each logging mechanism
241 for (Enumeration e = loggingMechanisms.elements();
242 e.hasMoreElements(); ) {
243
244 currentLoggingMechanism = (AbstractLoggingMechanism)
245 e.nextElement();
246 currentLoggingMechanism.openForLog(this, newLoggingLevel);
247 }
248
249 // Update dateOpened
250 dateOpened = new Date();
251
252 }
253
254 // Notify the log of the change if not deactivated
255 if ( (newLoggingLevel != Log.DEACTIVATE_LEVEL) &&
256 (currentLoggingLevel != Log.DEACTIVATE_LEVEL) )
257
258 for (Enumeration e = loggingMechanisms.elements();
259 e.hasMoreElements(); ) {
260 currentLoggingMechanism = (AbstractLoggingMechanism)
261 e.nextElement();
262 currentLoggingMechanism.notifyLoggingLevelChange(this, newLoggingLevel);
263 }
264
265 // Set the new logging level
266 currentLoggingLevel = newLoggingLevel;
267
268 }
269
270 /**
271 * Returns a <code>Vector</code> of logging mechanisms
272 * currently active for the log.
273 *
274 * @return a <code>Vector</code> of logging mechanisms
275 * currently active for the log.
276 */
277 public synchronized Vector getLoggingMechanisms() {
278 return this.loggingMechanisms;
279 }
280
281 /**
282 * If a logging mechanism of the type input is in effect for this log,
283 * return the logging mechanism instance matching the name given as
284 * input.
285 *
286 * @param loggingMechanismName Name of the logging mechanism to search for,
287 * one of the constants in the <code>Log</code> class.
288 *
289 * @return The concrete instance of an <code>AbstractLoggingMechanism</code>
290 * that is currently in effect for the Log if one found, null if not.
291 */
292 public synchronized AbstractLoggingMechanism getLoggingMechanism(String loggingMechanismName) {
293
294 AbstractLoggingMechanism currentLoggingMechanism = null;
295
296 // Run through the loggingMechanisms vector to try and find
297 // the mechanism for the name provided.
298 for (Enumeration e = loggingMechanisms.elements();
299 e.hasMoreElements(); ) {
300
301 currentLoggingMechanism = (AbstractLoggingMechanism)
302 e.nextElement();
303 if (currentLoggingMechanism.getName().equals(loggingMechanismName)) {
304 return currentLoggingMechanism;
305 }
306 }
307
308 // Not found in the enumeration, return null
309 return null;
310 }
311
312 /**
313 * Adds a Logging Mechanism to the list of mechanisms that this
314 * log writes to. Opens the mechanism and registers it also.
315 *
316 * @param loggingMechanismName The name of the Logging Mechanism.
317 *
318 * @return The concrete instance of <code>AbstractLoggingMechanism</code>
319 * that implements the mechanism just added, null if an error
320 * occurred like the log could not be opened or that log was
321 * previously opened!
322 */
323 public synchronized AbstractLoggingMechanism addLoggingMechanism(String loggingMechanismName) {
324
325 AbstractLoggingMechanism newLoggingMechanism = null;
326
327 System.out.println(" Adding log mechanism " + loggingMechanismName +
328 " to log " + this.getName());
329
330
331 // Try to find a duplicate. If found, log an error.
332 if (getLoggingMechanism(loggingMechanismName) != null) {
333 System.err.println("Error: Tried to open an already open logging mechanism: " +
334 loggingMechanismName);
335 System.err.println("Ignoring the call to re-open the logging mechanism");
336 return null;
337 }
338
339 try {
340 newLoggingMechanism =
341 AbstractLoggingMechanism.getLoggingMechanismForString(loggingMechanismName);
342 } catch (Throwable e) {
343 System.err.println("Exception caught: " + e.getMessage());
344 System.err.println("Unable to open logging mechanism " +
345 loggingMechanismName + " for log " + this.getName());
346 return null;
347 }
348
349 // Open the new mechanism and add it to the list of mechanisms currently logging to
350 newLoggingMechanism.openForLog(this, currentLoggingLevel);
351 loggingMechanisms.addElement(newLoggingMechanism);
352 return newLoggingMechanism;
353
354 }
355
356 /**
357 * Removes an active Logging Mechanism from the list of mechanisms that this
358 * log writes to. Closes the mechanism and deregisters it also.
359 *
360 * @param loggingMechanismName The name of the Logging Mechanism to remove.
361 *
362 */
363 public synchronized void removeLoggingMechanism(String loggingMechanismName) {
364
365 AbstractLoggingMechanism loggingMechanismToRemove = null;
366
367 // Try to find the open mechanism. If not found, log an error.
368 loggingMechanismToRemove = getLoggingMechanism(loggingMechanismName);
369 if (loggingMechanismToRemove == null) {
370 System.err.println("Error: Tried to close logging mechanism: " +
371 loggingMechanismName + " which is not open");
372 System.err.println("Ignoring the call to close the logging mechanism");
373 return;
374 }
375
376 loggingMechanismToRemove.closeForLog(this);
377 loggingMechanisms.removeElement(loggingMechanismToRemove);
378
379 }
380
381 /**
382 * Removes all Logging Mechanisms from the list of mechanisms that this
383 * log writes to. Closes the mechanisms and deregisters them also.
384 *
385 */
386 public synchronized void removeAllLoggingMechanisms() {
387
388 AbstractLoggingMechanism currentLoggingMechanism = null;
389
390 // Run through the loggingMechanisms vector and close the mechanisms
391 for (Enumeration e = loggingMechanisms.elements();
392 e.hasMoreElements(); ) {
393 currentLoggingMechanism = (AbstractLoggingMechanism)
394 e.nextElement();
395 currentLoggingMechanism.closeForLog(this);
396 }
397
398 loggingMechanisms.removeAllElements();
399 }
400
401
402 /**
403 * Adds a message string to the log if the log's level is
404 * currently set at or above the loggingLevel passed in.
405 *
406 * @param logString The string to write to all logging mechanisms
407 *
408 * @param loggingLevel The level at which to log the string.
409 */
410 synchronized public void logString(String logString, int loggingLevel) {
411
412 // Log the message if higher or equal to current logging level,
413 if (loggingLevel <= currentLoggingLevel) {
414
415 AbstractLoggingMechanism currentLoggingMechanism = null;
416
417 // Run through the loggingMechanisms vector and close the mechanisms
418 for (Enumeration e = loggingMechanisms.elements();
419 e.hasMoreElements(); ) {
420 currentLoggingMechanism = (AbstractLoggingMechanism)
421 e.nextElement();
422 currentLoggingMechanism.logString(this, loggingLevel, logString);
423 }
424 }
425 }
426
427 /**
428 * Must close the log for the application if the application did not or
429 * could not.
430 *
431 * @exception Throwable Default finalizer exception
432 */
433 protected void finalize() throws Throwable {
434
435 // If the log file is open must address open mechanisms
436 if (isOpen()) {
437 removeAllLoggingMechanisms();
438 }
439
440 super.finalize();
441 }
442
443
444 /**
445 * Gets the string that delimits the various fields of a log entry
446 */
447 public String getLogFieldSeparator() {
448
449 return logFieldSeparator;
450 }
451
452 /**
453 * Sets the string that delimits the various fields of a log entry
454 */
455 public void setLogFieldSeparator(String logFieldSeparator) {
456
457 this.logFieldSeparator = logFieldSeparator;
458 }
459
460 /**
461 * Return the name of the log, usually passed in by the constructor.
462 */
463 public String getName() {
464 return name;
465 }
466
467 /**
468 * Return whether the log is open (is not deactivated).
469 */
470 public boolean isOpen() {
471
472 return (currentLoggingLevel != Log.DEACTIVATE_LEVEL);
473 }
474
475 /**
476 * Return the date the log was opened, only valid if the log is
477 * currently open.
478 */
479 public Date getDateOpened() {
480
481 return dateOpened;
482 }
483
484 }