You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by Andrew Vajoczki <va...@yahoo.com> on 2002/01/18 04:42:17 UTC

[PATCH] improved logging performance for some Log4J date formats

This patch significantly improves the logging performance 
of the AbsoluteTimeDateFormat class (a.k.a. "%d{ABSOLUTE}"), 
and indirectly ISO8601DateFormat ("%d{ISO8601}") 
and DateTimeDateFormat (%d{"DATE"}).

The "HH:mm:ss," time string (less the "SSS" milliseconds portion) 
is cached and reused as long as the second does not change.
Since many thousands of events can be logged each
second, considerable CPU time can be saved by not recalculating 
the "HH:mm:ss," portion of the time string each time.
In tests using JDK 1.3/Windows I've seen an overall log4j 
logging speed improvement of 10% to 50% depending on the date 
format used. Other Log4J date formatting classes could be
changed to employ the same optimization.  I'll leave it to someone
else, since I don't use the other date formats.

The method DecimalFormatSymbols.getDecimalSeparator()
was also used instead of the previously hard coded ","
character for the decimal point symbol in your machine's locale 
("." in my case).

This diff was made against 
jakarta-log4j-1.2alpha6/src/java/org/apache/log4j/helpers/AbsoluteTimeDateFormat.java

-Andrew Vajoczki

--- AbsoluteTimeDateFormat.java.orig	Thu Jan 17 18:16:48 2002
+++ AbsoluteTimeDateFormat.java	Thu Jan 17 21:20:14 2002
@@ -56,7 +56,11 @@
   AbsoluteTimeDateFormat(TimeZone timeZone) {
     setCalendar(Calendar.getInstance(timeZone));
   }
