You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by rj...@apache.org on 2011/07/11 15:17:10 UTC

svn commit: r1145166 - in /tomcat/trunk: java/org/apache/catalina/valves/AccessLogValve.java java/org/apache/catalina/valves/LocalStrings.properties webapps/docs/changelog.xml webapps/docs/config/valve.xml

Author: rjung
Date: Mon Jul 11 13:17:09 2011
New Revision: 1145166

URL: http://svn.apache.org/viewvc?rev=1145166&view=rev
Log:
Allow choosing a locale for timestamp formatting
in AccessLogValve. Only relevant to timestamps
explicitely given by SimpleDateFormat syntax.

Also: use Locale.US for CLF and for timestamps
that are part of the access log file name.

Modified:
    tomcat/trunk/java/org/apache/catalina/valves/AccessLogValve.java
    tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/config/valve.xml

Modified: tomcat/trunk/java/org/apache/catalina/valves/AccessLogValve.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/AccessLogValve.java?rev=1145166&r1=1145165&r2=1145166&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/AccessLogValve.java (original)
+++ tomcat/trunk/java/org/apache/catalina/valves/AccessLogValve.java Mon Jul 11 13:17:09 2011
@@ -32,6 +32,7 @@ import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.TimeZone;
 
 import javax.servlet.ServletException;
@@ -249,6 +250,12 @@ public class AccessLogValve extends Valv
      * format) and a HashMap of caches for additional formats used by
      * SimpleDateFormat.</p>
      *
+     * <p>Although the cache supports specifying a locale when retrieving a
+     * formatted timestamp, each format will always use the locale given
+     * when the format was first used. New locales can only be used for new formats.
+     * The CLF format will always be formatted using the locale
+     * <code>en_US</code>.</p>
+     *
      * <p>The cache is not threadsafe. It can be used without synchronization
      * via thread local instances, or with synchronization as a global cache.</p>
      *
@@ -285,21 +292,34 @@ public class AccessLogValve extends Valv
 
             private Cache parent = null;
 
+            private Cache(Cache parent) {
+                this(null, parent);
+            }
+
             private Cache(String format, Cache parent) {
+                this(format, null, parent);
+            }
+
+            private Cache(String format, Locale loc, Cache parent) {
                 cache = new String[cacheSize];
                 for (int i = 0; i < cacheSize; i++) {
                     cache[i] = null;
                 }
+                if (loc == null) {
+                    loc = cacheDefaultLocale;
+                }
                 if (format == null) {
                     isCLF = true;
                     format = cLFFormat;
+                    formatter = new SimpleDateFormat(format, Locale.US);
+                } else {
+                    formatter = new SimpleDateFormat(format, loc);
                 }
-                formatter = new SimpleDateFormat(format);
                 formatter.setTimeZone(TimeZone.getDefault());
                 this.parent = parent;
             }
 
