]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-2950: Minor generalization of Profiler class. Temporary expedient in log4j...
authorAron Roberts <aron@socrates.berkeley.edu>
Mon, 27 Sep 2010 07:05:54 +0000 (07:05 +0000)
committerAron Roberts <aron@socrates.berkeley.edu>
Mon, 27 Sep 2010 07:05:54 +0000 (07:05 +0000)
services/common/src/main/config/log/jboss-log4j.xml
services/common/src/main/java/org/collectionspace/services/common/profile/CSpaceFilter.java
services/common/src/main/java/org/collectionspace/services/common/profile/Profiler.java

index f4bdca6c5a27003d7406cfbdb77ed2f892f0f938..d5f0a0daa13672cab5a11f7488e86855a8626867 100644 (file)
 
    <!-- collectionspace performance appender -->
    <appender name="CSLOG_PERF" class="org.jboss.logging.appender.DailyRollingFileAppender">
-      <errorHandler  class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
-     <param name="Append" value="false"/>
-     <param name="DatePattern" value="'.'yyyy-MM-dd"/>
+      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
+      <param name="Append" value="false"/>
+      <param name="DatePattern" value="'.'yyyy-MM-dd"/>
       <param name="File" value="${jboss.server.log.dir}/collectionspace-perf.log"/>
       <layout class="org.apache.log4j.PatternLayout">
-         <param name="ConversionPattern" value="%d [%t] %m%n"/>
+         <!-- FIXME: Temporary change to accommodate interleaved CSV log entries -->
+         <!-- param name="ConversionPattern" value="%d [%t] %m%n"/ -->
+         <param name="ConversionPattern" value="&quot;%d&quot;,%m%n"/>
       </layout>
             <!--filter class="org.jboss.logging.filter.TCLFilter">
          <param name="AcceptOnMatch" value="true"/>
       <filter class="org.apache.log4j.varia.DenyAllFilter"></filter-->
    </appender>
 
-   <!-- collectionspace performance appender, generating a format -->
-   <!-- common to the services and app layers -->
-   <appender name="CSLOG_PERF_COMMON" class="org.jboss.logging.appender.DailyRollingFileAppender">
-      <errorHandler  class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
-     <param name="Append" value="false"/>
-     <param name="DatePattern" value="'.'yyyy-MM-dd"/> <!-- Roll over at midnight daily -->
-      <param name="File" value="${jboss.server.log.dir}/collectionspace-perf-common.log"/>
+   <!-- collectionspace performance appender, generating a comma-separated value (CSV) -->
+   <!-- format common to (at least) the services and app layers -->
+   <appender name="CSLOG_PERF_CSV" class="org.jboss.logging.appender.DailyRollingFileAppender">
+      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
+      <param name="Append" value="false"/>
+      <param name="DatePattern" value="'.'yyyy-MM-dd"/> <!-- Roll over at midnight daily -->
+      <param name="File" value="${jboss.server.log.dir}/collectionspace-perf-csv.log"/>
       <layout class="org.apache.log4j.PatternLayout">
-         <param name="ConversionPattern" value="&quot;%d&quot;,%r,%t,app,svc,%C{2},%M,method_get_uri_placeholder,svc%n"/>
+         <!-- param name="ConversionPattern" value="&quot;%d&quot;,%r,%t,app,svc,%C{2},%M,method_get_uri_placeholder,svc%n"/ -->
+         <param name="ConversionPattern" value="&quot;%d&quot;,%m%n"/>
       </layout>
    </appender>
    
    <category name="perf.collectionspace">
      <priority value="DEBUG" />
      <appender-ref ref="CSLOG_PERF"/>
-     <appender-ref ref="CSLOG_PERF_COMMON"/>
+   </category>
+
+   <category name="perf.collectionspace.csv">
+     <priority value="DEBUG" />
+     <appender-ref ref="CSLOG_PERF_CSV"/>
    </category>
    
    <!-- ======================= -->
