001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002// The Molly framework is freely distributable under the terms of an
003// MIT-style license. For details, see the molly pages web site at:
004// http://www.mollypages.org/. Use, modify, have fun !
005
006package fc.io;
007
008import java.text.*;
009import java.util.*;
010import java.lang.reflect.*;
011
012import fc.util.*;
013
014/** 
015A system wide logging facility. Clearer and more elegant 
016semantics/nomenclature than <tt>java.util.logging</tt>.
017<p>
018Logs messages to some user specified destination(s). Each log has a
019<b>name</b> and a <b>log level</b>.
020<p>
021The names are arbitrary (hopefully descriptive) names, per your liking. Many
022different logs can be created and then later retrieved by their
023name as needed.
024<p>
025The levels provided by this class have the order:
026  <blockquote>
027  <tt>
028  OFF <b>&lt;</b> ERROR <b>&lt; </b>WARN <b>&lt;</b> INFO <b>&lt;</b> DEBUG
029  </tt>
030  </blockquote>
031The above levels are self-explanatory. 
032<p>
033Convenience methods with names equal to a <b>level</b> name are provided.
034So for example, instead of saying:
035  <blockquote>
036  <tt>log(<b>LogLevel.warn</b>, "the message");</tt>
037  </blockquote>
038one can say:
039  <blockquote>
040  <tt>log.<b>warn</b>("the message");</tt>
041  </blockquote>
042<p>
043<div style="border: 1px solid #ccc; padding: 1em;">
044A little historical quirk. For the debug level <tt>LogLevel.debug</b></tt>,
045one can say:
046  <blockquote>
047  <pre>
048  <tt>log.<b>debug</b>("the message");</tt> 
049     --<b>or</b>--
050  <tt>log.<b>bug</b>("the message");</tt> 
051  </pre>
052  </blockquote>
053</div>
054<p>
055A default logger of type {@link fc.io.SystemLog} is provided for
056convenience in this class and can be retrieved by calling the {@link
057#getDefault()} method.
058<p>
059The {@link #closeLog(String)} method is called on all logs
060at JVM shutdown.
061<p>
062<b>Note:</b>To log a full stack traces, pass the string obtained by the
063{@link IOUtil#throwableToString} method. (by default, an exception simply
064prints its message but not the full stack trace)
065<p>
066<b>Implementation Note</b>: subclasses should implement static
067<tt>getLog(..)</tt> type methods. These that create, as needed, and
068return a new log object of that subclass type. These getter methods
069should be static for convenience. Also, the implementation of the
070<tt>subclass.getLog(...)</tt> methods in subclasses is expected by
071convention.
072<p>
073Thread Safety: This class <tt>is</tt> Threadsafe and all its methods can
074be used concurrently.
075
076@author hursh jain
077**/
078public abstract class Log 
079{
080//--static variables--
081public static final LogLevel OFF  = new LogLevel("OFF",   0);
082public static final LogLevel ERROR  = new LogLevel("ERROR", 1);
083public static final LogLevel WARN = new LogLevel("WARN",  2);
084public static final LogLevel INFO = new LogLevel("INFO",  3);
085public static final LogLevel DEBUG  = new LogLevel("DEBUG", 4);
086
087/**
088The default level used for new logs. Subclasses should (by default) 
089create logs using this level.
090*/
091public static LogLevel DEFAULT_LEVEL = INFO;
092
093protected   static final byte[] linesepbytes = 
094            System.getProperty("line.separator").getBytes();
095
096            //synchronized map needed
097protected   static          SystemLog   defaultlog;
098protected   static final    Map         logs = new Hashtable(); 
099
100//--instance variables apply to a particular logger
101protected   String      name;
102protected   LogLevel    currentLevel;
103protected   long        startTime;  
104protected   String      startTimeString; //for toString()
105protected   boolean     printLevelName          = true;
106protected   boolean     printTimestamp          = false;
107protected   boolean     timestampIsRelative     = false;
108protected   LogLevel    printMethodInfoAtLevel  = DEBUG;
109
110//default timestamp data
111protected   final   SimpleDateFormat df 
112                        = new SimpleDateFormat("MMM dd H:m:s z");
113protected   final   NumberFormat nf     
114                        = NumberFormat.getNumberInstance();
115
116protected   Date        date        = new Date();
117protected   long        last_time   = date.getTime();
118protected   String      timestr     = df.format(date);
119
120//Add shutdown hook to close all open logs
121static 
122  {
123  Runtime.getRuntime().addShutdownHook(new Thread("fc.io.Log.Shutdown") {
124    public void run() 
125      {
126      System.out.println("JVM shutdown: fc.io.Log - closing all logs...");
127      Iterator i = logs.values().iterator();
128      while (i.hasNext())
129        ((Log)i.next()).close();
130      System.out.println();     
131      }
132    });
133  }
134
135
136/**
137Constructs a new Log. Can only be called from subclasses.
138
139@param  name      the name for the log -- any arbitrary
140            string denoting a conceptual category, 
141            destination, whatever
142@param  level     the initial logging level for this log
143*/
144protected Log(String name, LogLevel level) 
145  {
146  assert name != null : "name was null";
147  assert level != null : "level was null" ;
148  this.name = name;
149  this.currentLevel    = level;   
150  this.startTime       = System.currentTimeMillis();
151  this.startTimeString = new Date(startTime).toString();
152  }
153
154
155/**
156Returns a {@link SystemLog} with the specified name. If the log does not already
157exist, creates and returns a new SystemLog with that name.
158<p>
159The system log created will have a default destination of <tt>System.err</tt>
160and a default level of {@link Log#INFO}. 
161<p>
162To obtain logs with a different destination, create a SystemLog directly.
163*/
164public static Log get(String name)
165  {
166  Log log = (Log) logs.get(name);
167  if (log != null)
168    return log;
169    
170  synchronized(logs) {
171    log = new SystemLog(name);
172    logs.put(name, log);  
173    }
174    
175  return log;
176  }
177
178
179/**
180An alias for method {@link #get(String)}.
181<p>
182Returns a {@link SystemLog} with the specified name. If the log does not already
183exist, creates and returns a new SystemLog with that name.
184<p>
185The system log created will have a default destination of <tt>System.err</tt>
186and a default level of {@link Log#INFO}. 
187<p>
188To obtain logs with a different destination, create a SystemLog directly.
189*/
190public static Log getLog(String name)
191  {
192  return get(name);
193  }
194
195
196/**
197Convenience method that returns the log named after the <b>package</b> that
198the specified class belong to. If 2 classes <pre>a.b.Class1</pre> and
199<pre>a.b.Class2</pre> call this method, they will get the same logger
200(named <tt>a.b</tt>).
201<p>
202If the log does not already exist, creates and returns a new {@link SystemLog} 
203with that name.
204
205@param  c a non-null class
206*/
207public final static Log get(Class c) 
208  {
209  Argcheck.notnull(c, "class parameter was null");  
210  final Package p = c.getPackage();
211  final String name = (p == null) ? "default_pkg" : p.toString();
212  return get(name);
213  }
214
215/**
216Convenience method that returns a log named after the <b>package</b> that
217the specified object's class belong to. If 2 objects of class
218<pre>a.b.Class1</pre> and <pre>a.b.Class2</pre> call this method, they
219will get the same logger (named <tt>a.b</tt>).
220<p>
221If the log does not already exist, creates and returns a new {@link SystemLog} 
222with that name.
223
224@param  obj   a non-null object
225*/
226public final static Log get(Object obj) 
227  {
228  Argcheck.notnull(obj, "class parameter was null");  
229  return get(obj.getClass().getPackage().toString());
230  }
231
232/**
233Returns the default system log. This system log writes to
234<tt>System.err</tt> and has it's level set to {@link SystemLog#INFO}. This
235level can be changed to some other level if desired by invoking {@link
236setLevel()} on the returned object.
237*/
238public static SystemLog getDefault()
239  {
240  synchronized (Log.class)
241    {
242    if (defaultlog == null) {
243      defaultlog = new SystemLog(
244        "_defaultlog", System.out, SystemLog.INFO);
245      }
246    }   
247  return defaultlog;
248  }
249
250
251/**
252Returns an iteration containing level names for this log. The names can be in
253any order.
254*/
255public Iterator getLevelNames() 
256  {
257  Class myclass = getClass();
258  Field[] fields = myclass.getDeclaredFields();
259  Field levelfield = null;
260  List l = new ArrayList();
261  for (int n = 0; n < fields.length; n++) 
262    {
263    Field f = fields[n];
264    if (! f.getType().isAssignableFrom(LogLevel.class))
265      continue;
266    l.add(f.getName());
267    }
268  return l.iterator();
269  }
270
271/*
272Manually adds the specified log to the list of all logs. If a log with
273that name already exists, an <tt>IllegalArgumentException</tt> is thrown.
274<p> This method is useful when creating a new logging object manaually.
275So for example:
276  <blockquote>
277  <pre>
278  MyLogClass mylog = new MyLogClass("foo.bar");
279  Log.addLog(mylog)
280  </pre>
281  </blockquote>
282Contrast that with the more usual:
283  <blockquote>
284  <pre>
285  Log.getLog("foo.bar");
286  </pre>
287  </blockquote>
288<p>
289<u>Custom log implementations should always call this method in their
290constructor to add themselves to the list of all logs.</u>
291*/
292protected static void addLog(Log log)
293  {
294  synchronized(logs)
295    {
296    if (! logs.containsKey(log.name)) {
297      logs.put(log.name, log);  
298      } 
299    else throw new IllegalArgumentException("Log already exists: " + log);  
300    }
301  }
302
303/**
304Closes and removes the log with the specified name if it exists
305*/
306public static void closeLog(String name) 
307  {
308  if (logs.containsKey(name)) {
309    Log l = (Log) logs.get(name);
310    l.close();
311    logs.remove(name);
312    }
313  }
314
315/**
316Returns the method name, file number and line number
317of the calling method. Useful for logging/code tracing.
318
319@param  level   the level for which this logging call was invoked.  
320@param  framenum  the method to examine. This method itself
321          has frame number 0, the calling method
322          has frame number 1, it's parent 2 and so on.
323**/
324public final String getDebugContext(LogLevel level, int framenum) 
325  {
326  if (level.intval <  printMethodInfoAtLevel.intval) {
327    return "";
328    }
329    
330  StackTraceElement ste[] = new Exception().getStackTrace();
331  if (framenum >= ste.length)
332    throw new IllegalArgumentException(
333     "framenum [" + framenum 
334     + "] too large. Max number of record in stack = "
335     + (ste.length - 1)); 
336
337  //get method that called us, we are ste[0]
338  StackTraceElement st = ste[framenum];
339  String file = st.getFileName();
340  int line = st.getLineNumber();
341  String method = st.getMethodName();
342  String threadname = Thread.currentThread().getName();
343  //String classn = st.getClassName();
344  return method + "() [" + file + ":" + line + "/thread:" + threadname + "]";   
345  }
346
347
348/**
349If set to true, will print the level name before the logging
350message. For example, if the level is <code>INFO</code>, the 
351message is <code>foo</code>, then 
352  <blockquote>
353  INFO foo
354  </blockquote>
355will be printed. 
356<p>
357This is set to <tt>true</tt> by default.
358*/
359public void printLevelName(boolean printName)
360  {
361  printLevelName = printName;
362  }
363
364/**
365Prints a time stamp with every message. By default this
366is <tt>false</tt>
367
368@param  val    specify true to print time stamps, false
369         to not
370*/
371public void printTimestamp(boolean val) {
372  printTimestamp = val;
373  }
374
375/**
376Prints a relative time stamp with every message. By 
377default, printing any timestamp is <tt>false</tt>.
378<b>
379Timestamps must first be enabled via the {@link printTimestamp} 
380method before this method can have any effect.
381</b>
382
383@param  val   if true, prints a <b>relative</b> time
384        stamp. An initial timestamp is printed and
385        all succeeding timestamps are second
386        increments from the initial timestamp
387*/
388public void printRelativeTimestamp(boolean val) {
389  timestampIsRelative = val;
390  last_time = new Date().getTime();
391  }
392
393/**
394By default, method, line and thread information is printed wich each
395logging statement at the DEBUG level. Other levels print only the log
396message but skip the method/stack information.
397<p>
398This method allows method information to be printed at all levels greater
399than or equal to the specified level.
400*/
401public void printMethodInfoAtLevel(LogLevel level) {
402  this.printMethodInfoAtLevel = level;
403  }
404
405/** 
406A default implementation that returns an appropriate timestamp based on the
407timestamp setttings. <b> Multiple threads must synchronize access to this
408method </b>. Subclasses should call this method in their logging method
409implementations in the following way.
410<blockquote>
411Suppose the subclass uses an out object as a printwriter. Then
412<br>
413<code>
414<b>...in a synchronized block, typically around the output stream....</b>
415if (printTimestamp) {
416  out.print(getTS());
417  out.print(" ");
418  }
419.....
420</code>
421</blockquote>
422Of course subclasses are free to not call this method or 
423print timestamps in some other fashion.
424*/
425protected final String getTS()
426  {
427  date = new Date();
428  long now = date.getTime();
429
430  if (timestampIsRelative)
431    {
432    return nf.format( ((now - last_time) / 1000) ) ;  
433    }
434  else  //non relative ts
435    {
436    if (now - last_time >= 1000) {
437      last_time = now;
438      timestr = df.format(date);
439      }
440    }
441    
442  return timestr;
443  }
444
445/**
446Sets the current logging level for this logger. Each log has a logging
447level. A message is printed only if the message level is equal to or lower
448than the current maximum level for that log.
449<p>
450Typically, classes that implement a log will define a bunch of static
451variables of type {@link LogLevel} that list the available levels for that
452implementation. Clients of a particular log class should use levels
453defined within only that class.
454*/
455public void setLevel(LogLevel level) {
456  assert level != null : "specified level was null";
457  currentLevel = level;
458  }
459  
460/**
461Sets the level of this log based on a level description. This is
462convenient for when levels are specified in a configuration file. If the
463specified name cannot be converted into a level, then no change is made.
464
465@param  levelname the level name. For example, 
466          <tt>"info"</tt> would set the level of 
467          this log to <tt>INFO</tt>. The name
468          is case-<b>in</b>sensitive. 
469*/
470public void setLevel(String levelname) 
471  {
472  if (levelname == null) {
473    warn("specified levelname was null, log level will not be changed");
474    return;
475    }
476    
477  try {
478    Field levelfield = stringToLevel(levelname);
479    if (levelfield == null) {   
480      warn("Specified level", levelname, "is not valid/could not be resolved");
481      return;
482      }
483
484    Method method = Log.class.getMethod("setLevel", new Class[] { LogLevel.class });
485    //System.out.println("got method="+method);
486    method.invoke(this, new Object[] { levelfield.get(this) });
487    info("New log level for log=[", name ,"] set to: ", currentLevel);
488    }
489  catch (Exception e) {
490    warn(e);
491    }
492  }
493
494/*
495Returns a level field corresponding to the specified case-insensitive
496string.
497
498this is kinda overkill but hey: It takes about 5ms so speed
499isn't an issue and if we ever add more levels, we won't have to
500update this method.
501*/
502protected static Field stringToLevel(String levelname)
503  {
504  Field[] fields = Log.class.getDeclaredFields();
505  Field levelfield = null;
506  for (int n = 0; n < fields.length; n++) 
507    {
508    Field f = fields[n];
509    if (! f.getType().isAssignableFrom(LogLevel.class))
510      continue;
511    if (f.getName().equalsIgnoreCase(levelname))
512      levelfield = f;
513    }
514  return levelfield;
515  }
516  
517/**
518Sets the level for all logs whose name <b>contain</b> the specified name.
519This is convenient when changing log levels for package heirarchies. A
520empty string (non-null) "" sets the level for all logs.
521
522@param  levelname the level name. For example, 
523          <tt>"info"</tt> would set the level of 
524          this log to <tt>INFO</tt>. The name
525          is case-<b>in</b>sensitive. 
526*/
527public static void setLevelForAll(String name, LogLevel level)
528  {
529  Iterator i = logs.keySet().iterator();
530  while (i.hasNext()) {
531    String logname = (String) i.next();
532    if (logname.contains(logname))  {
533      ((Log)logs.get(logname)).setLevel(level);
534      }
535    }
536  }
537
538/**
539Sets the new default logging level for all new instances of loggers
540(that are created after this method is invoked).
541*/
542public static void setDefaultLevel(LogLevel level)
543  {
544  DEFAULT_LEVEL = level;
545  }
546
547/**
548Sets the new default logging level for all new instances of loggers
549(created after this method is invoked).
550*/
551public static void setDefaultLevel(String level)
552  {
553  if (level == null) {
554    new Exception("the specified level was null, log level will not be changed").printStackTrace();
555    return;
556    }
557    
558  try {
559    Field levelfield = stringToLevel(level);
560    if (levelfield == null)
561      return;
562      
563    Method method = Log.class.getMethod("setDefaultLevel", new Class[] { LogLevel.class });
564    //System.out.println("got method="+method);
565    method.invoke(null, new Object[] { levelfield.get(null) });
566    }
567  catch (Exception e) {
568    e.printStackTrace();
569    }
570  }
571
572/**
573Returns <tt>true</tt> if the log's current level will allow logging
574messages at the specified logging level.
575<p>
576Implementation Note: If the currentLevel is lesser or equal to the
577specified level returns true, else false. Subclasses can override this
578method if needed.
579
580@param  level the specified logging level
581*/
582public boolean canLog(LogLevel level) 
583  {
584  assert level != null : "specified level was null";
585  if (level.intval > currentLevel.intval)
586    return false;
587  return true;
588  }
589
590/**
591Returns the name of this log.
592*/
593public String getName() {
594  return name;
595  }
596
597/**
598Returns the current level set for this log. Useful when
599printing out debugging info.
600*/
601public LogLevel getLevel() {
602  return currentLevel;
603  }
604  
605public void logSystemInfo() 
606  { 
607  StringBuffer buf = new StringBuffer(1024);
608  Properties p = System.getProperties();
609  Enumeration e = p.propertyNames();
610  while (e.hasMoreElements()) {
611    buf.append(IOUtil.LINE_SEP);
612    String name = (String) e.nextElement();   
613    
614    buf.append(name).append("=");
615    
616    if (name.equals("line.separator")) {
617      buf.append(StringUtil.viewableAscii(p.getProperty(name)));
618      }
619    else{
620      buf.append(p.getProperty(name));
621      }
622    }
623  buf.append(IOUtil.LINE_SEP);    
624  info(buf.toString());
625  }
626
627public String toString()
628  {
629  return name + " [" + getClass().getName() + 
630      "/currentlevel:" + currentLevel.desc + 
631      "/started:" + startTimeString + "]";
632  }
633
634//--methods for various levels
635public final void error(final Object str1) {
636  doLog(ERROR, str1); 
637  }
638  
639public final void error(final Object str1, final Object str2) {
640  doLog(ERROR, str1, str2); 
641  }
642  
643public final void error(final Object str1, final Object str2, final Object str3) {
644  doLog(ERROR, str1, str2, str3); 
645  }
646
647public final void error(final Object str1, final Object str2, final Object str3, final Object str4) {
648  doLog(ERROR, str1, str2, str3, str4); 
649  }
650
651public final void error(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5) {
652  doLog(ERROR, str1, str2, str3, str4, str5); 
653  }
654
655public final void error(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6) {
656  doLog(ERROR, str1, str2, str3, str4, str5, str6); 
657  }
658
659public final void error(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7) {
660  doLog(ERROR, str1, str2, str3, str4, str5, str6, str7); 
661  }
662
663public final void error(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7, Object... args) {
664  doLog(ERROR, str1, str2, str3, str4, str5, str6, str7, args); 
665  }
666  
667public final void warn(final Object str1) {
668  doLog(WARN, str1);  
669  }
670  
671public final void warn(final Object str1, final Object str2) {
672  doLog(WARN, str1, str2);  
673  }
674  
675public final void warn(final Object str1, final Object str2, final Object str3) {
676  doLog(WARN, str1, str2, str3);  
677  }
678
679public final void warn(final Object str1, final Object str2, final Object str3, final Object str4) {
680  doLog(WARN, str1, str2, str3, str4);  
681  }
682
683public final void warn(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5) {
684  doLog(WARN, str1, str2, str3, str4, str5);  
685  }
686
687public final void warn(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6) {
688  doLog(WARN, str1, str2, str3, str4, str5, str6);  
689  }
690
691public final void warn(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7) {
692  doLog(WARN, str1, str2, str3, str4, str5, str6, str7);  
693  }
694
695public final void warn(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7, Object... args) {
696  doLog(WARN, str1, str2, str3, str4, str5, str6, str7, args);  
697  }
698
699public final void info(final Object str1) {
700  doLog(INFO, str1);  
701  }
702  
703public final void info(final Object str1, final Object str2) {
704  doLog(INFO, str1, str2);  
705  }
706  
707public final void info(final Object str1, final Object str2, final Object str3) {
708  doLog(INFO, str1, str2, str3);  
709  }
710
711public final void info(final Object str1, final Object str2, final Object str3, final Object str4) {
712  doLog(INFO, str1, str2, str3, str4);  
713  }
714  
715public final void info(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5) {
716  doLog(INFO, str1, str2, str3, str4, str5);  
717  }
718
719public final void info(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6) {
720  doLog(INFO, str1, str2, str3, str4, str5, str6);  
721  }
722
723public final void info(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7) {
724  doLog(INFO, str1, str2, str3, str4, str5, str6, str7);  
725  }
726
727public final void info(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7, Object... args) {
728  doLog(INFO, str1, str2, str3, str4, str5, str6, str7, args);  
729  }
730
731public final void debug(final Object str1) {
732  doLog(DEBUG, str1); 
733  }
734
735public final void debug(final Object str1, final Object str2) {
736  doLog(DEBUG, str1, str2); 
737  }
738  
739public final void debug(final Object str1, final Object str2, final Object str3) {
740  doLog(DEBUG, str1, str2, str3); 
741  }
742
743public final void debug(final Object str1, final Object str2, final Object str3, final Object str4) {
744  doLog(DEBUG, str1, str2, str3, str4); 
745  }
746
747public final void debug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5) {
748  doLog(DEBUG, str1, str2, str3, str4, str5); 
749  }
750
751public final void debug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6) {
752  doLog(DEBUG, str1, str2, str3, str4, str5, str6); 
753  }
754
755public final void debug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7) {
756  doLog(DEBUG, str1, str2, str3, str4, str5, str6, str7); 
757  }
758
759public final void debug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7, Object... args) {
760  doLog(DEBUG, str1, str2, str3, str4, str5, str6, str7, args); 
761  }
762
763public final void bug(final Object str1) {
764  doLog(DEBUG, str1); 
765  }
766
767public final void bug(final Object str1, final Object str2) {
768  doLog(DEBUG, str1, str2); 
769  }
770  
771public final void bug(final Object str1, final Object str2, final Object str3) {
772  doLog(DEBUG, str1, str2, str3); 
773  }
774
775public final void bug(final Object str1, final Object str2, final Object str3, final Object str4) {
776  doLog(DEBUG, str1, str2, str3, str4); 
777  }
778
779public final void bug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5) {
780  doLog(DEBUG, str1, str2, str3, str4, str5); 
781  }
782
783public final void bug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6) {
784  doLog(DEBUG, str1, str2, str3, str4, str5, str6); 
785  }
786
787public final void bug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7) {
788  doLog(DEBUG, str1, str2, str3, str4, str5, str6, str7); 
789  }
790
791public final void bug(final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7, Object... args) {
792  doLog(DEBUG, str1, str2, str3, str4, str5, str6, str7, args); 
793  }
794  
795final void doLog(final LogLevel level, final Object str1) 
796  {
797  if (level.intval > currentLevel.intval)
798    return;
799  
800  log(level, getDebugContext(level, 3), str1);
801  }
802
803final void doLog(final LogLevel level, final Object str1, final Object str2) 
804  {
805  if (level.intval > currentLevel.intval)
806    return;
807  
808  log(level, getDebugContext(level, 3), str1, str2);
809  }
810
811final void doLog(final LogLevel level, final Object str1, 
812         final Object str2, final Object str3) 
813  {
814  if (level.intval > currentLevel.intval)
815    return;
816  
817  log(level, getDebugContext(level, 3), str1, str2, str3);
818  }
819
820final void doLog(final LogLevel level, final Object str1, final Object str2, 
821         final Object str3, final Object str4) 
822  {
823  if (level.intval > currentLevel.intval)
824    return;
825  
826  log(level, getDebugContext(level, 3), str1, str2, str3, str4);
827  }
828
829final void doLog(final LogLevel level, final Object str1, final Object str2, 
830         final Object str3, final Object str4, final Object str5) 
831  {
832  if (level.intval > currentLevel.intval)
833    return;
834  
835  log(level, getDebugContext(level, 3), str1, str2, str3, str4, str5);
836  }
837
838final void doLog(final LogLevel level, final Object str1, final Object str2, 
839         final Object str3, final Object str4, final Object str5, 
840         final Object str6) 
841  {
842  if (level.intval > currentLevel.intval)
843    return;
844  
845  log(level, getDebugContext(level, 3), str1, str2, str3, str4, str5, str6);
846  }
847
848final void doLog(final LogLevel level, final Object str1, final Object str2, 
849         final Object str3, final Object str4, final Object str5, 
850         final Object str6, final Object str7) 
851  {
852  if (level.intval > currentLevel.intval)
853    return;
854  
855  log(level, getDebugContext(level, 3), str1, str2, str3, str4, str5, str6, str7);
856  }
857
858final void doLog(final LogLevel level, final Object str1, final Object str2, 
859         final Object str3, final Object str4, final Object str5, 
860         final Object str6, final Object str7, Object... args) 
861  {
862  if (level.intval > currentLevel.intval)
863    return;
864  
865  log(level, getDebugContext(level, 3), str1, str2, str3, str4, str5, str6, str7, args);
866  }
867
868
869//--abstract methods--
870
871public abstract void close();
872
873
874/**
875@param  level the current log level. This can be logged
876        as well.
877@param  str1  unless overridden in a subclass, this is the
878        value returned by {@link getDebugContext} and
879        is generated automatically by the warn(), 
880        info(), debug() etc., methods
881*/
882public abstract void log(LogLevel level, Object str1); 
883
884/**
885@param  level the current log level. This can be logged
886        as well.
887@param  str1  unless overridden in a subclass, this is the
888        value returned by {@link getDebugContext} and
889        is generated automatically by the warn(), 
890        info(), debug() etc., methods
891@param  str2_onwards  
892        some arbitrary object
893*/
894public abstract void log(LogLevel level, final Object str1, final Object str2);
895
896/**
897@param  level the current log level. This can be logged
898        as well.
899@param  str1  unless overridden in a subclass, this is the
900        value returned by {@link getDebugContext} and
901        is generated automatically by the warn(), 
902        info(), debug() etc., methods
903@param  str2_onwards  
904        some arbitrary object
905*/
906public abstract void log(LogLevel level, final Object str1, final Object str2, final Object str3);
907
908/**
909@param  level the current log level. This can be logged
910        as well.
911@param  str1  unless overridden in a subclass, this is the
912        value returned by {@link getDebugContext} and
913        is generated automatically by the warn(), 
914        info(), debug() etc., methods
915@param  str2_onwards  
916        some arbitrary object
917*/
918public abstract void log(LogLevel level, final Object str1, final Object str2, final Object str3, final Object str4);
919
920/**
921@param  level the current log level. This can be logged
922        as well.
923@param  str1  unless overridden in a subclass, this is the
924        value returned by {@link getDebugContext} and
925        is generated automatically by the warn(), 
926        info(), debug() etc., methods
927@param  str2_onwards  
928        some arbitrary object
929*/
930public abstract void log(LogLevel level, final Object str1, final Object str2, final Object str3, final Object str4, final Object str5);
931
932/**
933@param  level the current log level. This can be logged
934        as well.
935@param  str1  unless overridden in a subclass, this is the
936        value returned by {@link getDebugContext} and
937        is generated automatically by the warn(), 
938        info(), debug() etc., methods
939@param  str2_onwards  
940        some arbitrary object
941*/
942public abstract void log(LogLevel level, final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6);
943
944/**
945@param  level the current log level. This can be logged
946        as well.
947@param  str1  unless overridden in a subclass, this is the
948        value returned by {@link getDebugContext} and
949        is generated automatically by the warn(), 
950        info(), debug() etc., methods
951@param  str2_onwards  
952        some arbitrary object
953*/
954public abstract void log(LogLevel level, final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7);
955
956/**
957@param  level the current log level. This can be logged
958        as well.
959@param  str1  unless overridden in a subclass, this is the
960        value returned by {@link getDebugContext} and
961        is generated automatically by the warn(), 
962        info(), debug() etc., methods
963@param  str2_onwards  
964        some arbitrary object
965*/
966public abstract void log(LogLevel level, final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7, Object str8);
967
968/**
969@param  level the current log level. This can be logged
970        as well.
971@param  str1  unless overridden in a subclass, this is the
972        value returned by {@link getDebugContext} and
973        is generated automatically by the warn(), 
974        info(), debug() etc., methods
975@param  str2_onwards  
976        some arbitrary object
977*/
978public abstract void log(LogLevel level, final Object str1, final Object str2, final Object str3, final Object str4, final Object str5, final Object str6, final Object str7, Object str8, Object... args);
979}          //~class Log
980
981