-            private String getFormat(long time) {
+            private String getFormatInternal(long time) {
 
                 long seconds = time / 1000;
 
@@ -349,7 +369,7 @@ public class AccessLogValve extends Valv
                  * parent cache or locally. */
                 if (parent != null) {
                     synchronized(parent) {
-                        previousFormat = parent.getFormat(time);
+                        previousFormat = parent.getFormatInternal(time);
                     }
                 } else {
                     currentDate.setTime(time);
@@ -372,23 +392,25 @@ public class AccessLogValve extends Valv
         /* Number of cached entries */
         private int cacheSize = 0;
 
+        private Locale cacheDefaultLocale;
         private DateFormatCache parent;
         private Cache cLFCache;
         private HashMap<String, Cache> formatCache = new HashMap<String, Cache>();
 
-        private DateFormatCache(int size, DateFormatCache parent) {
+        private DateFormatCache(int size, Locale loc, DateFormatCache parent) {
             cacheSize = size;
+            cacheDefaultLocale = loc;
             this.parent = parent;
             Cache parentCache = null;
             if (parent != null) {
                 synchronized(parent) {
-                    parentCache = parent.getCache(null);
+                    parentCache = parent.getCache(null, null);
                 }
             }
-            cLFCache = new Cache(null, parentCache);
+            cLFCache = new Cache(parentCache);
         }
 
-        private Cache getCache(String format) {
+        private Cache getCache(String format, Locale loc) {
             Cache cache;
             if (format == null) {
                 cache = cLFCache;
@@ -398,19 +420,22 @@ public class AccessLogValve extends Valv
                     Cache parentCache = null;
                     if (parent != null) {
                         synchronized(parent) {
-                            parentCache = parent.getCache(format);
+                            parentCache = parent.getCache(format, loc);
                         }
                     }
-                    cache = new Cache(format, parentCache);
+                    cache = new Cache(format, loc, parentCache);
                     formatCache.put(format, cache);
                 }
             }
             return cache;
         }
 
-        public String getFormat(String format, long time) {
+        public String getFormat(long time) {
+            return cLFCache.getFormatInternal(time);
+        }
 
-            return getCache(format).getFormat(time);
+        public String getFormat(String format, Locale loc, long time) {
+            return getCache(format, loc).getFormatInternal(time);
         }
     }
 
@@ -418,7 +443,7 @@ public class AccessLogValve extends Valv
      * Global date format cache.
      */
     private static final DateFormatCache globalDateCache =
-            new DateFormatCache(globalCacheSize, null);
+            new DateFormatCache(globalCacheSize, Locale.getDefault(), null);
 
     /**
      * Thread local date format cache.
@@ -427,7 +452,7 @@ public class AccessLogValve extends Valv
             new ThreadLocal<DateFormatCache>() {
         @Override
         protected DateFormatCache initialValue() {
-            return new DateFormatCache(localCacheSize, globalDateCache);
+            return new DateFormatCache(localCacheSize, Locale.getDefault(), globalDateCache);
         }
     };
 
@@ -479,6 +504,20 @@ public class AccessLogValve extends Valv
      * Date format to place in log file name. Use at your own risk!
      */
     protected String fileDateFormat = null;
+
+
+    /**
+     * Name of locale used to format timestamps in log entries and in
+     * log file name suffix.
+     */
+    protected String localeName = Locale.getDefault().toString();
+
+
+    /**
+     * Locale used to format timestamps in log entries and in
+     * log file name suffix.
+     */
+    protected Locale locale = Locale.getDefault();
     
     /**
      * Array of AccessLogElement, they will be used to make log message.
@@ -708,6 +747,7 @@ public class AccessLogValve extends Valv
         this.condition = condition;
     }
 
+
     /**
      *  Return the date format date based log rotation.
      */
@@ -723,6 +763,29 @@ public class AccessLogValve extends Valv
         this.fileDateFormat =  fileDateFormat;
     }
 
+
+    /**
+     * Return the locale used to format timestamps in log entries and in
+     * log file name suffix.
+     */
+    public String getLocale() {
+        return localeName;
+    }
+
+
+    /**
+     * Set the locale used to format timestamps in log entries and in
+     * log file name suffix. Changing the locale is only supported
+     * as long as the AccessLogValve has not logged anything. Changing
+     * the locale later can lead to inconsistent formatting.
+     *
+     * @param locale The locale to use.
+     */
+    public void setLocale(String localeName) {
+        this.localeName = localeName;
+        locale = findLocale(localeName, locale);
+    }
+
     // --------------------------------------------------------- Public Methods
 
     /**
@@ -979,6 +1042,23 @@ public class AccessLogValve extends Valv
         return tz.toString();
     }
 
+    /**
+     * Find a locale by name
+     */
+    protected static Locale findLocale(String name, Locale fallback) {
+        if (name == null || name.isEmpty()) {
+            return Locale.getDefault();
+        } else {
+            for (Locale l: Locale.getAvailableLocales()) {
+                if (name.equals(l.toString())) {
+                    return(l);
+                }
+            }
+        }
+        log.error(sm.getString("accessLogValve.invalidLocale", name));
+        return fallback;
+    }
+
     static {
         // Initialize the timeZone
         timezone = TimeZone.getDefault();
@@ -1004,7 +1084,7 @@ public class AccessLogValve extends Valv
             format = "yyyy-MM-dd";
             setFileDateFormat(format);
         }
-        fileDateFormatter = new SimpleDateFormat(format);
+        fileDateFormatter = new SimpleDateFormat(format, Locale.US);
         fileDateFormatter.setTimeZone(timezone);
         dateStamp = fileDateFormatter.format(new Date(System.currentTimeMillis()));
         open();
@@ -1252,7 +1332,6 @@ public class AccessLogValve extends Valv
                     escape = !escape;
                 }
             }
-            format = result.toString();
         }
 
         protected DateAndTimeElement(String header) {
@@ -1296,7 +1375,7 @@ public class AccessLogValve extends Valv
             }
             switch (type) {
             case CLF:
-                buf.append(localDateCache.get().getFormat(null, timestamp));
+                buf.append(localDateCache.get().getFormat(timestamp));
                 break;
             case SEC:
                 buf.append(timestamp / 1000);
@@ -1317,7 +1396,7 @@ public class AccessLogValve extends Valv
                 buf.append(frac);
                 break;
             case SDF:
-                String temp = localDateCache.get().getFormat(format, timestamp);
+                String temp = localDateCache.get().getFormat(format, locale, timestamp);
                 if (usesMsecs) {
                     frac = timestamp % 1000;
                     StringBuilder trippleMsec = new StringBuilder(4);

Modified: tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties?rev=1145166&r1=1145165&r2=1145166&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/catalina/valves/LocalStrings.properties Mon Jul 11 13:17:09 2011
@@ -25,6 +25,7 @@ cometConnectionManagerValve.listenerEven
 accessLogValve.closeFail=Failed to close log file
 accessLogValve.openDirFail=Failed to create directory [{0}] for access logs
 accessLogValve.rotateFail=Failed to rotate access log
+accessLogValve.invalidLocale=Failed to set locale to [{0}]
 
 # Error report valve
 errorReportValve.errorReport=Error report

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1145166&r1=1145165&r2=1145166&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Mon Jul 11 13:17:09 2011
@@ -57,7 +57,7 @@
   <subsection name="Catalina">
     <changelog>
       <add>
-        Add option to activate AccessLog for unit tests. (rjung)
+        Add option to activate access log for unit tests. (rjung)
       </add>
       <fix>
         Fix regression in year number formatting for AccessLogValve. (rjung)
@@ -67,6 +67,10 @@
         if the associated web application was destroyed while the request was
         processing. (markt)
       </fix>
+      <update>
+        Allow choosing a locale for timestamp formatting in AccessLogValve.
+        (rjung)
+      </update>
     </changelog>
   </subsection>
   <subsection name="Coyote">

Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=1145166&r1=1145165&r2=1145166&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Mon Jul 11 13:17:09 2011
@@ -103,6 +103,19 @@
         (relative to $CATALINA_BASE).</p>
       </attribute>
 
+      <attribute name="locale" required="false">
+        <p>The locale used to format timestamps in the access log
+           lines. Any timestamps configured using an
+           explicit SimpleDateFormat pattern (<code>%{xxx}t</code>)
+           are formatted in this locale. By default the
+           default locale of the Java process is used. Switching the
+           locale after the AccessLogValve is initialized is not supported.
+           Any timestamps using the common log format
+           (<code>CLF</code>) are always formatted in the locale
+           <code>en_US</code>.
+        </p>
+      </attribute>
+
       <attribute name="pattern" required="false">
         <p>A formatting layout identifying the various information fields
         from the request and response to be logged, or the word
@@ -165,7 +178,9 @@
         <p>Allows a customized date format in the access log file name.
            The date format also decides how often the file is rotated.
            If you wish to rotate every hour, then set this value
-           to: <code>yyyy-MM-dd.HH</code>
+           to: <code>yyyy-MM-dd.HH</code>. The default value is
+           <code>yyyy-MM-dd</code>. The date format will always be localized
+           using the locale <code>en_US</code>.
         </p>
       </attribute>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org