[slf4j-dev] svn commit: r1079 - in slf4j/trunk: slf4j-ext/src/main/java/org/slf4j/profiler slf4j-ext/src/test/java/org/slf4j/profiler slf4j-ext/src/test/resources slf4j-site/src/site/pages

ceki at slf4j.org ceki at slf4j.org
Mon Jul 28 22:57:42 CEST 2008


Author: ceki
Date: Mon Jul 28 22:57:41 2008
New Revision: 1079

Added:
   slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/BasicProfilerDemo.java
   slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/NestedProfilerDemo.java
      - copied, changed from r1075, /slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerDemo.java
   slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/NestedProfilerDemo2.java
   slf4j/trunk/slf4j-ext/src/test/resources/
   slf4j/trunk/slf4j-ext/src/test/resources/log4j.properties
   slf4j/trunk/slf4j-site/src/site/pages/support.html
Removed:
   slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerDemo.java
Modified:
   slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/Profiler.java
   slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/StopWatch.java
   slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/TimeInstrument.java
   slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/SortAndPruneComposites.java
   slf4j/trunk/slf4j-site/src/site/pages/extensions.html
   slf4j/trunk/slf4j-site/src/site/pages/index.html

Log:
- improved Profiler docs and other minor changes

Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/Profiler.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/Profiler.java	(original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/Profiler.java	Mon Jul 28 22:57:41 2008
@@ -30,7 +30,6 @@
 import org.slf4j.Marker;
 import org.slf4j.MarkerFactory;
 
-
 // +  Profiler [BAS]
 // |-- elapsed time            [doX]     0 milliseconds.
 // |-- elapsed time        [doYYYYY]    56 milliseconds.
@@ -192,6 +191,9 @@
   
   public void log() {
     Marker profilerMarker = MarkerFactory.getMarker(PROFILER_MARKER_NAME);
+    if(logger == null) {
+      throw new NullPointerException("If you invoke the log() method, then you must associate a logger with this profiler.");
+    }
     if (logger.isDebugEnabled(profilerMarker)) {
       DurationUnit du = Util.selectDurationUnitForDisplay(globalStopWatch);
       String r = buildProfilerString(du, TOP_PROFILER_FIRST_PREFIX, TOTAL_ELAPSED, "");
@@ -238,20 +240,4 @@
     buf.append(SpacePadder.LINE_SEP);
   }
 
-  static void XXXbuildStringForGlobalStopWatch(StringBuffer buf,
-      String indentation, StopWatch sw, DurationUnit du) {
-    buf.append(indentation);
-    buf.append("|--");
-    //buf.append(prefix);
-    //buf.append(" Total elapsed time ");
-    SpacePadder.leftPad(buf, "[" + sw.getName() + "]", MIN_SW_NAME_LENGTH);
-    buf.append(" ");
-    String timeStr = Util.durationInDunrationUnitsAsStr(sw.elapsedTime(),
-        du);
-    SpacePadder.leftPad(buf, timeStr, MIN_SW_ELAPSED_TIME_NUMBER_LENGTH);
-    buf.append(" ");
-    Util.appendDurationUnitAsStr(buf, du);
-    buf.append(SpacePadder.LINE_SEP);
-  }
-
 }

Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/StopWatch.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/StopWatch.java	(original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/StopWatch.java	Mon Jul 28 22:57:41 2008
@@ -96,4 +96,8 @@
    System.out.println(toString());
   }
   
+  public void log() {
+    throw new UnsupportedOperationException("A stopwatch instance does not know how to log");
+  }
+  
 }

Modified: slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/TimeInstrument.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/TimeInstrument.java	(original)
+++ slf4j/trunk/slf4j-ext/src/main/java/org/slf4j/profiler/TimeInstrument.java	Mon Jul 28 22:57:41 2008
@@ -21,4 +21,6 @@
   long elapsedTime();
   
   void print();
+  
+  void log();
 }

