You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2013/04/23 02:38:46 UTC
[12/31] git commit: Start work on exposing the collected metrics on a
dashboard view
Start work on exposing the collected metrics on a dashboard view
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/259d5e1a
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/259d5e1a
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/259d5e1a
Branch: refs/heads/master
Commit: 259d5e1af4bd3aa86d5907f923432ebd538ce3fc
Parents: e764c95
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Sat Apr 20 19:13:15 2013 -0400
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Sat Apr 20 19:13:15 2013 -0400
----------------------------------------------------------------------
.../java/org/apache/tapestry5/TapestryFilter.java | 2 +
.../apache/tapestry5/corelib/pages/AppMetrics.java | 48 +++++++++++++
.../apache/tapestry5/modules/DashboardModule.java | 1 +
.../tapestry5/modules/RootMetricsFilter.java | 52 +++++++++++++++
.../apache/tapestry5/modules/TapestryModule.java | 12 ++--
.../apache/tapestry5/modules/WebMetricsModule.java | 34 ++++++++++
.../apache/tapestry5/corelib/pages/AppMetrics.tml | 6 ++
.../services/metrics/MetricCollectorImpl.java | 49 ++++++++++++--
.../tapestry5/ioc/services/metrics/Metric.java | 30 +++++++-
9 files changed, 219 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java b/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
index 98fea52..ed9795f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/TapestryFilter.java
@@ -165,7 +165,9 @@ public class TapestryFilter implements Filter
(HttpServletResponse) response);
if (!handled)
+ {
chain.doFilter(request, response);
+ }
} finally
{
registry.cleanupThread();
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/AppMetrics.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/AppMetrics.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/AppMetrics.java
new file mode 100644
index 0000000..d57b75c
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/AppMetrics.java
@@ -0,0 +1,48 @@
+// Copyright 2013 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.corelib.pages;
+
+import org.apache.tapestry5.annotations.WhitelistAccessOnly;
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.services.metrics.Metric;
+import org.apache.tapestry5.ioc.services.metrics.MetricCollector;
+import org.apache.tapestry5.services.BeanModelSource;
+
+import java.util.List;
+
+@WhitelistAccessOnly
+/**
+ * Contributes to the {@link T5Dashboard} page, providing application metrics from the {@link org.apache.tapestry5.ioc.services.metrics.MetricCollector}.
+ */
+public class AppMetrics
+{
+ @Inject
+ MetricCollector collector;
+
+ @Inject
+ BeanModelSource beanModelSource;
+
+ @Inject
+ private Messages messages;
+
+ public final BeanModel<Metric> metricModel = beanModelSource.createDisplayModel(Metric.class, messages);
+
+ public List<Metric> getRootMetrics()
+ {
+ return collector.getRootMetrics();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
index 22abd21..9655457 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
@@ -32,6 +32,7 @@ public class DashboardModule
public static void defaultTabs(OrderedConfiguration<DashboardTab> configuration)
{
configuration.add("Pages", new DashboardTab("Pages", "core/PageCatalog"));
+ configuration.add("Metrics", new DashboardTab("Metrics", "core/AppMetrics"));
configuration.add("Services", new DashboardTab("Services", "core/ServiceStatus"));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-core/src/main/java/org/apache/tapestry5/modules/RootMetricsFilter.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/RootMetricsFilter.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/RootMetricsFilter.java
new file mode 100644
index 0000000..3d08f30
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/RootMetricsFilter.java
@@ -0,0 +1,52 @@
+// Copyright 2013 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.modules;
+
+import org.apache.tapestry5.ioc.services.metrics.Metric;
+import org.apache.tapestry5.ioc.services.metrics.MetricCollector;
+import org.apache.tapestry5.services.HttpServletRequestFilter;
+import org.apache.tapestry5.services.HttpServletRequestHandler;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class RootMetricsFilter implements HttpServletRequestFilter
+{
+
+ private final Metric count, requestTime;
+
+ public RootMetricsFilter(MetricCollector collector)
+ {
+ count = collector.createRootMetric("request-count", Metric.Type.TOTAL, Metric.Units.COUNTER);
+ requestTime = collector.createRootMetric("request-time", Metric.Type.RATE, Metric.Units.MILLISECONDS);
+ }
+
+ public boolean service(HttpServletRequest request, HttpServletResponse response, HttpServletRequestHandler handler) throws IOException
+ {
+ long start = System.currentTimeMillis();
+
+ boolean handled = handler.service(request, response);
+
+ // We don't count the unhandled requests
+
+ if (handled) {
+ count.increment();
+ requestTime.accumulate(System.currentTimeMillis() - start);
+ }
+
+ return handled;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index 0c7d291..4f567b9 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -108,7 +108,7 @@ import java.util.regex.Pattern;
*/
@Marker(Core.class)
@SubModule(
- {InternalModule.class, AssetsModule.class, PageLoadModule.class, JavaScriptModule.class, CompatibilityModule.class, DashboardModule.class})
+ {InternalModule.class, AssetsModule.class, PageLoadModule.class, JavaScriptModule.class, CompatibilityModule.class, DashboardModule.class, WebMetricsModule.class})
public final class TapestryModule
{
private final PipelineBuilder pipelineBuilder;
@@ -235,8 +235,10 @@ public final class TapestryModule
Response response = new ResponseImpl(servletRequest, servletResponse);
// TAP5-257: Make sure that the "initial guess" for request/response
- // is available, even if
- // some filter in the RequestHandler pipeline replaces them.
+ // is available, even ifsome filter in the RequestHandler pipeline replaces them.
+ // Which just goes to show that there should have been only one way to access the Request/Response:
+ // either functionally (via parameters) or global (via ReqeuestGlobals) but not both.
+ // That ship has sailed.
requestGlobals.storeRequestResponse(request, response);
@@ -428,8 +430,8 @@ public final class TapestryModule
@Contribute(ComponentClassResolver.class)
public static void provideCoreAndAppLibraries(Configuration<LibraryMapping> configuration,
- @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
- String appRootPackage)
+ @Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
+ String appRootPackage)
{
configuration.add(new LibraryMapping(InternalConstants.CORE_LIBRARY, "org.apache.tapestry5.corelib"));
configuration.add(new LibraryMapping("", appRootPackage));
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-core/src/main/java/org/apache/tapestry5/modules/WebMetricsModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/WebMetricsModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/WebMetricsModule.java
new file mode 100644
index 0000000..7778e94
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/WebMetricsModule.java
@@ -0,0 +1,34 @@
+// Copyright 2013 The Apache Software Foundation
+//
+// Licensed 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.
+
+package org.apache.tapestry5.modules;
+
+import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.ioc.annotations.Contribute;
+import org.apache.tapestry5.services.HttpServletRequestFilter;
+import org.apache.tapestry5.services.HttpServletRequestHandler;
+
+/**
+ * Responsible for contributing filters in various places, to handle metrics collection.
+ *
+ * @since 5.4
+ */
+public class WebMetricsModule
+{
+ @Contribute(HttpServletRequestHandler.class)
+ public static void addRootFilter(OrderedConfiguration<HttpServletRequestFilter> configuration)
+ {
+ configuration.addInstance("RootMetrics", RootMetricsFilter.class, "before:GZip");
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/AppMetrics.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/AppMetrics.tml b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/AppMetrics.tml
new file mode 100644
index 0000000..736698a
--- /dev/null
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/AppMetrics.tml
@@ -0,0 +1,6 @@
+<t:block id="content" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
+ >
+
+ <t:grid source="rootMetrics" model="metricModel"/>"
+
+</t:block>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/metrics/MetricCollectorImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/metrics/MetricCollectorImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/metrics/MetricCollectorImpl.java
index 65db295..14ff478 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/metrics/MetricCollectorImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/metrics/MetricCollectorImpl.java
@@ -1,8 +1,23 @@
+// Copyright 2013 The Apache Software Foundation
+//
+// Licensed 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.
+
package org.apache.tapestry5.ioc.internal.services.metrics;
import com.google.common.util.concurrent.AtomicDouble;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.ioc.annotations.PostInjection;
+import org.apache.tapestry5.ioc.annotations.PreventServiceDecoration;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
@@ -13,15 +28,19 @@ import org.apache.tapestry5.ioc.services.metrics.Metric;
import org.apache.tapestry5.ioc.services.metrics.MetricCollector;
import org.apache.tapestry5.ioc.services.metrics.MetricsSymbols;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
+import org.rrd4j.ConsolFun;
+import org.rrd4j.DsType;
import org.rrd4j.core.*;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+@PreventServiceDecoration
public class MetricCollectorImpl extends LockSupport implements MetricCollector, Runnable
{
private final boolean inMemory;
@@ -38,7 +57,7 @@ public class MetricCollectorImpl extends LockSupport implements MetricCollector,
public static final String DS_NAME = "data";
- private class MetricImpl extends LockSupport implements Metric, Comparable<MetricImpl>, Runnable
+ public class MetricImpl extends LockSupport implements Metric, Comparable<MetricImpl>, Runnable
{
private final MetricImpl parent;
@@ -82,6 +101,8 @@ public class MetricCollectorImpl extends LockSupport implements MetricCollector,
path,
ExceptionUtils.toMessage(ex)), ex);
}
+
+ updates.add(this);
}
private RrdDb createDb() throws IOException
@@ -110,7 +131,13 @@ public class MetricCollectorImpl extends LockSupport implements MetricCollector,
private RrdDef createDef(String filePath)
{
- return null;
+ RrdDef result = new RrdDef(filePath, HEARTBEAT);
+
+ result.addDatasource(DS_NAME, DsType.COUNTER, HEARTBEAT, 0, Double.NaN);
+ // One archive: average for each new data point, 10 minutes worth.
+ result.addArchive(new ArcDef(ConsolFun.AVERAGE, .5, 1, 60));
+
+ return result;
}
public int compareTo(MetricImpl o)
@@ -175,16 +202,16 @@ public class MetricCollectorImpl extends LockSupport implements MetricCollector,
public void increment()
{
- store(1);
+ accumulate(1);
}
- public void store(double value)
+ public void accumulate(double value)
{
accumulator.addAndGet(value);
if (parent != null)
{
- parent.store(value);
+ parent.accumulate(value);
}
}
@@ -201,11 +228,21 @@ public class MetricCollectorImpl extends LockSupport implements MetricCollector,
}
}
- public void run()
+ public Date getLastUpdateTime()
{
try
{
+ return new Date(db.getLastUpdateTime());
+ } catch (IOException ex)
+ {
+ return null;
+ }
+ }
+ public void run()
+ {
+ try
+ {
db.createSample().setValue(DS_NAME, accumulator.getAndSet(0)).update();
} catch (IOException ex)
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/259d5e1a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/metrics/Metric.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/metrics/Metric.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/metrics/Metric.java
index 83f82da..71cda59 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/metrics/Metric.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/metrics/Metric.java
@@ -1,5 +1,20 @@
+// Copyright 2013 The Apache Software Foundation
+//
+// Licensed 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.
+
package org.apache.tapestry5.ioc.services.metrics;
+import java.util.Date;
import java.util.List;
/**
@@ -64,21 +79,28 @@ public interface Metric
Units getUnits();
/**
- * Stores a value of 1; useful when the metric's type is {@link Units#COUNTER}.
+ * Accumulates a value of 1; useful when the metric's type is {@link Units#COUNTER}.
*/
void increment();
/**
- * Stores a value into the current time interval. This may be called multiple times during
- * a time interval, and the values will accumulate. In addition, {@link #store(double)}
+ * Adds the provided value to the current time interval's value. This may be called multiple times during
+ * a time interval, and the values will accumulate. In addition, {@link #accumulate(double)}
* propagates the value up to the parent metrics, if any, all the way up to the root metric.
*
* @param value
*/
- void store(double value);
+ void accumulate(double value);
/**
* Returns the children of this metric, sorted by name.
*/
List<Metric> getChildren();
+
+ /**
+ * Returns the last time the archive was updated (this happens a regular intervals called heartbeats).
+ *
+ * @return archive update time, or null if there is an exception accessing the time
+ */
+ Date getLastUpdateTime();
}