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