Added: slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/BasicProfilerDemo.java
==============================================================================
--- (empty file)
+++ slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/BasicProfilerDemo.java	Mon Jul 28 22:57:41 2008
@@ -0,0 +1,63 @@
+package org.slf4j.profiler;
+
+/**
+ * 
+ * This demo illustrates usage of SLF4J profilers.
+ * 
+ * <p>
+ * We have been given the task of generating a large number, say N, of random
+ * integers. We need to transform that array into a smaller array containing
+ * only prime numbers. The new array has to be sorted.
+ * 
+ * <p>
+ * While tackling this problem, we would like to measure the time spent in each
+ * subtask.
+ * 
+ * <p>
+ * A typical output for this demo would be:
+ * 
+ * <pre>
+   + Profiler [BASIC]
+   |-- elapsed time                      [A]   213.186 milliseconds.
+   |-- elapsed time                      [B]  2499.107 milliseconds.
+   |-- elapsed time                  [OTHER]  3300.752 milliseconds.
+   |-- Total                         [BASIC]  6014.161 milliseconds.
+  </pre>
+ * 
+ * @author Ceki Gulcu
+ */
+public class BasicProfilerDemo {
+
+  public static void main(String[] args) {
+    // create a profiler called "BASIC"
+    Profiler profiler = new Profiler("BASIC");
+    profiler.start("A");
+    doA();
+
+    profiler.start("B");
+    doB();
+
+    profiler.start("OTHER");
+    doOther();
+    profiler.stop().print();
+  }
+
+  static private void doA() {
+    delay(200);
+  }
+
+  static private void doB() {
+    delay(2500);
+  }
+
+  static private void doOther() {
+    delay(3300);
+  }
+
+  static private void delay(int millis) {
+    try {
+      Thread.sleep(millis);
+    } catch (InterruptedException e) {
+    }
+  }
+}

Copied: slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/NestedProfilerDemo.java (from r1075, /slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerDemo.java)
==============================================================================
--- /slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerDemo.java	(original)
+++ slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/NestedProfilerDemo.java	Mon Jul 28 22:57:41 2008
@@ -30,21 +30,33 @@
  * 
  * @author Ceki Gulcu
  */
