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> </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.");
+ }
}