You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2012/07/15 18:07:59 UTC

svn commit: r1361722 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/metrics/ common/servicedef/ common/src/org/ofbiz/common/

Author: adrianc
Date: Sun Jul 15 16:07:59 2012
New Revision: 1361722

URL: http://svn.apache.org/viewvc?rev=1361722&view=rev
Log:
New feature - performance metrics. Basic code and services.

Added:
    ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/
    ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/Metrics.java   (with props)
    ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/MetricsFactory.java   (with props)
Modified:
    ofbiz/trunk/framework/common/servicedef/services.xml
    ofbiz/trunk/framework/common/src/org/ofbiz/common/CommonServices.java

Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/Metrics.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/Metrics.java?rev=1361722&view=auto
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/Metrics.java (added)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/Metrics.java Sun Jul 15 16:07:59 2012
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ Copyright (c) 2002 by Matt Welsh and The Regents of the University of California. All rights reserved.
+
+ IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA
+ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE
+ UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+package org.ofbiz.base.metrics;
+
+/**
+ * An object that tracks service metrics.
+ * <p>This interface and its default implementation are based on the
+ * <code>seda.sandstorm.internal.StageStats</code> class written by
+ * Matt Welsh.</code>
+ * @see <a href="http://www.eecs.harvard.edu/~mdw/proj/seda/">SEDA</a>
+ */
+public interface Metrics {
+
+    public static final int ESTIMATION_SIZE = 100;
+    public static final long ESTIMATION_TIME = 1000;
+    public static final double SMOOTHING = 0.7;
+
+    /**
+     * Returns the name of the metric.
+     */
+    String getName();
+
+    /**
+     * Returns a moving average of the service rate in milliseconds. The default
+     * implementation divides the total time by the total number of events and then
+     * applies a smoothing factor.
+     */
+    double getServiceRate();
+
+    /** Returns the metric threshold. The meaning of the threshold is
+     * determined by client code.
+     * <p>The idea is for client code to compare {@link #getServiceRate()} to
+     * the threshold and perform some action based on the comparison.</p>
+     */
+    double getThreshold();
+
+    /** Returns the total number of processed events. */
+    long getTotalEvents();
+
+    /** 
+     * Records the service time for <code>numEvents</code> taking
+     * <code>time</code> milliseconds to be processed.
+     */
+    void recordServiceRate(int numEvents, long time);
+
+    /** Resets all metrics. */
+    void reset();
+}
\ No newline at end of file

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/Metrics.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/Metrics.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Rev URL

Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/MetricsFactory.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/MetricsFactory.java?rev=1361722&view=auto
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/MetricsFactory.java (added)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/MetricsFactory.java Sun Jul 15 16:07:59 2012
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ Copyright (c) 2002 by Matt Welsh and The Regents of the University of California. All rights reserved.
+
+ IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA
+ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE
+ UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+package org.ofbiz.base.metrics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.ofbiz.base.lang.LockedBy;
+import org.ofbiz.base.lang.ThreadSafe;
+import org.ofbiz.base.util.Assert;
+import org.ofbiz.base.util.cache.UtilCache;
+import org.w3c.dom.Element;
+
+/**
+ * A {@link org.ofbiz.base.metrics.Metrics} factory.
+ */
+@ThreadSafe
+public final class MetricsFactory {
+
+    private static final UtilCache<String, Metrics> METRICS_CACHE = UtilCache.createUtilCache("base.metrics", 0, 0);
+    /**
+     * A "do-nothing" <code>Metrics</code> instance.
+     */
+    public static final Metrics NULL_METRICS = new NullMetrics();
+
+    /**
+     * Creates a <code>Metrics</code> instance based on <code>element</code> attributes.
+     * If an instance with the same name already exists, it will be returned.
+     * <p><strong>Element Attributes</strong>
+     * <table border="1">
+     * <tr><th>Attribute Name</th><th>Requirements</th><th>Description</th><th>Notes</th></tr>
+     * <tr><td>name</td><td>Required</td><td>The metric name.</td><td>&nbsp;</td></tr>
+     * <tr><td>estimation-size</td><td>Optional</td><td>Positive integer number of events to include in the metrics calculation.</td><td>Defaults to "100".</td></tr>
+     * <tr><td>estimation-time</td><td>Optional</td><td>Positive integer number of milliseconds to include in the metrics calculation.</td><td>Defaults to "1000".</td></tr>
+     * <tr><td>smoothing</td><td>Optional</td><td>Smoothing factor - used to smooth the differences between calculations.</td><td>A value of "1" disables smoothing. Defaults to "0.7".</td></tr>
+     * <tr><td>threshold</td><td>Optional</td><td>The metric threshold. The meaning of the threshold is determined by client code.</td><td>Defaults to "0.0".</td></tr>
+     * </table></p>
+     * 
+     * @param element The element whose attributes will be used to create the <code>Metrics</code> instance
+     * @return A <code>Metrics</code> instance based on <code>element</code> attributes
+     * @throws IllegalArgumentException if <code>element</code> is null or if the name attribute is empty
+     * @throws NumberFormatException if any of the numeric attribute values are unparsable
+     */
+    public static Metrics getInstance(Element element) {
+        Assert.notNull("element", element);
+        String name = element.getAttribute("name");
+        Assert.notEmpty("name attribute", name);
+        Metrics result = METRICS_CACHE.get(name);
+        if (result == null) {
+            int estimationSize = Metrics.ESTIMATION_SIZE;
+            String attributeValue = element.getAttribute("estimation-size");
+            if (!attributeValue.isEmpty()) {
+                estimationSize = Integer.parseInt(attributeValue);
+            }
+            long estimationTime = Metrics.ESTIMATION_TIME;
+            attributeValue = element.getAttribute("estimation-time");
+            if (!attributeValue.isEmpty()) {
+                estimationTime = Long.parseLong(attributeValue);
+            }
+            double smoothing = Metrics.SMOOTHING;
+            attributeValue = element.getAttribute("smoothing");
+            if (!attributeValue.isEmpty()) {
+                smoothing = Double.parseDouble(attributeValue);
+            }
+            double threshold = 0.0;
+            attributeValue = element.getAttribute("threshold");
+            if (!attributeValue.isEmpty()) {
+                threshold = Double.parseDouble(attributeValue);
+            }
+            result = new MetricsImpl(name, estimationSize, estimationTime, smoothing, threshold);
+            METRICS_CACHE.putIfAbsent(name, result);
+            result = METRICS_CACHE.get(name);
+        }
+        return result;
+    }
+
+    /**
+     * Creates a <code>Metrics</code> instance.
+     * If an instance with the same name already exists, it will be returned.
+     * @param name The metric name.
+     * @param estimationSize Positive integer number of events to include in the metrics calculation.
+     * @param estimationTime Positive integer number of milliseconds to include in the metrics calculation.
+     * @param smoothing Smoothing factor - used to smooth the differences between calculations.
+     * @return A <code>Metrics</code> instance
+     */
+    public static Metrics getInstance(String name, int estimationSize, long estimationTime, double smoothing, double threshold) {
+        Assert.notNull("name", name);
+        Metrics result = METRICS_CACHE.get(name);
+        if (result == null) {
+            result = new MetricsImpl(name, estimationSize, estimationTime, smoothing, threshold);
+            METRICS_CACHE.putIfAbsent(name, result);
+            result = METRICS_CACHE.get(name);
+        }
+        return result;
+    }
+
+    /**
+     * Returns an existing <code>Metric</code> instance with the specified name.
+     * Returns <code>null</code> if the metric does not exist.
+     * @param name The metric name
+     */
+    public static Metrics getMetric(String name) {
+        Assert.notNull("name", name);
+        return METRICS_CACHE.get(name);
+    }
+
+    /**
+     * Returns all <code>Metric</code> instances.
+     */
+    public static List<Metrics> getMetrics() {
+        return new ArrayList<Metrics>(METRICS_CACHE.values());
+    }
+
+    private static final class MetricsImpl implements Metrics {
+        @LockedBy("this")
+        private int count = 0;
+        @LockedBy("this")
+        private long lastTime = System.currentTimeMillis();
+        @LockedBy("this")
+        private double serviceRate = 0.0;
+        @LockedBy("this")
+        private long totalServiceTime = 0;
+        @LockedBy("this")
+        private long totalEvents = 0;
+        @LockedBy("this")
+        private long cumulativeEvents;
+        private final String name;
+        private final int estimationSize;
+        private final long estimationTime;
+        private final double smoothing;
+        private final double threshold;
+
+        private MetricsImpl(String name, int estimationSize, long estimationTime, double smoothing, double threshold) {
+            this.name = name;
+            this.estimationSize = estimationSize;
+            this.estimationTime = estimationTime;
+            this.smoothing = smoothing;
+            this.threshold = threshold;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                MetricsImpl that = (MetricsImpl) obj;
+                return this.name.equals(that.name);
+            } catch (Exception e) {}
+            return false;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public synchronized double getServiceRate() {
+            return serviceRate;
+        }
+
+        @Override
+        public double getThreshold() {
+            return threshold;
+        }
+
+        @Override
+        public synchronized long getTotalEvents() {
+            return cumulativeEvents;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        @Override
+        public synchronized void recordServiceRate(int numEvents, long time) {
+            totalEvents += numEvents;
+            cumulativeEvents += numEvents;
+            totalServiceTime += time;
+            count++;
+            long curTime = System.currentTimeMillis();
+            if ((count == estimationSize) || (curTime - lastTime >= estimationTime)) {
+                if (totalEvents == 0) {
+                    totalEvents = 1;
+                }
+                double rate = totalServiceTime / totalEvents;
+                serviceRate = (rate * smoothing) + (serviceRate * (1.0 - smoothing));
+                count = 0;
+                lastTime = curTime;
+                totalEvents = totalServiceTime = 0;
+            }
+        }
+
+        @Override
+        public synchronized void reset() {
+            serviceRate = 0.0;
+            count = 0;
+            lastTime = System.currentTimeMillis();
+            totalEvents = totalServiceTime = cumulativeEvents = 0;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    private static final class NullMetrics implements Metrics {
+
+        @Override
+        public String getName() {
+            return "NULL";
+        }
+
+        @Override
+        public double getServiceRate() {
+            return 0;
+        }
+
+        @Override
+        public double getThreshold() {
+            return 0.0;
+        }
+
+        @Override
+        public long getTotalEvents() {
+            return 0;
+        }
+
+        @Override
+        public void recordServiceRate(int numEvents, long time) {
+        }
+
+        @Override
+        public void reset() {
+        }
+    }
+
+    private MetricsFactory() {}
+}

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/MetricsFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/metrics/MetricsFactory.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Rev URL

Modified: ofbiz/trunk/framework/common/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/servicedef/services.xml?rev=1361722&r1=1361721&r2=1361722&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/servicedef/services.xml (original)
+++ ofbiz/trunk/framework/common/servicedef/services.xml Sun Jul 15 16:07:59 2012
@@ -787,4 +787,20 @@ under the License.
         <attribute name="encoding" mode="IN" type="String" optional="true" default-value="UTF-8"></attribute>
     </service>
 
+    <!-- Metrics services -->
+    <service name="getAllMetrics" auth="true" use-transaction="false"
+            engine="java" location="org.ofbiz.common.CommonServices" invoke="getAllMetrics">
+        <description>
+            Get all metrics. Returns a List of Maps - one Map per metric. Each Map includes the following keys:
+            name, serviceRate, threshold, totalEvents. See org.ofbiz.base.metrics.Metrics.
+        </description>
+        <attribute name="metricsList" mode="OUT" type="java.util.List" optional="false" />
+    </service>
+
+    <service name="resetMetric" auth="true" use-transaction="false"
+         engine="java" location="org.ofbiz.common.CommonServices" invoke="resetMetric">
+        <description>Resets a metric. See org.ofbiz.base.metrics.Metrics.</description>
+        <attribute name="name" mode="IN" type="String" optional="false"/>
+    </service>
+
 </services>

Modified: ofbiz/trunk/framework/common/src/org/ofbiz/common/CommonServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/CommonServices.java?rev=1361722&r1=1361721&r2=1361722&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/src/org/ofbiz/common/CommonServices.java (original)
+++ ofbiz/trunk/framework/common/src/org/ofbiz/common/CommonServices.java Sun Jul 15 16:07:59 2012
@@ -18,11 +18,14 @@
  *******************************************************************************/
 package org.ofbiz.common;
 
+import static org.ofbiz.base.util.UtilGenerics.checkList;
+import static org.ofbiz.base.util.UtilGenerics.checkMap;
+
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.RandomAccessFile;
@@ -43,14 +46,14 @@ import javolution.util.FastMap;
 
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
+import org.ofbiz.base.metrics.Metrics;
+import org.ofbiz.base.metrics.MetricsFactory;
 import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.StringUtil;
 import org.ofbiz.base.util.UtilDateTime;
-import org.ofbiz.base.util.UtilValidate;
-
-import static org.ofbiz.base.util.UtilGenerics.checkList;
-import static org.ofbiz.base.util.UtilGenerics.checkMap;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
@@ -63,6 +66,7 @@ import org.ofbiz.service.ModelService;
 import org.ofbiz.service.ServiceUtil;
 import org.ofbiz.service.ServiceXaWrapper;
 import org.ofbiz.service.mail.MimeMessageWrapper;
+import org.owasp.esapi.errors.EncodingException;
 
 /**
  * Common Services
@@ -541,4 +545,35 @@ public class CommonServices {
         }
     }
 
+    public static Map<String, Object> getAllMetrics(DispatchContext dctx, Map<String, ?> context) {
+        List<Map<String, Object>> metricsMapList = FastList.newInstance();
+        List<Metrics> metricsList = MetricsFactory.getMetrics();
+        for (Metrics metrics : metricsList) {
+            Map<String, Object> metricsMap = FastMap.newInstance();
+            metricsMap.put("name", metrics.getName());
+            metricsMap.put("serviceRate", metrics.getServiceRate());
+            metricsMap.put("threshold", metrics.getThreshold());
+            metricsMap.put("totalEvents", metrics.getTotalEvents());
+            metricsMapList.add(metricsMap);
+        }
+        Map<String, Object> result = ServiceUtil.returnSuccess();
+        result.put("metricsList", metricsMapList);
+        return result;
+    }
+
+    public static Map<String, Object> resetMetric(DispatchContext dctx, Map<String, ?> context) {
+        String name = (String) context.get("name");
+        try {
+            name = StringUtil.defaultWebEncoder.decodeFromURL(name);
+        } catch (EncodingException e) {
+            return ServiceUtil.returnError("Exception thrown while decoding metric name \"" + name + "\"");
+        }
+        Metrics metric = MetricsFactory.getMetric(name);
+        if (metric != null) {
+            metric.reset();
+            return ServiceUtil.returnSuccess();
+
+        }
+        return ServiceUtil.returnError("Metric \"" + name + "\" not found.");
+    }
 }