-public class ProfilerDemo {
+public class NestedProfilerDemo {
   
   public static void main(String[] args) {
+    // create a profiler called "DEMO"
     Profiler profiler = new Profiler("DEMO");
+    
+    // register this profiler in the thread context's profiler registry
     ProfilerRegistry profilerRegistry = ProfilerRegistry.getThreadContextInstance();
     profiler.registerWith(profilerRegistry);
     
+    // start a stopwatch called "RANDOM"
     profiler.start("RANDOM");
-    RandomIntegerArrayGenerator riag = new RandomIntegerArrayGenerator();
-    int n = 100*1000;
-    int[] randomArray = riag.generate(n);
+    RandomIntegerArrayGenerator riaGenerator = new RandomIntegerArrayGenerator();
+    int n = 10*1000;
+    int[] randomArray = riaGenerator.generate(n);
     
+    // create and start a nested profiler called "SORT_AND_PRUNE"
+    // By virtue of its parent-child relationship with the "DEMO"
+    // profiler, and the previous registration of the parent profiler, 
+    // this nested profiler will be automatically registered
+    // with the thread context's profiler registry
     profiler.startNested(SortAndPruneComposites.NESTED_PROFILER_NAME);
+    
     SortAndPruneComposites pruner = new SortAndPruneComposites(randomArray);
     pruner.sortAndPruneComposites();
+    
+    // stop and print the "DEMO" printer
     profiler.stop().print();
   }
 }

Added: slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/NestedProfilerDemo2.java
==============================================================================
--- (empty file)
+++ slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/NestedProfilerDemo2.java	Mon Jul 28 22:57:41 2008
@@ -0,0 +1,42 @@
+package org.slf4j.profiler;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+
+/**
+ * 
+ * This demo illustrates usage of SLF4J profilers. It is almost identical to
+ * the first NestProfilerDemo, except that it uses a logger instead of
+ * printing its output on the console.
+ * 
+
+ * @author Ceki Gulcu
+ */
+public class NestedProfilerDemo2 {
+
+  static Logger logger = LoggerFactory.getLogger(NestedProfilerDemo2.class);
+  
+  public static void main(String[] args) {
+    Profiler profiler = new Profiler("DEMO");
+    // associate a logger with the profiler
+    profiler.setLogger(logger);
+    
+    ProfilerRegistry profilerRegistry = ProfilerRegistry.getThreadContextInstance();
+    profiler.registerWith(profilerRegistry);
+    
+    profiler.start("RANDOM");
+    RandomIntegerArrayGenerator riaGenerator = new RandomIntegerArrayGenerator();
+    int n = 10*1000;
+    int[] randomArray = riaGenerator.generate(n);
+    
+    profiler.startNested(SortAndPruneComposites.NESTED_PROFILER_NAME);
+    
+    SortAndPruneComposites pruner = new SortAndPruneComposites(randomArray);
+    pruner.sortAndPruneComposites();
+    
+    // stop and log
+    profiler.stop().log();
+  }
+}

Modified: slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/SortAndPruneComposites.java
==============================================================================
--- slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/SortAndPruneComposites.java	(original)
+++ slf4j/trunk/slf4j-ext/src/test/java/org/slf4j/profiler/SortAndPruneComposites.java	Mon Jul 28 22:57:41 2008
@@ -17,11 +17,14 @@
   }
   
   public int[] sortAndPruneComposites() {
-    
+    // retrieve previously registered profiler named "SORT_AND_PRUNE"
     ProfilerRegistry profilerRegistry = ProfilerRegistry.getThreadContextInstance();
     Profiler sortProfiler = profilerRegistry.get(NESTED_PROFILER_NAME);
+
+    // start a new stopwatch called SORT
     sortProfiler.start("SORT");
     int[] sortedArray = sort();
+    // start a new stopwatch called PRUNE_COMPOSITES
     sortProfiler.start("PRUNE_COMPOSITES");
     int result[] = pruneComposites(sortedArray);
     

Added: slf4j/trunk/slf4j-ext/src/test/resources/log4j.properties
==============================================================================
--- (empty file)
+++ slf4j/trunk/slf4j-ext/src/test/resources/log4j.properties	Mon Jul 28 22:57:41 2008
@@ -0,0 +1,6 @@
+
+log4j.rootLogger=DEBUG, CONSOLE
+
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

Modified: slf4j/trunk/slf4j-site/src/site/pages/extensions.html
==============================================================================
--- slf4j/trunk/slf4j-site/src/site/pages/extensions.html	(original)
+++ slf4j/trunk/slf4j-site/src/site/pages/extensions.html	Mon Jul 28 22:57:41 2008
@@ -48,45 +48,43 @@
     <h2>Basic example</h2>
 
 
-    <em>Example: Using the profiler </em>
+    <em>Example: Using the profiler: <a
+    href="xref-test/org/slf4j/profiler/BasicProfilerDemo.html">BasicProfilerDemo</a></em>
 
-    <p class="source">
+    <p class="source">[omitted]
+32  public class BasicProfilerDemo {
+33  
+34    public static void main(String[] args) {
+35      // create a profiler called "BASIC"
+36      <b>Profiler profiler = new Profiler("BASIC");</b>
+37      <b>profiler.start("A");</b>
+38      doA();
+39  
+40      <b>profiler.start("B");</b>
+41      doB();
+42      
+43      <b>profiler.start("OTHER");</b>
+44      doOther();
+45      <b>profiler.stop().print();</b>
+46    }
+[omitted]</p>
 
-import ch.qos.logback.classic.stopwatch.Profiler;
-
-public class BasicUsageExample {
-
-  public static void main(String[] args) {
-    <b>Profiler profiler = new Profiler("BASIC");</b>
-    <b>profiler.start("A");</b>
-    doA();
-       
-    <b>profiler.start("B");</b>
-    for (int i = 0; i &lt; 5; i++) {
-      doSubtaskTwo(i);
-    }
-    <b>profiler.start("doOther");</b>
-    doOther();
-    System.out.println(<b>profiler.stop().toString()</b>);
-  }
-  ... cut </p>
 
   <p>Running the above example will output the following output.</p>
 
     <p class="source">+ Profiler [BASIC]
-|-- elapsed time                [A]  0.288 milliseconds.
-|-- elapsed time                [B] 24.717 milliseconds.
-|-- elapsed time            [Other] 22.085 milliseconds.
-|-- Total elapsed time      [BASIC] 50.691 milliseconds.</p>
-
+|-- elapsed time                      [A]   220.487 milliseconds.
+|-- elapsed time                      [B]  2499.866 milliseconds.
+|-- elapsed time                  [OTHER]  3300.745 milliseconds.
+|-- Total                         [BASIC]  6022.568 milliseconds.</p>
   
    <p>Instantiating a profiler starts a global stopwatch. Each call to
    the start() method starts a new and named stopwatch. In addition to
-   sarting a named stopwatch, the start() method also causes the
+   starting a named stopwatch, the start() method also causes the
    previous stopwatch to stop. Thus, the call to
    <code>profiler.start("A")</code> starts a stopwatch named "A". The
    subsequent call to <code>profiler.start("B")</code> starts
-   stopwatch "B" and simultanously stops the stopwatch named
+   stopwatch "B" and simultaneously stops the stopwatch named
    "A". Invoking the <code>stop()</code> on a profiler method stops
    the last stopwatch as well as the global stopwatch which was
    started when the profiler was instantiated.
@@ -106,12 +104,191 @@
    
    <p>Often times, the subtask is implemented by a different class as
    the class hosting the parent profiler. Using the
-   <code>ProfilerRegistry</code> is a convinient way of passing a
-   nested profiler to an object outside the current object.
+   <code>ProfilerRegistry</code> is a convenient way of passing a
+   nested profiler to an object outside the current object. Each
+   thread has its own profiler registry which can be retrieved by
+   invoking the <code>getThreadContextInstance()</code> method.
    </p>
 
    <em>Example: <a
-   href="xref-test/org/slf4j/profiler/ProfilerDemo.html">ProfilerDemo</a>
+   href="xref-test/org/slf4j/profiler/NestedProfilerDemo.html">NestedProfilerDemo</a>
+   </em>
+
+   <p class="source">33  public class NestedProfilerDemo {
+34    
+35    public static void main(String[] args) {
+36      // create a profiler called "DEMO"
+37      Profiler profiler = new Profiler("DEMO");
+38      
+39      // register this profiler in the thread context's profiler registry
+40      <b>ProfilerRegistry profilerRegistry = ProfilerRegistry.getThreadContextInstance();</b>
+41      <b>profiler.registerWith(profilerRegistry);</b>
+42      
+43      // start a stopwatch called "RANDOM"
+44      profiler.start("RANDOM");
+45      RandomIntegerArrayGenerator riaGenerator = new RandomIntegerArrayGenerator();
+46      int n = 1000*1000;
+47      int[] randomArray = riaGenerator.generate(n);
+48      
+49      // create and start a nested profiler called "SORT_AND_PRUNE"
+50      // By virtue of its parent-child relationship with the "DEMO"
+51      // profiler, and the previous registration of the parent profiler, 
+52      // this nested profiler will be automatically registered
+53      // with the thread context's profiler registry
+54      <b>profiler.startNested(SortAndPruneComposites.NESTED_PROFILER_NAME);</b>
+55      
+56      SortAndPruneComposites pruner = new SortAndPruneComposites(randomArray);
+57      pruner.sortAndPruneComposites();
+58      
+59      // stop and print the "DEMO" printer
+60      profiler.stop().print();
+61    }
+62  }</p>
+
+   <p>Here is the relevant excerpt from the <a
+   href="xref-test/org/slf4j/profiler/SortAndPruneComposites.html">SortAndPruneComposites</a>
+   class.
+   </p>
+
+   <p class="source">[omitted]
+6   public class SortAndPruneComposites {
+7   
+8     static String NESTED_PROFILER_NAME = "SORT_AND_PRUNE";
+9     
+10    final int[] originalArray;
+11    final int originalArrrayLength;
+12    
+13    public SortAndPruneComposites(int[] randomArray) {
+14      this.originalArray = randomArray;
+15      this.originalArrrayLength = randomArray.length;
+16     
+17    }
+18    
+19    public int[] sortAndPruneComposites() {
+20      // retrieve previously registered profiler named "SORT_AND_PRUNE"
+21      ProfilerRegistry profilerRegistry = ProfilerRegistry.getThreadContextInstance();
+22      <b>Profiler sortProfiler = profilerRegistry.get(NESTED_PROFILER_NAME);</b>
+23  
+24      // start a new stopwatch called SORT
+25      sortProfiler.start("SORT");
+26      int[] sortedArray = sort();
+27      // start a new stopwatch called PRUNE_COMPOSITES
+28      sortProfiler.start("PRUNE_COMPOSITES");
+29      int result[] = pruneComposites(sortedArray);
+30      
+31      return result;
+32    }
+[omitted] </p>
+   
+
+  <p>On a Dual-Core Intel CPU clocked at 3.2 GHz, running the
+  <code>ProfilerDemo</code> application yields the following output:</p>
+  
+  <p class="source">+ Profiler [DEMO]
+|-- elapsed time                 [RANDOM]    70.524 milliseconds.
+|---+ Profiler [SORT_AND_PRUNE]
+    |-- elapsed time                   [SORT]   665.281 milliseconds.
+    |-- elapsed time       [PRUNE_COMPOSITES]  5695.515 milliseconds.
+    |-- Subtotal             [SORT_AND_PRUNE]  6360.866 milliseconds.
+|-- elapsed time         [SORT_AND_PRUNE]  6360.866 milliseconds.
+|-- Total                          [DEMO]  6433.922 milliseconds.</p>
+
+  <p>From the above, we learn that generating 1'000'000 random
+  integers takes 70 ms, sorting them 665 ms, and pruning the composite
+  (non-prime) integers 5695 ms, for a grand total of 6433 ms. Given
+  that pruning composites takes most of the CPU effort, any future
+  optimizations efforts would be directed at the pruning part.
+  </p>
+
+  <p>With just a few well-placed profiler calls we were able to
+  identify hot-spots in our application. Also note that passing a
+  profiler to a target class could be achieved by registering it in a
+  profiler registry and then retrieving it in the target class.
+  </p>
+
+  <h2>Printing using a logger</h2>
+
+  <p> Invoking <code>profiler.print</code> will always print the
+  output on the console. If you wish to leave the profiler code in
+  production, then you probably need more control over the output
+  destination.
+  </p>
+  
+  <p>To use a logger, you need to associate a logger of your choice
+  with the profiler and then invoke the <code>log()</code> method
+  instead of <code>print()</code>, as the next example illustrates.
+  </p>
+
+  <em>Profiler with a logger: <a
+  href="xref-test/org/slf4j/profiler/NestedProfilerDemo2.html">NestedProfilerDemo2</a>
+   </em>
+
+   <p class="source">[omitted]
+17  public class NestedProfilerDemo2 {
+18  
+19    static Logger logger = LoggerFactory.getLogger(NestedProfilerDemo2.class);
+20    
+21    public static void main(String[] args) {
+22      Profiler profiler = new Profiler("DEMO");
+23      // associate a logger with the profiler
+24      <b>profiler.setLogger(logger);</b>
+25      
+26      ProfilerRegistry profilerRegistry = ProfilerRegistry.getThreadContextInstance();
+27      profiler.registerWith(profilerRegistry);
+28      
+29      profiler.start("RANDOM");
+30      RandomIntegerArrayGenerator riaGenerator = new RandomIntegerArrayGenerator();
+31      int n = 10*1000;
+32      int[] randomArray = riaGenerator.generate(n);
+33      
+34      profiler.startNested(SortAndPruneComposites.NESTED_PROFILER_NAME);
+35      
+36      SortAndPruneComposites pruner = new SortAndPruneComposites(randomArray);
+37      pruner.sortAndPruneComposites();
+38      
+39      // stop and log
+40      profiler.stop().<b>log()</b>;
+41    }
+42  } </p>
+  
+  <p>The output generated by this example will depend on the logging
+  environment, but should be very similar to the output generated by
+  the previous <code>NestedProfilerDemo</code> example.
+  </p>
+
+  <p>The log() method logs at level DEBUG using a marker named
+  "PROFILER".</p>
+
+  <p>If your logging system supports markers, e.g. logback, you could
+  specifically enable or disable output generated by SLF4J
+  profilers. Here is logback configuration file disabling output for
+  any logging event bearing the "PROFILER" marker, even if the logger
+  used by the profiler is enabled for the debug level.
+  </p>
+
+
+  <em>logback configuration disabling logging from profilers, and only
+  profilers</em>
+
+  <p class="source">&lt;configuration>
+
+  <b>&lt;turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
+    &lt;Marker>PROFILER&lt;/Marker>
+    &lt;OnMatch>DENY&lt;/OnMatch>
+  &lt;/turboFilter></b>
+    
+  &lt;appender name="STDOUT"
+    class="ch.qos.logback.core.ConsoleAppender">
+    &lt;layout class="ch.qos.logback.classic.PatternLayout">
+      &lt;Pattern>%-5level %logger{36} - %msg%n&lt;/Pattern>
+    &lt;/layout>
+  &lt;/appender>
+
+  &lt;root>
+    &lt;level value="DEBUG" />
+    &lt;appender-ref ref="STDOUT" />
+  &lt;/root>
+&lt;/configuration>  </p>
 
 </div>
 </body>

Modified: slf4j/trunk/slf4j-site/src/site/pages/index.html
==============================================================================
--- slf4j/trunk/slf4j-site/src/site/pages/index.html	(original)
+++ slf4j/trunk/slf4j-site/src/site/pages/index.html	Mon Jul 28 22:57:41 2008
@@ -108,6 +108,7 @@
           <li><a href="http://displaytag.sourceforge.net/11/">Display tag</a></li>
           <li><a href="http://groovy.codehaus.org/GMaven">GMaven</a></li>
           <li><a href="http://www.h2database.com/">H2 Database</a></li>
+          <li><a href="http://www.gradle.org/">Gradle</a></li>
           <li><a href="http://www.icegreen.com/greenmail/">GreenMail</a></li>
           <li><a href="http://ha-jdbc.sourceforge.net/">HA-JDBC</a></li>         
           <li><a href="http://www.hibernate.org/">Hibernate</a></li>         

Added: slf4j/trunk/slf4j-site/src/site/pages/support.html
==============================================================================
--- (empty file)
+++ slf4j/trunk/slf4j-site/src/site/pages/support.html	Mon Jul 28 22:57:41 2008
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+<title>Log4j Bridge</title>
+<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
+<link rel="stylesheet" type="text/css" media="print" href="css/print.css" />
+
+</head>
+<body>
+	<script>
+prefix='';	
+</script>
+
+<script src="templates/header.js"></script>
+<div id="left">
+  <script src="templates/left.js"></script>
+</div>
+<div id="right">
+  <script src="templates/right.js"></script>
+</div>
+<div id="content">
+	
+    <h2>Contractual Support</h2>
+    
+
+    <p>The following companies, listed in alphabetical order, offer
+    contractual support for SLF4J.
+    </p>
+
+    <ul>
+      <li>QOS.ch, in Lausanne, Swizerland. For more information visit
+      QOS.ch's <a href="">support page</a>. </li>
+    </ul>
+
+
+	
+<script src="templates/footer.js"></script>
+</div>
+</body>
+</html>
+
+



More information about the slf4j-dev mailing list