index 1d2e44b2dc02a659db68386bf3ddd82b3ecb6e1c..72aa93411675807a528cd6eb230b05b928908a03 100644 (file)
@@ -1,14 +1,4 @@
-/**    \r
- * CSpaceFilter.java\r
- *\r
- * {Purpose of This Class}\r
- *\r
- * {Other Notes Relating to This Class (Optional)}\r
- *\r
- * $LastChangedBy: $\r
- * $LastChangedRevision: $\r
- * $LastChangedDate: $\r
- *\r
+/**\r
  * This document is a part of the source code and related artifacts\r
  * for CollectionSpace, an open source collections management system\r
  * for museums and related institutions:\r
@@ -36,52 +26,92 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;\r
 //import javax.servlet.ServletContext;\r
 \r
+import org.collectionspace.services.common.ServletTools;\r
+\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
 /**\r
- * The Class CSpaceFilter.\r
+ * CSpaceFilter.java\r
+ *\r
+ * A filter that performs specified actions at the time\r
+ * each new request is received by the servlet container.\r
+ *\r
+ * This filter is currently used for recording performance\r
+ * metrics for requests to the CollectionSpace services.\r
+ *\r
+ * $LastChangedRevision: $\r
+ * $LastChangedDate: $\r
+ *\r
  */\r
 public class CSpaceFilter implements Filter {\r
-       \r
-       /** The filter config. */\r
-       FilterConfig filterConfig = null;\r
 \r
-       /* (non-Javadoc)\r
-        * @see javax.servlet.Filter#destroy()\r
-        */\r
-       @Override\r
-       public void destroy() {\r
-               // Empty method.\r
-       }\r
+    /** The filter config. */\r
+    FilterConfig filterConfig = null;\r
+\r
+    private final String CLASS_NAME = this.getClass().getSimpleName();\r
+    private Logger csvPerfLogger = LoggerFactory.getLogger("perf.collectionspace.csv");\r
+\r
+    /* (non-Javadoc)\r
+     * @see javax.servlet.Filter#destroy()\r
+     */\r
+    @Override\r
+    public void destroy() {\r
+        // Empty method.\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)\r
+     */\r
+    @Override\r
+    public void doFilter(ServletRequest request, ServletResponse response,\r
+            FilterChain chain) throws IOException, ServletException {\r
+        if (request != null) {\r
+            HttpServletRequest httpRequest = (HttpServletRequest) request;\r
+\r
+            // Instantiate the CollectionSpace services profiler.\r
+            StringBuffer uri = new StringBuffer(httpRequest.getRequestURI());\r
+            uri.append(':');\r
+            uri.append(httpRequest.getMethod());\r
+            Profiler profiler = new Profiler(uri.toString(), 0);\r
+\r
+            // Start timing.\r
+            profiler.start();\r
+\r
+            // Process the request.\r
+            chain.doFilter(request, response);\r
+\r
+            // Stop timing and log performance-related metrics.\r
+            profiler.stop();\r
 \r
-       /* (non-Javadoc)\r
-        * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)\r
-        */\r
-       @Override\r
-       public void doFilter(ServletRequest request, ServletResponse response,\r
-                       FilterChain chain) throws IOException, ServletException {               \r
-               if (request != null) {\r
-                       HttpServletRequest httpRequest = (HttpServletRequest)request;\r
-                       StringBuffer uri = new StringBuffer(httpRequest.getRequestURI());\r
-                       uri.append(':');\r
-                       uri.append(httpRequest.getMethod());\r
-                       Profiler profiler = new Profiler(uri.toString(),\r
-                                       0);\r
-                       profiler.start();\r
-                       chain.doFilter(request, response);\r
-//                     profiler.log(httpRequest.getRequestURI());\r
-                       profiler.stop();\r
-               }\r
-       }\r
+            String csvMsg =\r
+                    "," + System.currentTimeMillis()\r
+                    + "," + Thread.currentThread().getName()\r
+                    + "," + "app"\r
+                    + "," + "svc"\r
+                    + "," + CLASS_NAME\r
+                    + "," + httpRequest.getMethod()\r
+                    + "," + ServletTools.getURL(httpRequest)\r
+                    + "," + profiler.getElapsedTime();\r
 \r
-       /* (non-Javadoc)\r
-        * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)\r
-        */\r
-       @Override\r
-       public void init(FilterConfig theFilterConfig) throws ServletException {\r
-               filterConfig = theFilterConfig;\r
-               if (filterConfig != null) {\r
-                       // We can initialize using the init-params here which we defined in\r
-                       // web.xml)\r
-               }\r
-       }\r
+            // FIXME: Expedient change interleaves CSV-style log entries with entries\r
+            // in the original perf log.  These should be written to their own log file,\r
+            // with their own patternLayout.\r
+            profiler.log(csvMsg);\r
+            profiler.reset();\r
+            // csvPerfLogger.debug(csvMsg);\r
+        }\r
+    }\r
 \r
+    /* (non-Javadoc)\r
+     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)\r
+     */\r
+    @Override\r
+    public void init(FilterConfig theFilterConfig) throws ServletException {\r
+        filterConfig = theFilterConfig;\r
+        if (filterConfig != null) {\r
+            // We can initialize using the init-params here which we defined in\r
+            // web.xml)\r
+        }\r
+    }\r
 }\r
index 1a85859cd7fadd892eda470105dfc6c2fa9b784c..d63c5300f31a21ed5778fbdeb880f630c196dfc4 100644 (file)
@@ -1,14 +1,4 @@
-/**    \r
- * Profiler.java\r
- *\r
- * {Purpose of This Class}\r
- *\r
- * {Other Notes Relating to This Class (Optional)}\r
- *\r
- * $LastChangedBy: $\r
- * $LastChangedRevision: $\r
- * $LastChangedDate: $\r
- *\r
+/**\r
  * This document is a part of the source code and related artifacts\r
  * for CollectionSpace, an open source collections management system\r
  * for museums and related institutions:\r
@@ -29,137 +19,272 @@ package org.collectionspace.services.common.profile;
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
 \r
-\r
 /**\r
- * The Class Profiler.\r
+ * Profiler.java\r
+ *\r
+ * Simple utility to store and report performance metrics.\r
+ *\r
+ * Records start and stop times, and elapsed and cumulative timings;\r
+ * writes performance-related log times.\r
+ *\r
+ * $LastChangedRevision: $\r
+ * $LastChangedDate: $\r
+ *\r
  */\r
 public class Profiler {\r
-       \r
-       private int messageIndent = 0;\r
-       \r
-       /** The start time. */\r
-       private long startTime = 0;\r
-       \r
-       /** The stop time. */\r
-       private long stopTime = 0;\r
-       \r
-       /** The final time. */\r
-       private long finalTime = 0;\r
-       \r
-       /** The message prefix. */\r
-       private String messagePrefix = "Default profiler prefix:";\r
 \r
+    /** The level of indentation. */\r
+    private int messageIndent = 0;\r
+    /** The indentation character(s) */\r
+    private static String INDENT = "\t";\r
+    /** The message prefix. */\r
+    private String messagePrefix = "";\r
+    /** The separator between the message prefix and the message. **/\r
+    final static String PREFIX_SEPARATOR = ":";\r
+    /** The start time. */\r
+    private long startTime = 0;\r
+    /** The stop time. */\r
+    private long stopTime = 0;\r
+    /** The segment time. */\r
+    private long elapsedTime = 0;\r
+    /** The cumulative time. */\r
+    private long cumulativeTime = 0;\r
     /** The profiler logger. */\r
-       private static String LOG4J_CATEGORY = "perf.collectionspace";\r
-    private static Logger profilerLogger = LoggerFactory.getLogger(LOG4J_CATEGORY);\r
-       \r
+    private static String DEFAULT_LOG4J_CATEGORY = "perf.collectionspace";\r
+    private static Logger profileLogger = LoggerFactory.getLogger(DEFAULT_LOG4J_CATEGORY);\r
+\r
     /**\r
      * private default constructor.\r
      */\r
     private Profiler() {\r
-       //empty default constructor\r
+        //empty default constructor\r
+    }\r
+\r
+    /**\r
+     * Instantiates a new profiler.\r
+     *\r
+     * @param theObject a class whose name is to be logged.\r
+     */\r
+    public Profiler(Object theObject) {\r
+        this(theObject, 0);\r
     }\r
-    \r
+\r
     /**\r
-     * Sets the message prefix.\r
+     * Instantiates a new profiler.\r
      *\r
-     * @param theMessagePrefix the new message prefix\r
+     * @param theObject a class whose name is to be logged.\r
+     * @param messageIndent the level of indentation for log messages.\r
      */\r
-    protected void setMessagePrefix(String theMessagePrefix, int indent) {\r
-       StringBuffer stringBuffer = new StringBuffer();\r
-       for (int i = 0; i < indent; i++) {\r
-               stringBuffer.append('\t');\r
-       }\r
-       stringBuffer.append(theMessagePrefix);\r
-       stringBuffer.append(':');\r
-       messagePrefix = stringBuffer.toString();\r
-    }\r
-    \r
-    protected StringBuffer getMessagePrefix() {\r
-       return new StringBuffer(messagePrefix);\r
-    }\r
-    \r
+    public Profiler(Object theObject, int messageIndent) {\r
+        init(objectName(theObject), messageIndent);\r
+    }\r
+\r
     /**\r
      * Instantiates a new profiler.\r
-     * @param theObject \r
-     * @param indent \r
      *\r
-     * @param theClass the the class\r
+     * @param messagePrefix the message prefix to appear in log messages.\r
+     * @param messageIndent the level of indentation for log messages.\r
+     */\r
+    public Profiler(String messagePrefix, int messageIndent) {\r
+        init(messagePrefix, messageIndent);\r
+    }\r
+\r
+    /*\r
+     * For some reason, we need to call this method "early" at startup time for our\r
+     * Logger instance to get created correctly.  FIXME: REM - Can we figure this out and fix it?\r
+     */\r
+    /**\r
+     * Setup.\r
+     */\r
+    public static void setup() {\r
+        //do nothing\r
+    }\r
+\r
+    private void init(String messagePrefix, int messageIndent) {\r
+        this.setMessagePrefix(messagePrefix);\r
+        this.setMessageIndent(messageIndent);\r
+    }\r
+\r
+    /**\r
+     * Stores and logs the start time.\r
+     *\r
+     * Logs using a default message.\r
+     */\r
+    public void start() {\r
+        start(defaultStartMessage());\r
+    }\r
+\r
+    /**\r
+     * Stores and logs the start time.\r
+     *\r
+     * @param msg the message to log.\r
+     */\r
+    public void start(String msg) {\r
+        log(msg);\r
+        setStartTime(currentTime());\r
+    }\r
+\r
+    /**\r
+     * Stores and logs the stop time, and the elapsed and cumulative timings\r
+     * from one or more cycles of start and stop.\r
+     *\r
+     * Logs using a default message.\r
+     */\r
+    public void stop() {\r
+        // FIXME: Need to store values before constructing default stop message,\r
+        // hence has some redundant code with stop(msg) below.  Perhaps can be consolidated.\r
+        setStopTime(currentTime());\r
+        setElapsedTime(elapsedTime());\r
+        addToCumulativeTime(elapsedTime());\r
+        stop(defaultStopMessage());\r
+    }\r
+\r
+    /**\r
+     * Stores and logs the stop time, and the elapsed and cumulative timings,\r
+     * from one or more cycles of start and stop.\r
+     *\r
+     * @param msg the message to log.\r
+     */\r
+    public void stop(String msg) {\r
+        setStopTime(currentTime());\r
+        setElapsedTime(elapsedTime());\r
+        addToCumulativeTime(elapsedTime());\r
+        log(msg);\r
+    }\r
+\r
+    public long getStartTime() {\r
+        return this.startTime;\r
+    }\r
+\r
+    public long getStopTime() {\r
+        return this.stopTime;\r
+    }\r
+\r
+    public long getElapsedTime() {\r
+        return this.elapsedTime;\r
+    }\r
+\r
+    public long getCumulativeTime() {\r
+        return this.cumulativeTime;\r
+    }\r
+\r
+    /**\r
+     * Resets the start and stop time, and the elapsed and cumulative timings.\r
+     */\r
+    public void reset() {\r
+        setStartTime(0);\r
+        setStopTime(0);\r
+        setElapsedTime(0);\r
+        setCumulativeTime(0);\r
+    }\r
+\r
+    /**\r
+     * Writes a log entry.\r
+     *\r
+     * @param msg the message to log.\r
+     */\r
+    public void log(String msg) {\r
+        if (getLogger().isDebugEnabled()) {\r
+            getLogger().debug(formatLogMessage(msg));\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Gets the logger.\r
+     *\r
+     * @return the logger\r
      */\r
-    public Profiler(Object theObject, int indent) {\r
-       if (theObject != null) {\r
-               this.setMessagePrefix(theObject.getClass().getSimpleName(), indent);\r
-       }\r
-    }\r
-       /**\r
-        * Instantiates a new profiler.\r
-        *\r
-        * @param theMessagePrefix the the message prefix\r
-        * @param indent \r
-        */\r
-       public Profiler(String theMessagePrefix, int indent) {\r
-               this.setMessagePrefix(theMessagePrefix, indent);\r
-       }\r
-       \r
-       /*\r
-        * For some reason, we need to call this method "early" at startup time for our\r
-        * Logger instance to get created correctly.  FIXME: REM - Can we figure this out and fix it?\r
-        */\r
-       /**\r
-        * Setup.\r
-        */\r
-       public static void setup() {\r
-               //do nothing\r
-       }\r
-       \r
-       /**\r
-        * Gets the logger.\r
-        *\r
-        * @return the logger\r
-        */\r
-       protected Logger getLogger() {\r
-               return profilerLogger;\r
-       }\r
-       \r
-       /**\r
-        * Private log.\r
-        *\r
-        * @param inMessage the in message\r
-        */\r
-       public void log(String inMessage) {\r
-               if (getLogger().isDebugEnabled() == true) {\r
-                       StringBuffer finalMessage = getMessagePrefix();\r
-                       if (inMessage != null) {\r
-                               finalMessage.append(inMessage);\r
-                       }\r
-                       getLogger().debug(finalMessage.toString());\r
-               }\r
-       }\r
-       \r
-       /**\r
-        * Start\r
-        */\r
-       public void start() {\r
-               if (getLogger().isDebugEnabled() == true) {\r
-                       StringBuffer message = getMessagePrefix();\r
-                       message.append(">>>> Start >>>>");\r
-                       getLogger().debug(message.toString());\r
-               }\r
-               startTime = System.currentTimeMillis();\r
-       }\r
-       \r
-       /**\r
-        * Stop.\r
-        */\r
-       public void stop() {\r
-               stopTime = System.currentTimeMillis();\r
-               finalTime = finalTime + (stopTime - startTime);\r
-               if (getLogger().isDebugEnabled() == true) {\r
-                       StringBuffer message = getMessagePrefix();\r
-                       message.append("<<<< Stopped <<<< [");\r
-                       message.append(finalTime);\r
-                       message.append("ms]");\r
-                       getLogger().debug(message.toString());\r
-               }               \r
-       }\r
+    protected Logger getLogger() {\r
+        return this.profileLogger;\r
+    }\r
+\r
+    private void setMessagePrefix(String prefix) {\r
+        this.messagePrefix = prefix;\r
+    }\r
+\r
+    private String getMessagePrefix() {\r
+        return this.messagePrefix;\r
+    }\r
+\r
+    private int getMessageIndent() {\r
+        return this.messageIndent;\r
+    }\r
+\r
+    private void setMessageIndent(int indent) {\r
+        this.messageIndent = indent;\r
+    }\r
+\r
+    private void setStartTime(long start) {\r
+        this.startTime = start;\r
+    }\r
+\r
+    private void setStopTime(long stop) {\r
+        this.stopTime = stop;\r
+    }\r
+\r
+    private void setElapsedTime(long segment) {\r
+        this.elapsedTime = segment;\r
+    }\r
+\r
+    private void setCumulativeTime(long cumulative) {\r
+        this.cumulativeTime = cumulative;\r
+    }\r
+\r
+    private void addToCumulativeTime(long cumulative) {\r
+        this.cumulativeTime += cumulative;\r
+    }\r
+\r
+    private long currentTime() {\r
+        return System.currentTimeMillis();\r
+    }\r
+\r
+    private long elapsedTime() {\r
+        return (currentTime() - getStartTime());\r
+    }\r
+\r
+    private String objectName(Object theObject) {\r
+        if (theObject != null) {\r
+            return (theObject.getClass().getSimpleName());\r
+        } else {\r
+            return "";\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns a formatted log message, including indentation and prefix.\r
+     *\r
+     * @param msg the message to log.\r
+     * @return a constructed log message, including indentation and prefix, if any.\r
+     */\r
+    private String formatLogMessage(String msg) {\r
+        StringBuffer logMsg = new StringBuffer();\r
+        for (int i = 0; i < getMessageIndent(); i++) {\r
+            logMsg.append(INDENT);\r
+        }\r
+        String prefix = getMessagePrefix();\r
+        if (prefix != null && !prefix.trim().isEmpty()) {\r
+            logMsg.append(prefix);\r
+            logMsg.append(PREFIX_SEPARATOR);\r
+        }\r
+        if (msg != null) {\r
+            logMsg.append(msg);\r
+        }\r
+        return logMsg.toString();\r
+    }\r
+\r
+    private String defaultStartMessage() {\r
+        StringBuffer defaultStartMessage = new StringBuffer();\r
+        defaultStartMessage.append(">>>> Start >>>>");\r
+        return defaultStartMessage.toString();\r
+    }\r
+\r
+    private String defaultStopMessage() {\r
+        StringBuffer defaultStopMessage = new StringBuffer();\r
+        defaultStopMessage.append("<<<< Stopped <<<<");\r
+        defaultStopMessage.append(" [" + getElapsedTime() + " ms]");\r
+        if (getCumulativeTime() > getElapsedTime()) {\r
+            defaultStopMessage.append(" (cumulative [" + getCumulativeTime() + " ms])");\r
+        }\r
+        return defaultStopMessage.toString();\r
+    }\r
 }\r