-  
+
+  private static Object previousTimeLock = new Object();
+  private static long   previousTime;
+  private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ss."
+
   /**
      Appends to <code>sbuf</code> the time in the format
      "HH:mm:ss,SSS" for example, "15:49:37,459"
@@ -69,32 +73,52 @@
   StringBuffer format(Date date, StringBuffer sbuf,
 		      FieldPosition fieldPosition) {
 
-    // We use a previously instantiated Date object to avoid the needless
-    // creation of temporary objects. This saves a few micro-secs.
-    calendar.setTime(date); 
-    
-    int hour = calendar.get(Calendar.HOUR_OF_DAY);
-    if(hour < 10) {
-      sbuf.append('0');
-    }
-    sbuf.append(hour);
-    sbuf.append(':');
-
-    int mins = calendar.get(Calendar.MINUTE);
-    if(mins < 10) {
-      sbuf.append('0');
-    }
-    sbuf.append(mins);
-    sbuf.append(':');
-    
-    int secs = calendar.get(Calendar.SECOND);
-    if(secs < 10) {
-      sbuf.append('0');
-    }
-    sbuf.append(secs);
-    sbuf.append(',');
+    long now = date.getTime();
+    int millis = (int)(now % 1000);
+ 
+    synchronized (previousTimeLock) {
+      if ((now - millis) != previousTime) {
+        // We reach this point at most once per second
+        // across all threads instead of each time format()
+        // is called. This saves considerable CPU time.
+         
+        calendar.setTime(date); 
+        
+        int start = sbuf.length();
+                
+        int hour = calendar.get(Calendar.HOUR_OF_DAY);
+        if(hour < 10) {
+          sbuf.append('0');
+        }
+        sbuf.append(hour);
+        sbuf.append(':');
+        
+        int mins = calendar.get(Calendar.MINUTE);
+        if(mins < 10) {
+          sbuf.append('0');
+        }
+        sbuf.append(mins);
+        sbuf.append(':');
+         
+        int secs = calendar.get(Calendar.SECOND);
+        if(secs < 10) {
+          sbuf.append('0');
+        }
+        sbuf.append(secs);
+        
+        // use current locale's decimal separator
+        sbuf.append(new java.text.DecimalFormatSymbols().getDecimalSeparator());
+        
+        // store the time string for next time to avoid recomputation
+        sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
+        
+        previousTime = now - millis;
+      }
+      else {
+        sbuf.append(previousTimeWithoutMillis);
+      } 
+    } 
 
-    int millis = calendar.get(Calendar.MILLISECOND);
     if(millis < 100) 
       sbuf.append('0');
     if(millis < 10)

[PATCH] ISO8601DateFormat/%d{ISO8601} speed optimization

Posted by Andrew Vajoczki <va...@yahoo.com>.
Overall Log4J logging speed with typical ISO date format strings
(like "%p %t %d{ISO8601} %c %m%n") is roughly 50% faster 
with this date string caching optimization (at least on
my JDK 1.3/Windows machine).

This puts typical logging using %d{ISO8601} closer to 
as %r (relative) timings.

Although I've tested it and it seems fine, more testing never hurts.

diff -u made against
jakarta-log4j-1.2alpha6/src/java/org/apache/log4j/helpers/ISO8601DateFormat.java

-Andrew Vajoczki

--- ISO8601DateFormat.java.orig	Thu Jan 17 19:52:28 2002
+++ ISO8601DateFormat.java	Fri Jan 18 12:20:26 2002
@@ -41,6 +41,10 @@
   ISO8601DateFormat(TimeZone timeZone) {
     super(timeZone);
   }
+
+  static private Object lastTimeLock = new Object();;
+  static private long   lastTime;
+  static private char[] lastTimeString = new char[20];
   
   /**
      Appends a date in the format "YYYY-mm-dd HH:mm:ss,SSS"
@@ -52,37 +56,87 @@
   StringBuffer format(Date date, StringBuffer sbuf,
 		      FieldPosition fieldPosition) {
 
-    calendar.setTime(date);      
-
-    int year =  calendar.get(Calendar.YEAR);
-    sbuf.append(year);
+    long now = date.getTime();
+    int millis = (int)(now % 1000);
 
-    String month;
-    switch(calendar.get(Calendar.MONTH)) {
-    case Calendar.JANUARY: month = "-01-"; break;      
-    case Calendar.FEBRUARY: month = "-02-";  break;     
-    case Calendar.MARCH: month = "-03-"; break;      
-    case Calendar.APRIL: month = "-04-";  break;     
-    case Calendar.MAY: month = "-05-"; break;      
-    case Calendar.JUNE: month = "-06-";  break;     
-    case Calendar.JULY: month = "-07-"; break;      
-    case Calendar.AUGUST: month = "-08-";  break;     
-    case Calendar.SEPTEMBER: month = "-09-"; break;      
-    case Calendar.OCTOBER: month = "-10-"; break;      
-    case Calendar.NOVEMBER: month = "-11-";  break;           
-    case Calendar.DECEMBER: month = "-12-";  break;
-    default: month = "-NA-"; break;
+    synchronized (lastTimeLock) {
+      if ((now - millis) != lastTime) {
+        // We reach this point at most once per second
+        // across all threads instead of each time format()
+        // is called. This saves considerable CPU time.
+        
+        calendar.setTime(date);      
+          
+        int start = sbuf.length();
+         
+        int year =  calendar.get(Calendar.YEAR);
+        sbuf.append(year);
+         
+        String month;
+        switch(calendar.get(Calendar.MONTH)) {
+        case Calendar.JANUARY: month = "-01-"; break;      
+        case Calendar.FEBRUARY: month = "-02-";  break;     
+        case Calendar.MARCH: month = "-03-"; break;      
+        case Calendar.APRIL: month = "-04-";  break;     
+        case Calendar.MAY: month = "-05-"; break;      
+        case Calendar.JUNE: month = "-06-";  break;     
+        case Calendar.JULY: month = "-07-"; break;      
+        case Calendar.AUGUST: month = "-08-";  break;     
+        case Calendar.SEPTEMBER: month = "-09-"; break;      
+        case Calendar.OCTOBER: month = "-10-"; break;      
+        case Calendar.NOVEMBER: month = "-11-";  break;           
+        case Calendar.DECEMBER: month = "-12-";  break;
+        default: month = "-NA-"; break;
+        }
+        sbuf.append(month);
+         
+        int day = calendar.get(Calendar.DAY_OF_MONTH);
+        if(day < 10) 
+          sbuf.append('0');
+        sbuf.append(day);
+         
+        sbuf.append(' ');    
+
+        int hour = calendar.get(Calendar.HOUR_OF_DAY);
+        if(hour < 10) {
+          sbuf.append('0');
+        }
+        sbuf.append(hour);
+        sbuf.append(':');
+
+        int mins = calendar.get(Calendar.MINUTE);
+        if(mins < 10) {
+          sbuf.append('0');
+        }
+        sbuf.append(mins);
+        sbuf.append(':');
+
+        int secs = calendar.get(Calendar.SECOND);
+        if(secs < 10) {
+          sbuf.append('0');
+        }
+        sbuf.append(secs);
+
+        // use current locale's decimal separator
+        sbuf.append(new java.text.DecimalFormatSymbols().getDecimalSeparator());
+        
+        // store the time string for next time to avoid recomputation
+        sbuf.getChars(start, sbuf.length(), lastTimeString, 0);
+        lastTime = now - millis;
+      } 
+      else {
+        sbuf.append(lastTimeString);
+      } 
     }
-    sbuf.append(month);
-
-    int day = calendar.get(Calendar.DAY_OF_MONTH);
-    if(day < 10) 
-      sbuf.append('0');
-    sbuf.append(day);
-
-    sbuf.append(' ');    
-    return super.format(date, sbuf, fieldPosition);
-  }
+    
+    if (millis < 100)
+      sbuf.append('0'); 
+    if (millis < 10)
+      sbuf.append('0'); 
+    
+    sbuf.append(millis);
+    return sbuf;
+  } 
 
   /**
     This method does not do anything but return <code>null</code>.
@@ -92,3 +146,4 @@
     return null;
   }  
 }
+

Re: [PATCH] improved logging performance for some Log4J date formats

Posted by Ceki Gülcü <ce...@qos.ch>.
Andrew,

Your patches have been incorporated. As mentioned previously
synchronization is not necessary so I removed it. In addition, the
separator for milliseconds remains the ',' character as specified by
the ISO8601 standard.

Thanks again for a useful patch. Ceki


At 22:42 17.01.2002 -0500, you wrote:
>This patch significantly improves the logging performance
>of the AbsoluteTimeDateFormat class (a.k.a. "%d{ABSOLUTE}"),
>and indirectly ISO8601DateFormat ("%d{ISO8601}")
>and DateTimeDateFormat (%d{"DATE"}).
>
>The "HH:mm:ss," time string (less the "SSS" milliseconds portion)
>is cached and reused as long as the second does not change.
>Since many thousands of events can be logged each
>second, considerable CPU time can be saved by not recalculating
>the "HH:mm:ss," portion of the time string each time.
>In tests using JDK 1.3/Windows I've seen an overall log4j
>logging speed improvement of 10% to 50% depending on the date
>format used. Other Log4J date formatting classes could be
>changed to employ the same optimization.  I'll leave it to someone
>else, since I don't use the other date formats.
>
>The method DecimalFormatSymbols.getDecimalSeparator()
>was also used instead of the previously hard coded ","
>character for the decimal point symbol in your machine's locale
>("." in my case).
>
>This diff was made against
>jakarta-log4j-1.2alpha6/src/java/org/apache/log4j/helpers/AbsoluteTimeDateFormat.java
>
>-Andrew Vajoczki
>
>--- AbsoluteTimeDateFormat.java.orig    Thu Jan 17 18:16:48 2002
>+++ AbsoluteTimeDateFormat.java Thu Jan 17 21:20:14 2002
>@@ -56,7 +56,11 @@
>    AbsoluteTimeDateFormat(TimeZone timeZone) {
>      setCalendar(Calendar.getInstance(timeZone));
>    }
>-
>+
>+  private static Object previousTimeLock = new Object();
>+  private static long   previousTime;
>+  private static char[] previousTimeWithoutMillis = new char[9]; // 
>"HH:mm:ss."
>+
>    /**
>       Appends to <code>sbuf</code> the time in the format
>       "HH:mm:ss,SSS" for example, "15:49:37,459"
>@@ -69,32 +73,52 @@
>    StringBuffer format(Date date, StringBuffer sbuf,
>                       FieldPosition fieldPosition) {
>
>-    // We use a previously instantiated Date object to avoid the needless
>-    // creation of temporary objects. This saves a few micro-secs.
>-    calendar.setTime(date);
>-
>-    int hour = calendar.get(Calendar.HOUR_OF_DAY);
>-    if(hour < 10) {
>-      sbuf.append('0');
>-    }
>-    sbuf.append(hour);
>-    sbuf.append(':');
>-
>-    int mins = calendar.get(Calendar.MINUTE);
>-    if(mins < 10) {
>-      sbuf.append('0');
>-    }
>-    sbuf.append(mins);
>-    sbuf.append(':');
>-
>-    int secs = calendar.get(Calendar.SECOND);
>-    if(secs < 10) {
>-      sbuf.append('0');
>-    }
>-    sbuf.append(secs);
>-    sbuf.append(',');
>+    long now = date.getTime();
>+    int millis = (int)(now % 1000);
>+
>+    synchronized (previousTimeLock) {
>+      if ((now - millis) != previousTime) {
>+        // We reach this point at most once per second
>+        // across all threads instead of each time format()
>+        // is called. This saves considerable CPU time.
>+
>+        calendar.setTime(date);
>+
>+        int start = sbuf.length();
>+
>+        int hour = calendar.get(Calendar.HOUR_OF_DAY);
>+        if(hour < 10) {
>+          sbuf.append('0');
>+        }
>+        sbuf.append(hour);
>+        sbuf.append(':');
>+
>+        int mins = calendar.get(Calendar.MINUTE);
>+        if(mins < 10) {
>+          sbuf.append('0');
>+        }
>+        sbuf.append(mins);
>+        sbuf.append(':');
>+
>+        int secs = calendar.get(Calendar.SECOND);
>+        if(secs < 10) {
>+          sbuf.append('0');
>+        }
>+        sbuf.append(secs);
>+
>+        // use current locale's decimal separator
>+        sbuf.append(new 
>java.text.DecimalFormatSymbols().getDecimalSeparator());
>+
>+        // store the time string for next time to avoid recomputation
>+        sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
>+
>+        previousTime = now - millis;
>+      }
>+      else {
>+        sbuf.append(previousTimeWithoutMillis);
>+      }
>+    }
>
>-    int millis = calendar.get(Calendar.MILLISECOND);
>      if(millis < 100)
>        sbuf.append('0');
>      if(millis < 10)


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: [PATCH] improved logging performance for some Log4J dateformats

Posted by Andrew Vajoczki <va...@yahoo.com>.
Hi Ceki,

I am not familiar with Log4J's threading and synchronization 
model, so I thought synchronizing would not hurt.  
But if format() is already guaranteed to be called in a 
synchronous fashion, then by all means remove the mutex check.

I'm hanging up my Log4J optimization hat for now.
Others may want to look at similar optimizations for other 
format classes.

regards,

-Andrew Vajoczki

Ceki Gülcü wrote:
> 
> Hi Andrew,
> 
> Nice! I'll check in the code asap.
> 
> I don't see a need for synchronizing on previousTimeLock because
> layout objects are not shared and can be attached to only one
> appender. The doAppend method  in AppenderSkeleton is synchronized and
> will protect against any threading surprises...
> 
> Does that make sense? Cheers, Ceki

_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


A question on QuiteWriter

Posted by Andrea Fabris <an...@email.it>.
Hi people.
I was taking a deep look on the source code of log4j to understand why i can
delete the logging files and no exception r reported.
I discovered that when log4j was designed, the ppl thought it was a good
idea to no throw exception everytime there was a logging problem
Now, im using log4j in a project but the designer wanted to throw exception
whenever i have a logging problem.
How can i avoid the actual log4j behaviour and let log4j warn about logging
problems?
I have to patch completely the source code?

Thanx in advance
Andrea Fabri




--
Prendi GRATIS l'email universale che... risparmia: http://www.email.it/f

Sponsor:
Le vacanze da sogno si prenotano solo su eDreams.
Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=75&d=21-1  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: build.xml missing from alpha log4j releases?

Posted by Ceki Gülcü <ce...@qos.ch>.
Andrew,

Thanks. This omission will be corrected in alpha7.

-- 
Ceki

At 19:34 18.01.2002 -0500, you wrote:
>Sorry, I guess I didn't make myself clear...
>
>I did not find a file named 'build.xml' anywhere in 
>the tar file.
>
>$ gzip -dc jakarta-log4j-1_2alpha6.tar.gz | tar t | grep 'uild.xml'
>jakarta-log4j-1.2alpha6/build/siteBuild.xml
>
>Perhaps build.xml is not necessary to build Log4J
>and that's why it was not in the tarfile?


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: build.xml missing from alpha log4j releases?

Posted by Andrew Vajoczki <va...@yahoo.com>.
Sorry, I guess I didn't make myself clear...

I did not find a file named 'build.xml' anywhere in 
the tar file.

$ gzip -dc jakarta-log4j-1_2alpha6.tar.gz | tar t | grep 'uild.xml'
jakarta-log4j-1.2alpha6/build/siteBuild.xml

Perhaps build.xml is not necessary to build Log4J
and that's why it was not in the tarfile?

Ceki Gülcü wrote:
> 
> The build.xml file is now in the topmost directory of the
> distribution.
> 
> Just invoking ant should suffice to build. The build.sh and
> build.bat are no longer used. This similar to what many
> other Jakarta projects...
> 
> I can't tell you whether this is good or bad. Just following
> the crowd. Regards, Ceki
> 
> At 14:17 18.01.2002 -0500, you wrote:
> >Hello,
> >
> >I thought I should mention that when I downloaded the
> >log4j alpha6 snapshot it was missing the build.xml file:
> >
> > http://jakarta.apache.org/log4j/jakarta-log4j-1.2alpha6.tar.gz
> >
> >I had to grab it from WebCVS in order to build the jar.
> >Is this by design or did I not run the install script
> >with the correct parameters?
> >I used "./build.sh jar" after setting my JAVA_HOME env variable
> >under Cygwin.
> >
> >-Andrew
> >
> >_________________________________________________________
> >Do You Yahoo!?
> >Get your free @yahoo.com address at http://mail.yahoo.com
> >
> >
> >--
> >To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> >For additional commands, e-mail: <ma...@jakarta.apache.org>
> 
> --
> Ceki Gülcü - http://qos.ch
> 
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>

_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: build.xml missing from alpha log4j releases?

Posted by Ceki Gülcü <ce...@qos.ch>.
The build.xml file is now in the topmost directory of the 
distribution. 

Just invoking ant should suffice to build. The build.sh and
build.bat are no longer used. This similar to what many
other Jakarta projects...

I can't tell you whether this is good or bad. Just following
the crowd. Regards, Ceki

At 14:17 18.01.2002 -0500, you wrote:
>Hello,
>
>I thought I should mention that when I downloaded the
>log4j alpha6 snapshot it was missing the build.xml file:
>
> http://jakarta.apache.org/log4j/jakarta-log4j-1.2alpha6.tar.gz
>
>I had to grab it from WebCVS in order to build the jar.
>Is this by design or did I not run the install script 
>with the correct parameters?
>I used "./build.sh jar" after setting my JAVA_HOME env variable
>under Cygwin.
>
>-Andrew
>
>_________________________________________________________
>Do You Yahoo!?
>Get your free @yahoo.com address at http://mail.yahoo.com
>
>
>--
>To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>For additional commands, e-mail: <ma...@jakarta.apache.org>

--
Ceki Gülcü - http://qos.ch



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


build.xml missing from alpha log4j releases?

Posted by Andrew Vajoczki <va...@yahoo.com>.
Hello,

I thought I should mention that when I downloaded the
log4j alpha6 snapshot it was missing the build.xml file:

 http://jakarta.apache.org/log4j/jakarta-log4j-1.2alpha6.tar.gz

I had to grab it from WebCVS in order to build the jar.
Is this by design or did I not run the install script 
with the correct parameters?
I used "./build.sh jar" after setting my JAVA_HOME env variable
under Cygwin.

-Andrew

_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: [PATCH] improved logging performance for some Log4J date formats

Posted by Ceki Gülcü <ce...@qos.ch>.
Hi Andrew,

Nice! I'll check in the code asap.

I don't see a need for synchronizing on previousTimeLock because 
layout objects are not shared and can be attached to only one
appender. The doAppend method  in AppenderSkeleton is synchronized and
will protect against any threading surprises...

Does that make sense? Cheers, Ceki

At 22:42 17.01.2002 -0500, you wrote:
>This patch significantly improves the logging performance 
>of the AbsoluteTimeDateFormat class (a.k.a. "%d{ABSOLUTE}"), 
>and indirectly ISO8601DateFormat ("%d{ISO8601}") 
>and DateTimeDateFormat (%d{"DATE"}).
>
>The "HH:mm:ss," time string (less the "SSS" milliseconds portion) 
>is cached and reused as long as the second does not change.
>Since many thousands of events can be logged each
>second, considerable CPU time can be saved by not recalculating 
>the "HH:mm:ss," portion of the time string each time.
>In tests using JDK 1.3/Windows I've seen an overall log4j 
>logging speed improvement of 10% to 50% depending on the date 
>format used. Other Log4J date formatting classes could be
>changed to employ the same optimization.  I'll leave it to someone
>else, since I don't use the other date formats.
>
>The method DecimalFormatSymbols.getDecimalSeparator()
>was also used instead of the previously hard coded ","
>character for the decimal point symbol in your machine's locale 
>("." in my case).
>
>This diff was made against 
>jakarta-log4j-1.2alpha6/src/java/org/apache/log4j/helpers/AbsoluteTimeDateFormat.java
>
>-Andrew Vajoczki
>
>--- AbsoluteTimeDateFormat.java.orig    Thu Jan 17 18:16:48 2002
>+++ AbsoluteTimeDateFormat.java Thu Jan 17 21:20:14 2002
>@@ -56,7 +56,11 @@
>   AbsoluteTimeDateFormat(TimeZone timeZone) {
>     setCalendar(Calendar.getInstance(timeZone));
>   }
>-  
>+
>+  private static Object previousTimeLock = new Object();
>+  private static long   previousTime;
>+  private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ss."
>+
>   /**
>      Appends to <code>sbuf</code> the time in the format
>      "HH:mm:ss,SSS" for example, "15:49:37,459"
>@@ -69,32 +73,52 @@
>   StringBuffer format(Date date, StringBuffer sbuf,
>                      FieldPosition fieldPosition) {
> 
>-    // We use a previously instantiated Date object to avoid the needless
>-    // creation of temporary objects. This saves a few micro-secs.
>-    calendar.setTime(date); 
>-    
>-    int hour = calendar.get(Calendar.HOUR_OF_DAY);
>-    if(hour < 10) {
>-      sbuf.append('0');
>-    }
>-    sbuf.append(hour);
>-    sbuf.append(':');
>-
>-    int mins = calendar.get(Calendar.MINUTE);
>-    if(mins < 10) {
>-      sbuf.append('0');
>-    }
>-    sbuf.append(mins);
>-    sbuf.append(':');
>-    
>-    int secs = calendar.get(Calendar.SECOND);
>-    if(secs < 10) {
>-      sbuf.append('0');
>-    }
>-    sbuf.append(secs);
>-    sbuf.append(',');
>+    long now = date.getTime();
>+    int millis = (int)(now % 1000);
>+ 
>+    synchronized (previousTimeLock) {
>+      if ((now - millis) != previousTime) {
>+        // We reach this point at most once per second
>+        // across all threads instead of each time format()
>+        // is called. This saves considerable CPU time.
>+         
>+        calendar.setTime(date); 
>+        
>+        int start = sbuf.length();
>+                
>+        int hour = calendar.get(Calendar.HOUR_OF_DAY);
>+        if(hour < 10) {
>+          sbuf.append('0');
>+        }
>+        sbuf.append(hour);
>+        sbuf.append(':');
>+        
>+        int mins = calendar.get(Calendar.MINUTE);
>+        if(mins < 10) {
>+          sbuf.append('0');
>+        }
>+        sbuf.append(mins);
>+        sbuf.append(':');
>+         
>+        int secs = calendar.get(Calendar.SECOND);
>+        if(secs < 10) {
>+          sbuf.append('0');
>+        }
>+        sbuf.append(secs);
>+        
>+        // use current locale's decimal separator
>+        sbuf.append(new java.text.DecimalFormatSymbols().getDecimalSeparator());
>+        
>+        // store the time string for next time to avoid recomputation
>+        sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
>+        
>+        previousTime = now - millis;
>+      }
>+      else {
>+        sbuf.append(previousTimeWithoutMillis);
>+      } 
>+    } 
> 
>-    int millis = calendar.get(Calendar.MILLISECOND);
>     if(millis < 100) 
>       sbuf.append('0');
>     if(millis < 10)
>
>--
>To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
>For additional commands, e-mail: <ma...@jakarta.apache.org>

--
Ceki Gülcü - http://qos.ch



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>