From 7ef05feadde89b2554576ee50f9ce30d56a552ae Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Thu, 10 Mar 2016 11:40:39 +0100 Subject: [PATCH 01/16] Wicket Metrics --- README | 2 + pom.xml | 19 +++++ wicket-metrics/pom.xml | 45 +++++++++++ .../apache/wicket/metrics/WicketMetrics.java | 76 +++++++++++++++++++ .../metrics/aspects/ApplicationAspect.java | 24 ++++++ .../wicket/metrics/aspects/PageAspect.java | 25 ++++++ .../src/main/resources/META-INF/aop.xml | 8 ++ 7 files changed, 199 insertions(+) create mode 100644 wicket-metrics/pom.xml create mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java create mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java create mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java create mode 100644 wicket-metrics/src/main/resources/META-INF/aop.xml diff --git a/README b/README index 436937c2f18..45663f78c25 100644 --- a/README +++ b/README @@ -75,6 +75,7 @@ You will find the source code here: |-- wicket-spring |-- wicket-util |-- wicket-user-guide + |-- wicket-metrics `-- wicket-velocity @@ -117,6 +118,7 @@ Here is a list of projects in this distribution and what they do. - wicket-eclipse-settings: specifies Eclipse settings for a uniform development environment. Most notably the formatting rules; - wicket-user-guide: the user guide of wicket + - wicket-metrics: collects data of a running wicket application Getting started --------------- diff --git a/pom.xml b/pom.xml index ff784f4058a..f4f84a1301e 100644 --- a/pom.xml +++ b/pom.xml @@ -114,6 +114,7 @@ wicket-bean-validation wicket-cdi-1.1 wicket-user-guide + wicket-metrics @@ -141,6 +142,8 @@ 2.2 2.2.4 + 1.8.8 + 3.1.2 @@ -402,6 +405,12 @@ 8.0.0-SNAPSHOT jar + + org.apache.wicket + wicket-metrics + 8.0.0-SNAPSHOT + jar + org.apache.wicket.experimental.wicket7 wicket-atmosphere @@ -536,6 +545,16 @@ + + org.aspectj + aspectjrt + ${aspectj.version} + + + io.dropwizard.metrics + metrics-core + ${metrics.version} + diff --git a/wicket-metrics/pom.xml b/wicket-metrics/pom.xml new file mode 100644 index 00000000000..4ed79f1a015 --- /dev/null +++ b/wicket-metrics/pom.xml @@ -0,0 +1,45 @@ + + + + 4.0.0 + + org.apache.wicket + wicket-parent + 8.0.0-SNAPSHOT + ../pom.xml + + wicket-metrics + jar + Wicket Metrics + + Wicket’s implementation to show metric information + about web applications build on the web framework. + + + + org.aspectj + aspectjrt + provided + + + io.dropwizard.metrics + metrics-core + + + diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java new file mode 100644 index 00000000000..26314f08ffb --- /dev/null +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java @@ -0,0 +1,76 @@ +package org.apache.wicket.metrics; + +import com.codahale.metrics.JmxReporter; +import com.codahale.metrics.MetricRegistry; + +/** + * Base aspect provides access to the metric registry + * + * @author Tobias Soloschenko + * + */ +public class WicketMetrics +{ + + private static MetricRegistry metricRegistry; + + private static boolean enabled = true; + + private static final String JMX_PREFIX = "ApacheWicket/"; + + /** + * Gets the metric registry + * + * @return the metric registry + */ + public static MetricRegistry getMetricRegistry() + { + if (metricRegistry == null) + { + metricRegistry = new MetricRegistry(); + } + return metricRegistry; + } + + + /** + * Marks the meter with the given name + * + * @param name + * the name of the meter to be marked + */ + protected void mark(String name) + { + if (WicketMetrics.enabled) + { + getMetricRegistry().meter(JMX_PREFIX + name).mark(); + } + } + + /** + * Starts the jmx reporter + */ + public static void startJmxReporter() + { + JmxReporter.forRegistry(getMetricRegistry()).build().start(); + } + + /** + * Stops the jmx reporter + */ + public static void stopJmxReporter() + { + JmxReporter.forRegistry(getMetricRegistry()).build().stop(); + } + + /** + * If the metrics should be enabled + * + * @param enabled + * if the metrics should be enabled + */ + public static void setEnabled(boolean enabled) + { + WicketMetrics.enabled = enabled; + } +} diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java new file mode 100644 index 00000000000..2f56e5032de --- /dev/null +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java @@ -0,0 +1,24 @@ +package org.apache.wicket.metrics.aspects; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Aspect to handle basic web application information + * + * @author Tobias Soloschenko + */ +@Aspect +public class ApplicationAspect extends WicketMetrics +{ + + /** + * Collects data how often a request has been made against the web app + */ + @Before("call(* org.apache.wicket.protocol.http.WicketFilter.processRequest(..))") + public void beforeRequestProcessed() + { + mark("core/application/request"); + } +} diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java new file mode 100644 index 00000000000..4e85a367b8a --- /dev/null +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java @@ -0,0 +1,25 @@ +package org.apache.wicket.metrics.aspects; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Collects basic information about pages + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class PageAspect extends WicketMetrics +{ + + /** + * Collects data how often a pages has been rendered + */ + @Before("target(org.apache.wicket.Page+) && call(* onRender(..))") + public void beforeRequestProcessed() + { + mark("core/page/render"); + } +} diff --git a/wicket-metrics/src/main/resources/META-INF/aop.xml b/wicket-metrics/src/main/resources/META-INF/aop.xml new file mode 100644 index 00000000000..ba00763256b --- /dev/null +++ b/wicket-metrics/src/main/resources/META-INF/aop.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From 399c08eb14241588f1c98a4d3614e1edbfd86037 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Thu, 10 Mar 2016 13:27:22 +0100 Subject: [PATCH 02/16] Wicket Metrics - Fixed errors on startup --- wicket-metrics/src/main/resources/META-INF/aop.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wicket-metrics/src/main/resources/META-INF/aop.xml b/wicket-metrics/src/main/resources/META-INF/aop.xml index ba00763256b..e9c48d15b79 100644 --- a/wicket-metrics/src/main/resources/META-INF/aop.xml +++ b/wicket-metrics/src/main/resources/META-INF/aop.xml @@ -1,6 +1,8 @@ - + + + From 0f0f6b0e6bcc93f3655b8825ad02e95c95145a03 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Thu, 10 Mar 2016 14:03:19 +0100 Subject: [PATCH 03/16] Wicket Metrics - Time measurement / license header --- .../apache/wicket/metrics/WicketMetrics.java | 54 ++++++++++++++++++- .../metrics/aspects/ApplicationAspect.java | 45 ++++++++++++++-- .../wicket/metrics/aspects/PageAspect.java | 16 ++++++ 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java index 26314f08ffb..055b07f34ba 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java @@ -1,7 +1,24 @@ +/* + * 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. + */ package org.apache.wicket.metrics; import com.codahale.metrics.JmxReporter; import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer.Context; /** * Base aspect provides access to the metric registry @@ -16,7 +33,7 @@ public class WicketMetrics private static boolean enabled = true; - private static final String JMX_PREFIX = "ApacheWicket/"; + private static final String PREFIX = "ApacheWicket/"; /** * Gets the metric registry @@ -43,7 +60,40 @@ protected void mark(String name) { if (WicketMetrics.enabled) { - getMetricRegistry().meter(JMX_PREFIX + name).mark(); + getMetricRegistry().meter(PREFIX + name).mark(); + } + } + + /** + * Gets a timer context + * + * @param name + * the name of the timer context + * @return the timer context + */ + protected Context context(String name) + { + if (WicketMetrics.enabled) + { + return getMetricRegistry().timer(PREFIX + name).time(); + } + else + { + return null; + } + } + + /** + * Stops the contex quietly + * + * @param context + * the context to stop + */ + public void stopQuietly(Context context) + { + if (context != null) + { + context.stop(); } } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java index 2f56e5032de..10d51a8f7bb 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java @@ -1,8 +1,27 @@ +/* + * 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. + */ package org.apache.wicket.metrics.aspects; import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; + +import com.codahale.metrics.Timer.Context; /** * Aspect to handle basic web application information @@ -14,11 +33,27 @@ public class ApplicationAspect extends WicketMetrics { /** - * Collects data how often a request has been made against the web app + * Collects data how often a request has been made against the webapp and counts the time how + * long the request remains + * + * @param joinPoint + * the joinPoint to be proceed + * @return returns the boolean of the processRequest method + * + * @throws Throwable + * might occure while invoking process request */ - @Before("call(* org.apache.wicket.protocol.http.WicketFilter.processRequest(..))") - public void beforeRequestProcessed() + @Around("execution(* org.apache.wicket.protocol.http.WicketFilter.processRequest(..))") + public Object aroundRequestProcessed(ProceedingJoinPoint joinPoint) throws Throwable { - mark("core/application/request"); + Context context = context("core/application/request"); + try + { + return joinPoint.proceed(); + } + finally + { + stopQuietly(context); + } } } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java index 4e85a367b8a..1f03d3542d3 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java @@ -1,3 +1,19 @@ +/* + * 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. + */ package org.apache.wicket.metrics.aspects; import org.apache.wicket.metrics.WicketMetrics; From 756612158e391d43155a3b1373a29bf5a789dcce Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Thu, 10 Mar 2016 14:12:21 +0100 Subject: [PATCH 04/16] Wicket Metrics - Simplified time measurement --- .../apache/wicket/metrics/WicketMetrics.java | 30 +++++++++++++++++-- .../metrics/aspects/ApplicationAspect.java | 12 +------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java index 055b07f34ba..9c4eb59e62e 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java @@ -16,6 +16,8 @@ */ package org.apache.wicket.metrics; +import org.aspectj.lang.ProceedingJoinPoint; + import com.codahale.metrics.JmxReporter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer.Context; @@ -56,7 +58,7 @@ public static MetricRegistry getMetricRegistry() * @param name * the name of the meter to be marked */ - protected void mark(String name) + public void mark(String name) { if (WicketMetrics.enabled) { @@ -71,7 +73,7 @@ protected void mark(String name) * the name of the timer context * @return the timer context */ - protected Context context(String name) + public Context context(String name) { if (WicketMetrics.enabled) { @@ -97,6 +99,30 @@ public void stopQuietly(Context context) } } + /** + * Simply measure the time for a {@literal @}around + * + * @param name + * the name of the timer context + * @param joinPoint + * the joinPoint to be proceed + * @return the value of the join point + * @throws Throwable + * if there is an exception while execution + */ + public Object measureTime(String name, ProceedingJoinPoint joinPoint) throws Throwable + { + Context context = context(name); + try + { + return joinPoint.proceed(); + } + finally + { + stopQuietly(context); + } + } + /** * Starts the jmx reporter */ diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java index 10d51a8f7bb..45fe51dd898 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java @@ -21,8 +21,6 @@ import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import com.codahale.metrics.Timer.Context; - /** * Aspect to handle basic web application information * @@ -46,14 +44,6 @@ public class ApplicationAspect extends WicketMetrics @Around("execution(* org.apache.wicket.protocol.http.WicketFilter.processRequest(..))") public Object aroundRequestProcessed(ProceedingJoinPoint joinPoint) throws Throwable { - Context context = context("core/application/request"); - try - { - return joinPoint.proceed(); - } - finally - { - stopQuietly(context); - } + return measureTime("core/application/request", joinPoint); } } From f7769716545f77aff6ce47cb7b89494d80cc5aa7 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Thu, 10 Mar 2016 15:12:33 +0100 Subject: [PATCH 05/16] Wicket Metrics - Component create / render / ResourceReference create --- .../metrics/aspects/ApplicationAspect.java | 2 +- .../metrics/aspects/ComponentAspect.java | 72 +++++++++++++++++++ ...pect.java => ResourceReferenceAspect.java} | 20 ++++-- .../src/main/resources/META-INF/aop.xml | 3 +- 4 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java rename wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/{PageAspect.java => ResourceReferenceAspect.java} (60%) diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java index 45fe51dd898..a2ee0ddebd3 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java @@ -39,7 +39,7 @@ public class ApplicationAspect extends WicketMetrics * @return returns the boolean of the processRequest method * * @throws Throwable - * might occure while invoking process request + * might occur while invoking process request */ @Around("execution(* org.apache.wicket.protocol.http.WicketFilter.processRequest(..))") public Object aroundRequestProcessed(ProceedingJoinPoint joinPoint) throws Throwable diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java new file mode 100644 index 00000000000..37d4e8e4c0c --- /dev/null +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java @@ -0,0 +1,72 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Gets information how often different components are rendered + * + * @author Tobias Soloschenko + */ +@Aspect +public class ComponentAspect extends WicketMetrics +{ + + /** + * Collects data how often components are rendered + * + * @param joinPoint + * @return the object returned from the joinPoint + * @throws Throwable + */ + @Around("target(org.apache.wicket.Component+) && execution(* onRender(..))") + public Object aroundRender(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/component/render/" + joinPoint.getTarget().getClass().getName(), + joinPoint); + } + + /** + * Collects data how often components are created + * + * @param joinPoint + * the join point (component) which is created + * @return the object returned from the joinPoint + * @throws Throwable + * might occur while invoking process request + */ + @Around("execution(org.apache.wicket.Component.new(..))") + public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable + { + mark("core/component/create/" + joinPoint.getTarget().getClass().getName()); + return joinPoint.proceed(); + } + + /** + * Collects data how often components redirect to another page + */ + @Before("call(* org.apache.wicket.Component.setResponsePage(..))") + public void aroundResponsePage() + { + mark("core/component/redirect"); + } +} diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java similarity index 60% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java rename to wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java index 1f03d3542d3..1430ee7108a 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/PageAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java @@ -17,8 +17,9 @@ package org.apache.wicket.metrics.aspects; import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; /** * Collects basic information about pages @@ -27,15 +28,22 @@ * */ @Aspect -public class PageAspect extends WicketMetrics +public class ResourceReferenceAspect extends WicketMetrics { /** - * Collects data how often a pages has been rendered + * Collects data how often components are created + * + * @param joinPoint + * the join point (component) which is created + * @return the object returned from the joinPoint + * @throws Throwable + * might occur while invoking process request */ - @Before("target(org.apache.wicket.Page+) && call(* onRender(..))") - public void beforeRequestProcessed() + @Around("execution(org.apache.wicket.request.resource.ResourceReference.new(..))") + public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable { - mark("core/page/render"); + mark("core/resourceReference/create/" + joinPoint.getTarget().getClass().getName()); + return joinPoint.proceed(); } } diff --git a/wicket-metrics/src/main/resources/META-INF/aop.xml b/wicket-metrics/src/main/resources/META-INF/aop.xml index e9c48d15b79..eedd3978bb8 100644 --- a/wicket-metrics/src/main/resources/META-INF/aop.xml +++ b/wicket-metrics/src/main/resources/META-INF/aop.xml @@ -4,7 +4,8 @@ + - + \ No newline at end of file From 5cb7b27b4dc1bf295737fd3ecb8b3547144a1651 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Thu, 10 Mar 2016 15:16:38 +0100 Subject: [PATCH 06/16] Wicket Metrics - Switched create to time measure --- .../org/apache/wicket/metrics/aspects/ComponentAspect.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java index 37d4e8e4c0c..65df92b88dc 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java @@ -57,8 +57,8 @@ public Object aroundRender(ProceedingJoinPoint joinPoint) throws Throwable @Around("execution(org.apache.wicket.Component.new(..))") public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable { - mark("core/component/create/" + joinPoint.getTarget().getClass().getName()); - return joinPoint.proceed(); + return measureTime("core/component/create/" + joinPoint.getTarget().getClass().getName(), + joinPoint); } /** From c50e3040adc561cc5ac3b57cb11e4efd2766e86b Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Fri, 11 Mar 2016 19:29:30 +0100 Subject: [PATCH 07/16] Wicket Metrics - Guide / Added several new measurement aspects --- .../apache/wicket/metrics/WicketMetrics.java | 82 +++++++++++-------- .../metrics/aspects/BehaviorAspect.java | 47 +++++++++++ .../metrics/aspects/ComponentAspect.java | 72 +++++++++++++--- .../IPartialPageRequestHandlerAspect.java | 68 +++++++++++++++ .../aspects/ResourceReferenceAspect.java | 11 ++- ...ionAspect.java => WicketFilterAspect.java} | 2 +- .../src/main/resources/META-INF/aop.xml | 4 +- .../src/docs/guide/monitoring.gdoc | 7 ++ .../docs/guide/monitoring/monitoring_1.gdoc | 19 +++++ .../docs/guide/monitoring/monitoring_2.gdoc | 66 +++++++++++++++ wicket-user-guide/src/docs/guide/toc.yml | 4 + 11 files changed, 327 insertions(+), 55 deletions(-) create mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java create mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java rename wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/{ApplicationAspect.java => WicketFilterAspect.java} (96%) create mode 100644 wicket-user-guide/src/docs/guide/monitoring.gdoc create mode 100644 wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc create mode 100644 wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java index 9c4eb59e62e..52ca2611ae7 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java @@ -51,38 +51,59 @@ public static MetricRegistry getMetricRegistry() return metricRegistry; } - /** - * Marks the meter with the given name + * Simply measure the time for a {@literal @}around * * @param name - * the name of the meter to be marked + * the name of the timer context + * @param joinPoint + * the joinPoint to be proceed + * @return the value of the join point + * @throws Throwable + * if there is an exception while execution */ - public void mark(String name) + public Object measureTime(String name, ProceedingJoinPoint joinPoint) throws Throwable { if (WicketMetrics.enabled) { - getMetricRegistry().meter(PREFIX + name).mark(); + Context context = getMetricRegistry().timer(PREFIX + name + renderClassName(joinPoint)) + .time(); + try + { + return joinPoint.proceed(); + } + finally + { + stopQuietly(context); + } + } + else + { + return joinPoint.proceed(); } } /** - * Gets a timer context + * Marks the meter with the given name * * @param name - * the name of the timer context - * @return the timer context + * the name of the meter to be marked + * @param joinPoint + * the join point + * @return the result of the proceeded join point + * @throws Throwable */ - public Context context(String name) + public Object mark(String name, ProceedingJoinPoint joinPoint) throws Throwable { if (WicketMetrics.enabled) { - return getMetricRegistry().timer(PREFIX + name).time(); + getMetricRegistry().meter(PREFIX + name + renderClassName(joinPoint)).mark(); } - else + if (joinPoint != null) { - return null; + return joinPoint.proceed(); } + return null; } /** @@ -99,30 +120,6 @@ public void stopQuietly(Context context) } } - /** - * Simply measure the time for a {@literal @}around - * - * @param name - * the name of the timer context - * @param joinPoint - * the joinPoint to be proceed - * @return the value of the join point - * @throws Throwable - * if there is an exception while execution - */ - public Object measureTime(String name, ProceedingJoinPoint joinPoint) throws Throwable - { - Context context = context(name); - try - { - return joinPoint.proceed(); - } - finally - { - stopQuietly(context); - } - } - /** * Starts the jmx reporter */ @@ -149,4 +146,17 @@ public static void setEnabled(boolean enabled) { WicketMetrics.enabled = enabled; } + + /** + * Renders the class name of the given join point + * + * @param joinPoint + * the join point to get the class of + * @return the class name representation + */ + public String renderClassName(ProceedingJoinPoint joinPoint) + { + return joinPoint != null + ? "/" + joinPoint.getTarget().getClass().getName().replace('.', '_') : ""; + } } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java new file mode 100644 index 00000000000..94cc60c8f0d --- /dev/null +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Measures everything about behaviors + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class BehaviorAspect extends WicketMetrics +{ + /** + * Collects data how often a behavior is created + * + * @param joinPoint + * the join point (behavior) which is created + * @return the result of constructor + * @throws Throwable + * might occur while creating a new behavior + */ + @Around("execution(org.apache.wicket.behavior.Behavior.new(..))") + public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable + { + return mark("core/behavior/create", joinPoint); + } +} diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java index 65df92b88dc..e046a638265 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java @@ -35,14 +35,15 @@ public class ComponentAspect extends WicketMetrics * Collects data how often components are rendered * * @param joinPoint - * @return the object returned from the joinPoint + * the join point (component) which is rendered + * @return the object returned from the join point * @throws Throwable + * might occur while onRender */ - @Around("target(org.apache.wicket.Component+) && execution(* onRender(..))") - public Object aroundRender(ProceedingJoinPoint joinPoint) throws Throwable + @Around("execution(* org.apache.wicket.Component.onRender(..))") + public Object aroundOnRender(ProceedingJoinPoint joinPoint) throws Throwable { - return measureTime("core/component/render/" + joinPoint.getTarget().getClass().getName(), - joinPoint); + return measureTime("core/component/render", joinPoint); } /** @@ -50,23 +51,72 @@ public Object aroundRender(ProceedingJoinPoint joinPoint) throws Throwable * * @param joinPoint * the join point (component) which is created - * @return the object returned from the joinPoint + * @return the object returned from the join point * @throws Throwable - * might occur while invoking process request + * might occur while constructing a new component */ @Around("execution(org.apache.wicket.Component.new(..))") public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable { - return measureTime("core/component/create/" + joinPoint.getTarget().getClass().getName(), - joinPoint); + return measureTime("core/component/create", joinPoint); + } + + /** + * Collects data how often components calls onConfigure + * + * @param joinPoint + * the join point (component) which is configured + * @return the object returned from the join point + * + * @throws Throwable + * might occur while invoking onConfigure + */ + @Around("execution(* org.apache.wicket.Component.onConfigure(..))") + public Object aroundOnConfigure(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/component/configure", joinPoint); + } + + /** + * Collects data how often components calls onInitialize + * + * @param joinPoint + * the join point (component) which is initialized + * @return the object returned from the join point + * + * @throws Throwable + * might occur while invoking onInitialize + */ + @Around("execution(* org.apache.wicket.Component.onInitialize(..))") + public Object aroundOnInitialize(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/component/initialize", joinPoint); + } + + /** + * Collects data how often components calls onDetach + * + * @param joinPoint + * the join point (component) which is calling detach + * @return the object returned from the join point + * @throws Throwable + * might occur while invoking onDetach + */ + @Around("execution(* org.apache.wicket.Component.onDetach(..))") + public Object arroundOnDetach(ProceedingJoinPoint joinPoint) throws Throwable + { + return mark("core/component/detach", joinPoint); } /** * Collects data how often components redirect to another page + * + * @throws Throwable + * might occur while invoking setResponsePage */ @Before("call(* org.apache.wicket.Component.setResponsePage(..))") - public void aroundResponsePage() + public void beforeResponsePage() throws Throwable { - mark("core/component/redirect"); + mark("core/component/redirect", null); } } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java new file mode 100644 index 00000000000..24cb2a137fe --- /dev/null +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java @@ -0,0 +1,68 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Aspect which checks ajax request targets + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class IPartialPageRequestHandlerAspect extends WicketMetrics +{ + /** + * Collects data how often components calls add + * + * @throws Throwable + * might occur while invoking add + */ + @Before("call(* org.apache.wicket.core.request.handler.IPartialPageRequestHandler.add(..))") + public void beforeAdd() throws Throwable + { + mark("core/ajax/add", null); + } + + /** + * Collects data how often components calls prependJavaScript + * + * @throws Throwable + * might occur while invoking prependJavaScript + */ + @Before("call(* org.apache.wicket.core.request.handler.IPartialPageRequestHandler.prependJavaScript(..))") + public void beforePrependJavaScript() throws Throwable + { + mark("core/ajax/prependJavaScript", null); + } + + /** + * Collects data how often components calls appendJavaScript + * + * @throws Throwable + * might occur while invoking appendJavaScript + */ + @Before("call(* org.apache.wicket.core.request.handler.IPartialPageRequestHandler.appendJavaScript(..))") + public void beforeAppendJavaScript() throws Throwable + { + mark("core/ajax/appendJavaScript", null); + } + +} diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java index 1430ee7108a..cd11e5486fc 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java @@ -32,18 +32,17 @@ public class ResourceReferenceAspect extends WicketMetrics { /** - * Collects data how often components are created + * Collects data how often a resource reference is created * * @param joinPoint - * the join point (component) which is created - * @return the object returned from the joinPoint + * the join point (resource reference) which is created + * @return the result of constructor * @throws Throwable - * might occur while invoking process request + * might occur while creating a new resource reference */ @Around("execution(org.apache.wicket.request.resource.ResourceReference.new(..))") public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable { - mark("core/resourceReference/create/" + joinPoint.getTarget().getClass().getName()); - return joinPoint.proceed(); + return mark("core/resource/create", joinPoint); } } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java similarity index 96% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java rename to wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java index a2ee0ddebd3..bb31b744bcf 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ApplicationAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java @@ -27,7 +27,7 @@ * @author Tobias Soloschenko */ @Aspect -public class ApplicationAspect extends WicketMetrics +public class WicketFilterAspect extends WicketMetrics { /** diff --git a/wicket-metrics/src/main/resources/META-INF/aop.xml b/wicket-metrics/src/main/resources/META-INF/aop.xml index eedd3978bb8..0d8ee24e583 100644 --- a/wicket-metrics/src/main/resources/META-INF/aop.xml +++ b/wicket-metrics/src/main/resources/META-INF/aop.xml @@ -4,8 +4,10 @@ + + - + \ No newline at end of file diff --git a/wicket-user-guide/src/docs/guide/monitoring.gdoc b/wicket-user-guide/src/docs/guide/monitoring.gdoc new file mode 100644 index 00000000000..413f51015f3 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/monitoring.gdoc @@ -0,0 +1,7 @@ +The wicket-metrics module is available since Wicket 8.0.0 and contains a life measurement implementation to collect data of applications and visualize it. + +You can see how many request your application served, how often components are created, initalized, configured or their detach method has been invoked and a lot of other additional information. + +The module itself is using "Metrics of dropwizard":https://dropwizard.github.io/metrics/3.1.0/ and "AspectJ":https://eclipse.org/aspectj/ so that if you turn of the measurement it has no longer any effect + +to your web application. \ No newline at end of file diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc new file mode 100644 index 00000000000..608b9c24572 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc @@ -0,0 +1,19 @@ +This is a little example how to setup wicket-metrics within a tomcat. + +(1) Add the maven dependency to your project +{code} + + org.apache.wicket + wicket-metrics + ${wicket.version} + +{code} + +(2) Just drop the jars of aspectjrt and aspectjweaver into the tomcat lib folder - you can download it from here "http://mvnrepository.com/artifact/org.aspectj/":http://mvnrepository.com/artifact/org.aspectj/ (the metrics dependency is shipped with the project) + +(3) Add the java agent to the jvm start options of your tomcat: -javaagent:/pathToServer/lib/aspectjweaver-x.x.x.jar + +(4) To enable the JMX measurement write the following line into your init method of your Application (Now you are able to connect with jvisualvm to your server and have a look at the data): +{code} +WicketMetrics.startJmxReporter(); +{code} \ No newline at end of file diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc new file mode 100644 index 00000000000..4ecf64e6bc0 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc @@ -0,0 +1,66 @@ +To visualize the metrics with Graphite a little additional configuration is required: + +(1) Add the additional maven dependency to your project: +{code} + + io.dropwizard.metrics + metrics-graphite + ${metrics.graphite.version} + +{code} + +(2) Add the following code to your Application's init method: +{code} +final Graphite graphite = new Graphite(new InetSocketAddress("127.0.0.1", 2003)); +final GraphiteReporter reporter = GraphiteReporter.forRegistry(WicketMetrics.getMetricRegistry()) + .prefixedWith("WebApplications") + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .filter(MetricFilter.ALL) + .build(graphite); +reporter.start(1, TimeUnit.SECONDS); +{code} + +(3) Install and setup graphite on your system. Example installation for mac (beware that this is only a quickstart setup!): + +- (1) Install homebrew: "brew":http://brew.sh/ + +- (2) Install "Git":https://git-scm.com/ + +- (3) brew install python + +- (4) brew install cairo + +- (5) brew install py2cairo + +- (6) pip install Django==1.5 + +- (7) pip install "django-tagging<0.4" + +- (8) sudo pip install carbon + +- (9) pip install whisper + +- (10) sudo pip install graphite-web + +- (11) sudo pip install Twisted==11.1.0 + +- (12) sudo chown -R :staff /opt/graphite + +- (13) cp /opt/graphite/conf/carbon.conf{.example,} + +- (14) cp /opt/graphite/conf/storage-schemas.conf{.example,} + +- (15) cd /opt/graphite/webapp/graphite + +- (16) cp local_settings.py{.example,} + +- (17) python manage.py syncdb + +- (18) python /opt/graphite/bin/carbon-cache.py start + +- (19) python /opt/graphite/bin/run-graphite-devel-server.py /opt/graphite + +- (20) Go to http://localhost:8080 + +(4) Now start your tomcat server configured like mentioned in the previous chapter. \ No newline at end of file diff --git a/wicket-user-guide/src/docs/guide/toc.yml b/wicket-user-guide/src/docs/guide/toc.yml index 520d57be859..f9be35edd1b 100644 --- a/wicket-user-guide/src/docs/guide/toc.yml +++ b/wicket-user-guide/src/docs/guide/toc.yml @@ -223,6 +223,10 @@ wicketstuff: wicketstuff_5: Module wicketstuff-inmethod-grid wicketstuff_6: Module wicketstuff-rest-annotations wicketstuff_7: Module stateless +monitoring: + title: Wicket Metrics Monitoring + monitoring_1: Example setup + monitoring_2: Visualization with Graphite redirects: title: Lost In Redirection With Apache Wicket (Appendix) contributing: From b8ebc68a06e0c38ebc87a17cd4ae174d3a2c90b8 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Sat, 12 Mar 2016 09:05:28 +0100 Subject: [PATCH 08/16] Wicket Metrics - Screenshot / further guide improvements --- .../docs/guide/monitoring/monitoring_2.gdoc | 6 +++++- .../docs/guide/monitoring/monitoring_3.gdoc | 18 ++++++++++++++++++ wicket-user-guide/src/docs/guide/toc.yml | 1 + .../src/docs/img/wicket_metrics_graphite.png | Bin 0 -> 97808 bytes 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc create mode 100644 wicket-user-guide/src/docs/img/wicket_metrics_graphite.png diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc index 4ecf64e6bc0..b77e7993c95 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc @@ -63,4 +63,8 @@ reporter.start(1, TimeUnit.SECONDS); - (20) Go to http://localhost:8080 -(4) Now start your tomcat server configured like mentioned in the previous chapter. \ No newline at end of file +* (18) and (19) have to be executed if the mac has been restarted + +(4) Now start your tomcat server configured like mentioned in the previous chapter. + +!wicket_metrics_graphite.png! \ No newline at end of file diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc new file mode 100644 index 00000000000..6760b6f9c09 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc @@ -0,0 +1,18 @@ +The data which is going to be measured depends on the wicket-metrics implementation. So it doesn't make any sense to collect time data + +about setRepsonsePage, but it does for the constructor of components, to see if a component needs a long time to be created. You can + +get the information about which data has been collected from out of the mbeans. + +Here are some information about them: + +* max - the maximal time for a task (created, initialized, etc.) + +* min - the minimal time for a task (created, initialized, etc.) + +* count - how often something happend (request count) + +The structure is separated in the way that under core there are the kind of components measured and below that the type of operation + +(created, initialized, detached). In this category every component is listed dynamically. + diff --git a/wicket-user-guide/src/docs/guide/toc.yml b/wicket-user-guide/src/docs/guide/toc.yml index f9be35edd1b..dab016ea6be 100644 --- a/wicket-user-guide/src/docs/guide/toc.yml +++ b/wicket-user-guide/src/docs/guide/toc.yml @@ -227,6 +227,7 @@ monitoring: title: Wicket Metrics Monitoring monitoring_1: Example setup monitoring_2: Visualization with Graphite + monitoring_3: Measured data redirects: title: Lost In Redirection With Apache Wicket (Appendix) contributing: diff --git a/wicket-user-guide/src/docs/img/wicket_metrics_graphite.png b/wicket-user-guide/src/docs/img/wicket_metrics_graphite.png new file mode 100644 index 0000000000000000000000000000000000000000..c10ab42b436d7eae65823a4331244ff819b25c47 GIT binary patch literal 97808 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�VfQ!Y)<$D`ey&f1#os=e0;w8`1t&& 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 Dhozo{ literal 0 HcmV?d00001 From a7f6edeb3debd748ba613d4400ae348259d37568 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Sun, 13 Mar 2016 22:35:30 +0100 Subject: [PATCH 09/16] Wicket Metrics - Updated API due to review --- wicket-metrics/pom.xml | 4 + .../apache/wicket/metrics/WicketMetrics.java | 113 +++++++++++------- .../wicket/metrics/WicketMetricsSettings.java | 87 ++++++++++++++ .../src/main/resources/META-INF/aop.xml | 13 -- .../docs/guide/monitoring/monitoring_1.gdoc | 37 +++++- .../docs/guide/monitoring/monitoring_2.gdoc | 3 +- .../docs/guide/monitoring/monitoring_3.gdoc | 2 +- 7 files changed, 195 insertions(+), 64 deletions(-) create mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java delete mode 100644 wicket-metrics/src/main/resources/META-INF/aop.xml diff --git a/wicket-metrics/pom.xml b/wicket-metrics/pom.xml index 4ed79f1a015..a3a6a5b4871 100644 --- a/wicket-metrics/pom.xml +++ b/wicket-metrics/pom.xml @@ -32,6 +32,10 @@ about web applications build on the web framework. + + org.apache.wicket + wicket-core + org.aspectj aspectjrt diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java index 52ca2611ae7..6331a78799f 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java @@ -16,9 +16,10 @@ */ package org.apache.wicket.metrics; +import org.apache.wicket.Application; +import org.apache.wicket.MetaDataKey; import org.aspectj.lang.ProceedingJoinPoint; -import com.codahale.metrics.JmxReporter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer.Context; @@ -31,24 +32,32 @@ public class WicketMetrics { - private static MetricRegistry metricRegistry; - - private static boolean enabled = true; - - private static final String PREFIX = "ApacheWicket/"; - + /** The key for metrics **/ + public static final MetaDataKey METRICS = new MetaDataKey() + { + private static final long serialVersionUID = 1L; + }; + + /** The key for metrics registry **/ + public static final MetaDataKey METRIC_REGISTRY = new MetaDataKey() + { + private static final long serialVersionUID = 1L; + }; + + /** The key for metrics registry **/ + public static final MetaDataKey METRIC_SETTINGS = new MetaDataKey() + { + private static final long serialVersionUID = 1L; + }; + /** - * Gets the metric registry - * - * @return the metric registry + * Creates the wicket metrics */ - public static MetricRegistry getMetricRegistry() + public WicketMetrics() { - if (metricRegistry == null) - { - metricRegistry = new MetricRegistry(); - } - return metricRegistry; + Application application = Application.get(); + application.setMetaData(METRICS, this); + application.setMetaData(METRIC_SETTINGS, new WicketMetricsSettings()); } /** @@ -64,10 +73,13 @@ public static MetricRegistry getMetricRegistry() */ public Object measureTime(String name, ProceedingJoinPoint joinPoint) throws Throwable { - if (WicketMetrics.enabled) + WicketMetricsSettings settings = getSettings(); + MetricRegistry registry = getMetricRegistry(); + + if (settings.isEnabled()) { - Context context = getMetricRegistry().timer(PREFIX + name + renderClassName(joinPoint)) - .time(); + Context context = registry + .timer(settings.getPrefix() + name + renderClassName(joinPoint)).time(); try { return joinPoint.proceed(); @@ -95,9 +107,12 @@ public Object measureTime(String name, ProceedingJoinPoint joinPoint) throws Thr */ public Object mark(String name, ProceedingJoinPoint joinPoint) throws Throwable { - if (WicketMetrics.enabled) + WicketMetricsSettings settings = getSettings(); + MetricRegistry registry = getMetricRegistry(); + + if (settings.isEnabled()) { - getMetricRegistry().meter(PREFIX + name + renderClassName(joinPoint)).mark(); + registry.meter(settings.getPrefix() + name + renderClassName(joinPoint)).mark(); } if (joinPoint != null) { @@ -107,7 +122,7 @@ public Object mark(String name, ProceedingJoinPoint joinPoint) throws Throwable } /** - * Stops the contex quietly + * Stops the context quietly * * @param context * the context to stop @@ -121,42 +136,50 @@ public void stopQuietly(Context context) } /** - * Starts the jmx reporter - */ - public static void startJmxReporter() - { - JmxReporter.forRegistry(getMetricRegistry()).build().start(); - } - - /** - * Stops the jmx reporter + * Renders the class name of the given join point + * + * @param joinPoint + * the join point to get the class of + * @return the class name representation */ - public static void stopJmxReporter() + public String renderClassName(ProceedingJoinPoint joinPoint) { - JmxReporter.forRegistry(getMetricRegistry()).build().stop(); + return joinPoint != null + ? "/" + joinPoint.getTarget().getClass().getName().replace('.', '_') : ""; } /** - * If the metrics should be enabled + * Gets the metric registry * - * @param enabled - * if the metrics should be enabled + * @return the metric registry */ - public static void setEnabled(boolean enabled) + private MetricRegistry getMetricRegistry() { - WicketMetrics.enabled = enabled; + Application application = Application.get(); + MetricRegistry metricRegistry = application.getMetaData(METRIC_REGISTRY); + if (metricRegistry == null) + { + metricRegistry = new MetricRegistry(); + application.setMetaData(METRIC_REGISTRY, metricRegistry); + } + return metricRegistry; } /** - * Renders the class name of the given join point + * Gets the wicket metrics settings * - * @param joinPoint - * the join point to get the class of - * @return the class name representation + * @return the wicket metrics settings */ - public String renderClassName(ProceedingJoinPoint joinPoint) + private WicketMetricsSettings getSettings() { - return joinPoint != null - ? "/" + joinPoint.getTarget().getClass().getName().replace('.', '_') : ""; + Application application = Application.get(); + + WicketMetricsSettings metricRegistry = application.getMetaData(METRIC_SETTINGS); + if (metricRegistry == null) + { + metricRegistry = new WicketMetricsSettings(); + Application.get().setMetaData(METRIC_SETTINGS, metricRegistry); + } + return metricRegistry; } } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java new file mode 100644 index 00000000000..1bbaef220e0 --- /dev/null +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java @@ -0,0 +1,87 @@ +/* + * 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. + */ +package org.apache.wicket.metrics; + +import org.apache.wicket.Application; + +import com.codahale.metrics.JmxReporter; +import com.codahale.metrics.MetricRegistry; + +/** + * Settings to configure wicket metrics + * + * @author Tobias Soloschenko + * + */ +public class WicketMetricsSettings +{ + + private boolean enabled = true; + + private String prefix = "ApacheWicket/"; + + /** + * If the metrics should be enabled + * + * @param enabled + * if the metrics should be enabled + */ + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + /** + * If the wicket metrics are enabled + * + * @return if the wicket metrics are enabled + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * Gets the prefix. + * + * @return the prefix + */ + public String getPrefix() + { + return prefix; + } + + /** + * Starts the jmx reporter + */ + public void startJmxReporter() + { + MetricRegistry metricRegistry = Application.get() + .getMetaData(WicketMetrics.METRIC_REGISTRY); + JmxReporter.forRegistry(metricRegistry).build().start(); + } + + /** + * Stops the jmx reporter + */ + public void stopJmxReporter() + { + MetricRegistry metricRegistry = Application.get() + .getMetaData(WicketMetrics.METRIC_REGISTRY); + JmxReporter.forRegistry(metricRegistry).build().stop(); + } +} diff --git a/wicket-metrics/src/main/resources/META-INF/aop.xml b/wicket-metrics/src/main/resources/META-INF/aop.xml deleted file mode 100644 index 0d8ee24e583..00000000000 --- a/wicket-metrics/src/main/resources/META-INF/aop.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc index 608b9c24572..6d2dab5d5fb 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc @@ -1,4 +1,4 @@ -This is a little example how to setup wicket-metrics within a tomcat. +This is a little example how to setup wicket-metrics within a Apache Tomcat. (1) Add the maven dependency to your project {code} @@ -13,7 +13,36 @@ This is a little example how to setup wicket-metrics within a tomcat. (3) Add the java agent to the jvm start options of your tomcat: -javaagent:/pathToServer/lib/aspectjweaver-x.x.x.jar -(4) To enable the JMX measurement write the following line into your init method of your Application (Now you are able to connect with jvisualvm to your server and have a look at the data): +(4) Add an aop.xml to your project with the metrics you want to use (aspect tags) - if you don't want to enable a metrics just remove the aspect tag: {code} -WicketMetrics.startJmxReporter(); -{code} \ No newline at end of file + + + + + + + + + + + + + +{code} + +(5 - optional) To enable the JMX measurement write the following line into your init method of your Application (Now you are able to connect with jvisualvm to your server and have a look at the data): +{code} +Application.get().getMetaData(WicketMetrics.METRIC_SETTINGS).startJmxReporter(); +{code} + +To deactivate: +{code} +Application.get().getMetaData(WicketMetrics.METRIC_SETTINGS).stopJmxReporter(); +{code} + +To disable measurement: +{code} +Application.get().getMetaData(WicketMetrics.METRIC_SETTINGS).setEnable(false); +{code} + + diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc index b77e7993c95..be330cedbd4 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc @@ -11,8 +11,9 @@ To visualize the metrics with Graphite a little additional configuration is requ (2) Add the following code to your Application's init method: {code} +MetricRegistry metricRegistry = Application.get().getMetaData(WicketMetrics.METRIC_REGISTRY) final Graphite graphite = new Graphite(new InetSocketAddress("127.0.0.1", 2003)); -final GraphiteReporter reporter = GraphiteReporter.forRegistry(WicketMetrics.getMetricRegistry()) +final GraphiteReporter reporter = GraphiteReporter.forRegistry(metricRegistry) .prefixedWith("WebApplications") .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc index 6760b6f9c09..56fcd89c5b7 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_3.gdoc @@ -1,6 +1,6 @@ The data which is going to be measured depends on the wicket-metrics implementation. So it doesn't make any sense to collect time data -about setRepsonsePage, but it does for the constructor of components, to see if a component needs a long time to be created. You can +about setResponsePage, but it does for the constructor of components, to see if a component needs a long time to be created. You can get the information about which data has been collected from out of the mbeans. From ee469cfe0eb749b96ede3a4188d118c79eb7a060 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Mon, 14 Mar 2016 08:54:55 +0100 Subject: [PATCH 10/16] Wicket Metrics - Fixed thread local issue --- .../apache/wicket/metrics/WicketMetrics.java | 25 +++---------------- .../metrics/aspects/WicketFilterAspect.java | 4 +-- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java index 6331a78799f..51e55c53d7f 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java @@ -32,33 +32,17 @@ public class WicketMetrics { - /** The key for metrics **/ - public static final MetaDataKey METRICS = new MetaDataKey() - { - private static final long serialVersionUID = 1L; - }; - /** The key for metrics registry **/ public static final MetaDataKey METRIC_REGISTRY = new MetaDataKey() { private static final long serialVersionUID = 1L; }; - + /** The key for metrics registry **/ public static final MetaDataKey METRIC_SETTINGS = new MetaDataKey() { private static final long serialVersionUID = 1L; }; - - /** - * Creates the wicket metrics - */ - public WicketMetrics() - { - Application application = Application.get(); - application.setMetaData(METRICS, this); - application.setMetaData(METRIC_SETTINGS, new WicketMetricsSettings()); - } /** * Simply measure the time for a {@literal @}around @@ -75,7 +59,7 @@ public Object measureTime(String name, ProceedingJoinPoint joinPoint) throws Thr { WicketMetricsSettings settings = getSettings(); MetricRegistry registry = getMetricRegistry(); - + if (settings.isEnabled()) { Context context = registry @@ -109,7 +93,7 @@ public Object mark(String name, ProceedingJoinPoint joinPoint) throws Throwable { WicketMetricsSettings settings = getSettings(); MetricRegistry registry = getMetricRegistry(); - + if (settings.isEnabled()) { registry.meter(settings.getPrefix() + name + renderClassName(joinPoint)).mark(); @@ -173,12 +157,11 @@ private MetricRegistry getMetricRegistry() private WicketMetricsSettings getSettings() { Application application = Application.get(); - WicketMetricsSettings metricRegistry = application.getMetaData(METRIC_SETTINGS); if (metricRegistry == null) { metricRegistry = new WicketMetricsSettings(); - Application.get().setMetaData(METRIC_SETTINGS, metricRegistry); + application.setMetaData(METRIC_SETTINGS, metricRegistry); } return metricRegistry; } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java index bb31b744bcf..c71430c50e7 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java +++ b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java @@ -41,9 +41,9 @@ public class WicketFilterAspect extends WicketMetrics * @throws Throwable * might occur while invoking process request */ - @Around("execution(* org.apache.wicket.protocol.http.WicketFilter.processRequest(..))") + @Around("execution(* org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(..))") public Object aroundRequestProcessed(ProceedingJoinPoint joinPoint) throws Throwable { - return measureTime("core/application/request", joinPoint); + return measureTime("core/application/requestCycle", joinPoint); } } From b4f4297119b59d8a2190697a553a63443440b4e6 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Mon, 14 Mar 2016 18:16:53 +0100 Subject: [PATCH 11/16] Wicket Metrics - Moved to experimental / doc improvements / aspects --- pom.xml | 5 +- wicket-experimental/pom.xml | 2 +- wicket-experimental/wicket-atmosphere/pom.xml | 3 +- .../wicket-metrics}/pom.xml | 4 +- .../apache/wicket/metrics/WicketMetrics.java | 4 +- .../wicket/metrics/WicketMetricsSettings.java | 0 .../WicketFilterRequestCycleAspect.java | 2 +- .../IPartialPageRequestHandlerAddAspect.java | 43 ++++++ ...eRequestHandlerAppendJavaScriptAspect.java | 45 +++++++ ...RequestHandlerPrependJavaScriptAspect.java | 32 +---- .../behavior/BehaviorCreateAspect.java | 4 +- .../component/ComponentCreateAspect.java | 47 +++++++ .../component/ComponentOnConfigureAspect.java | 48 +++++++ .../component/ComponentOnDetachAspect.java | 47 +++++++ .../ComponentOnInitializeAspect.java | 47 +++++++ .../component/ComponentOnRenderAspect.java | 48 +++++++ .../ComponentSetResponsePageAspect.java | 42 ++++++ .../aspects/markup/WicketTagCreateAspect.java | 43 ++++++ .../LoadableDetachableModelLoadAspect.java | 32 +++++ .../IRequestHandlerDetachAspect.java | 31 +++++ .../IRequestHandlerRespondAspect.java | 31 +++++ .../resource/IResourceCreateAspect.java | 30 +++++ .../ResourceReferenceCreateAspect.java | 6 +- .../resources/wicket-metrics.template.xml | 26 ++++ .../metrics/aspects/ComponentAspect.java | 122 ------------------ .../docs/guide/monitoring/monitoring_1.gdoc | 30 ++++- .../docs/guide/monitoring/monitoring_2.gdoc | 31 +++-- .../docs/guide/monitoring/monitoring_4.gdoc | 33 +++++ wicket-user-guide/src/docs/guide/toc.yml | 3 +- 29 files changed, 658 insertions(+), 183 deletions(-) rename {wicket-metrics => wicket-experimental/wicket-metrics}/pom.xml (94%) rename {wicket-metrics => wicket-experimental/wicket-metrics}/src/main/java/org/apache/wicket/metrics/WicketMetrics.java (97%) rename {wicket-metrics => wicket-experimental/wicket-metrics}/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java (100%) rename wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java => wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterRequestCycleAspect.java (96%) create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAddAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAppendJavaScriptAspect.java rename wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java => wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerPrependJavaScriptAspect.java (62%) rename wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java => wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/behavior/BehaviorCreateAspect.java (93%) create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentCreateAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnConfigureAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnDetachAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnInitializeAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnRenderAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentSetResponsePageAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/markup/WicketTagCreateAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java create mode 100644 wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java rename wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java => wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/ResourceReferenceCreateAspect.java (89%) create mode 100644 wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml delete mode 100644 wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java create mode 100644 wicket-user-guide/src/docs/guide/monitoring/monitoring_4.gdoc diff --git a/pom.xml b/pom.xml index f4f84a1301e..05d565f0605 100644 --- a/pom.xml +++ b/pom.xml @@ -114,7 +114,6 @@ wicket-bean-validation wicket-cdi-1.1 wicket-user-guide - wicket-metrics @@ -406,13 +405,13 @@ jar - org.apache.wicket + org.apache.wicket.experimental.wicket8 wicket-metrics 8.0.0-SNAPSHOT jar - org.apache.wicket.experimental.wicket7 + org.apache.wicket.experimental.wicket8 wicket-atmosphere 0.24-SNAPSHOT jar diff --git a/wicket-experimental/pom.xml b/wicket-experimental/pom.xml index e77b7d4ce67..9f9922d59eb 100644 --- a/wicket-experimental/pom.xml +++ b/wicket-experimental/pom.xml @@ -23,7 +23,7 @@ 8.0.0-SNAPSHOT ../pom.xml - org.apache.wicket.experimental.wicket7 + org.apache.wicket.experimental.wicket8 wicket-experimental pom Wicket-Experimental diff --git a/wicket-experimental/wicket-atmosphere/pom.xml b/wicket-experimental/wicket-atmosphere/pom.xml index dd8c10822f8..bca4c364fb3 100644 --- a/wicket-experimental/wicket-atmosphere/pom.xml +++ b/wicket-experimental/wicket-atmosphere/pom.xml @@ -18,13 +18,12 @@ 4.0.0 - org.apache.wicket.experimental.wicket7 + org.apache.wicket.experimental.wicket8 wicket-experimental 8.0.0-SNAPSHOT ../pom.xml wicket-atmosphere - 0.24-SNAPSHOT jar Wicket-Atmosphere Wicket-Atmosphere provides integration of the Atmosphere Framework in Wicket. diff --git a/wicket-metrics/pom.xml b/wicket-experimental/wicket-metrics/pom.xml similarity index 94% rename from wicket-metrics/pom.xml rename to wicket-experimental/wicket-metrics/pom.xml index a3a6a5b4871..3ae58279d72 100644 --- a/wicket-metrics/pom.xml +++ b/wicket-experimental/wicket-metrics/pom.xml @@ -19,8 +19,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 - org.apache.wicket - wicket-parent + org.apache.wicket.experimental.wicket8 + wicket-experimental 8.0.0-SNAPSHOT ../pom.xml diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java similarity index 97% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java rename to wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java index 51e55c53d7f..4b4704de375 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetrics.java @@ -137,7 +137,7 @@ public String renderClassName(ProceedingJoinPoint joinPoint) * * @return the metric registry */ - private MetricRegistry getMetricRegistry() + private static synchronized MetricRegistry getMetricRegistry() { Application application = Application.get(); MetricRegistry metricRegistry = application.getMetaData(METRIC_REGISTRY); @@ -154,7 +154,7 @@ private MetricRegistry getMetricRegistry() * * @return the wicket metrics settings */ - private WicketMetricsSettings getSettings() + private static synchronized WicketMetricsSettings getSettings() { Application application = Application.get(); WicketMetricsSettings metricRegistry = application.getMetaData(METRIC_SETTINGS); diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java similarity index 100% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java rename to wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/WicketMetricsSettings.java diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterRequestCycleAspect.java similarity index 96% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java rename to wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterRequestCycleAspect.java index c71430c50e7..f7f7c0cbb53 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/WicketFilterRequestCycleAspect.java @@ -27,7 +27,7 @@ * @author Tobias Soloschenko */ @Aspect -public class WicketFilterAspect extends WicketMetrics +public class WicketFilterRequestCycleAspect extends WicketMetrics { /** diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAddAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAddAspect.java new file mode 100644 index 00000000000..f14fe6d15e4 --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAddAspect.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.ajax; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Aspect which measures ajax request targets components to be requested for repaint + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class IPartialPageRequestHandlerAddAspect extends WicketMetrics +{ + /** + * Collects data how often components calls add + * + * @throws Throwable + * might occur while invoking add + */ + @Before("call(* org.apache.wicket.core.request.handler.IPartialPageRequestHandler.add(..))") + public void beforeAdd() throws Throwable + { + mark("core/ajax/add", null); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAppendJavaScriptAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAppendJavaScriptAspect.java new file mode 100644 index 00000000000..233c6397d5c --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerAppendJavaScriptAspect.java @@ -0,0 +1,45 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.ajax; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Aspect which measures ajax request targets append java script metrics + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class IPartialPageRequestHandlerAppendJavaScriptAspect extends WicketMetrics +{ + + /** + * Collects data how often components calls appendJavaScript + * + * @throws Throwable + * might occur while invoking appendJavaScript + */ + @Before("call(* org.apache.wicket.core.request.handler.IPartialPageRequestHandler.appendJavaScript(..))") + public void beforeAppendJavaScript() throws Throwable + { + mark("core/ajax/appendJavaScript", null); + } + +} diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerPrependJavaScriptAspect.java similarity index 62% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java rename to wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerPrependJavaScriptAspect.java index 24cb2a137fe..a1d183f9559 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/IPartialPageRequestHandlerAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ajax/IPartialPageRequestHandlerPrependJavaScriptAspect.java @@ -14,33 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.wicket.metrics.aspects; +package org.apache.wicket.metrics.aspects.ajax; import org.apache.wicket.metrics.WicketMetrics; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; /** - * Aspect which checks ajax request targets + * Aspect measures checks ajax request targets prepent java script * * @author Tobias Soloschenko * */ @Aspect -public class IPartialPageRequestHandlerAspect extends WicketMetrics +public class IPartialPageRequestHandlerPrependJavaScriptAspect extends WicketMetrics { - /** - * Collects data how often components calls add - * - * @throws Throwable - * might occur while invoking add - */ - @Before("call(* org.apache.wicket.core.request.handler.IPartialPageRequestHandler.add(..))") - public void beforeAdd() throws Throwable - { - mark("core/ajax/add", null); - } - + /** * Collects data how often components calls prependJavaScript * @@ -52,17 +41,4 @@ public void beforePrependJavaScript() throws Throwable { mark("core/ajax/prependJavaScript", null); } - - /** - * Collects data how often components calls appendJavaScript - * - * @throws Throwable - * might occur while invoking appendJavaScript - */ - @Before("call(* org.apache.wicket.core.request.handler.IPartialPageRequestHandler.appendJavaScript(..))") - public void beforeAppendJavaScript() throws Throwable - { - mark("core/ajax/appendJavaScript", null); - } - } diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/behavior/BehaviorCreateAspect.java similarity index 93% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java rename to wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/behavior/BehaviorCreateAspect.java index 94cc60c8f0d..767d8942b15 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/BehaviorAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/behavior/BehaviorCreateAspect.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.wicket.metrics.aspects; +package org.apache.wicket.metrics.aspects.behavior; import org.apache.wicket.metrics.WicketMetrics; import org.aspectj.lang.ProceedingJoinPoint; @@ -28,7 +28,7 @@ * */ @Aspect -public class BehaviorAspect extends WicketMetrics +public class BehaviorCreateAspect extends WicketMetrics { /** * Collects data how often a behavior is created diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentCreateAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentCreateAspect.java new file mode 100644 index 00000000000..318ef3164c2 --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentCreateAspect.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.component; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Gets information how often different components are created + * + * @author Tobias Soloschenko + */ +@Aspect +public class ComponentCreateAspect extends WicketMetrics +{ + + /** + * Collects data how often components are created + * + * @param joinPoint + * the join point (component) which is created + * @return the object returned from the join point + * @throws Throwable + * might occur while constructing a new component + */ + @Around("execution(org.apache.wicket.Component.new(..))") + public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/component/create", joinPoint); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnConfigureAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnConfigureAspect.java new file mode 100644 index 00000000000..7058567de82 --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnConfigureAspect.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.component; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Gets information how often different components are configured + * + * @author Tobias Soloschenko + */ +@Aspect +public class ComponentOnConfigureAspect extends WicketMetrics +{ + + /** + * Collects data how often components calls onConfigure + * + * @param joinPoint + * the join point (component) which is configured + * @return the object returned from the join point + * + * @throws Throwable + * might occur while invoking onConfigure + */ + @Around("execution(* org.apache.wicket.Component.onConfigure(..))") + public Object aroundOnConfigure(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/component/configure", joinPoint); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnDetachAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnDetachAspect.java new file mode 100644 index 00000000000..1abfd53fa1f --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnDetachAspect.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.component; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Gets information how often different components are detached + * + * @author Tobias Soloschenko + */ +@Aspect +public class ComponentOnDetachAspect extends WicketMetrics +{ + + /** + * Collects data how often components calls onDetach + * + * @param joinPoint + * the join point (component) which is calling detach + * @return the object returned from the join point + * @throws Throwable + * might occur while invoking onDetach + */ + @Around("execution(* org.apache.wicket.Component.onDetach(..))") + public Object arroundOnDetach(ProceedingJoinPoint joinPoint) throws Throwable + { + return mark("core/component/detach", joinPoint); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnInitializeAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnInitializeAspect.java new file mode 100644 index 00000000000..d2cca54c9bc --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnInitializeAspect.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.component; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Gets information how often different components are initialized + * + * @author Tobias Soloschenko + */ +@Aspect +public class ComponentOnInitializeAspect extends WicketMetrics +{ + /** + * Collects data how often components calls onInitialize + * + * @param joinPoint + * the join point (component) which is initialized + * @return the object returned from the join point + * + * @throws Throwable + * might occur while invoking onInitialize + */ + @Around("execution(* org.apache.wicket.Component.onInitialize(..))") + public Object aroundOnInitialize(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/component/initialize", joinPoint); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnRenderAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnRenderAspect.java new file mode 100644 index 00000000000..ad9bdfd4acb --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentOnRenderAspect.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.component; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Gets information how often different components are rendered + * + * @author Tobias Soloschenko + */ +@Aspect +public class ComponentOnRenderAspect extends WicketMetrics +{ + + /** + * Collects data how often components are rendered + * + * @param joinPoint + * the join point (component) which is rendered + * @return the object returned from the join point + * @throws Throwable + * might occur while onRender + */ + @Around("execution(* org.apache.wicket.Component.onRender(..))") + public Object aroundOnRender(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/component/render", joinPoint); + } + +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentSetResponsePageAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentSetResponsePageAspect.java new file mode 100644 index 00000000000..7a802046feb --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/component/ComponentSetResponsePageAspect.java @@ -0,0 +1,42 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.component; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Gets information how often different components are calling setResponsePage + * + * @author Tobias Soloschenko + */ +@Aspect +public class ComponentSetResponsePageAspect extends WicketMetrics +{ + /** + * Collects data how often components redirect to another page + * + * @throws Throwable + * might occur while invoking setResponsePage + */ + @Before("call(* org.apache.wicket.Component.setResponsePage(..))") + public void beforeResponsePage() throws Throwable + { + mark("core/component/redirect", null); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/markup/WicketTagCreateAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/markup/WicketTagCreateAspect.java new file mode 100644 index 00000000000..2a2751a2cae --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/markup/WicketTagCreateAspect.java @@ -0,0 +1,43 @@ +/* + * 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. + */ +package org.apache.wicket.metrics.aspects.markup; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; + +/** + * Measures information about wicket tags + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class WicketTagCreateAspect extends WicketMetrics +{ + /** + * Collects data how often components redirect to another page + * + * @throws Throwable + * might occur while invoking setResponsePage + */ + @Before("call(org.apache.wicket.markup.WicketTag.new(..))") + public void beforeResponsePage() throws Throwable + { + mark("core/tags/wicket/create", null); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java new file mode 100644 index 00000000000..5b83de50d42 --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java @@ -0,0 +1,32 @@ +package org.apache.wicket.metrics.aspects.model; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Measures information about how long the loading process of the ldm take + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class LoadableDetachableModelLoadAspect extends WicketMetrics +{ + + /** + * Collects data how often a request handler calls detach + * + * @param joinPoint + * the join point (request handler) which processes the response + * @return the object returned from the join point + * @throws Throwable + * might occur while detach + */ + @Around("execution(* org.apache.wicket.model.LoadableDetachableModel.load())") + public Object aroundOnRender(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/model/loadabledetachablemodel/load", joinPoint); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java new file mode 100644 index 00000000000..7c658b48738 --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java @@ -0,0 +1,31 @@ +package org.apache.wicket.metrics.aspects.requesthandler; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Measures information about request handlers detach + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class IRequestHandlerDetachAspect extends WicketMetrics +{ + /** + * Collects data how often a request handler calls detach + * + * @param joinPoint + * the join point (request handler) which processes the response + * @return the object returned from the join point + * @throws Throwable + * might occur while detach + */ + @Around("execution(* org.apache.wicket.request.IRequestHandler.detach(..))") + public Object aroundOnRender(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/requesthandler/detach", joinPoint); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java new file mode 100644 index 00000000000..45387f2d850 --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java @@ -0,0 +1,31 @@ +package org.apache.wicket.metrics.aspects.requesthandler; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Measures information about request handlers respond + * + * @author Tobias Soloschenko + * + */ +@Aspect +public class IRequestHandlerRespondAspect extends WicketMetrics +{ + /** + * Collects data how often a request handler processes its response + * + * @param joinPoint + * the join point (request handler) which processes the response + * @return the object returned from the join point + * @throws Throwable + * might occur while respond + */ + @Around("execution(* org.apache.wicket.request.IRequestHandler.respond(..))") + public Object aroundOnRender(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("core/requesthandler/respond", joinPoint); + } +} diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java new file mode 100644 index 00000000000..7a5f1f7300c --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java @@ -0,0 +1,30 @@ +package org.apache.wicket.metrics.aspects.resource; + +import org.apache.wicket.metrics.WicketMetrics; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; + +/** + * Measures how often a resource is created + * @author Tobias Soloschenko + * + */ +@Aspect +public class IResourceCreateAspect extends WicketMetrics +{ + /** + * Collects data how often a resource reference is created + * + * @param joinPoint + * the join point (resource reference) which is created + * @return the result of constructor + * @throws Throwable + * might occur while creating a new resource reference + */ + @Around("execution(org.apache.wicket.request.resource.IResource.new(..))") + public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable + { + return mark("core/resource/resource/create", joinPoint); + } +} diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/ResourceReferenceCreateAspect.java similarity index 89% rename from wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java rename to wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/ResourceReferenceCreateAspect.java index cd11e5486fc..b14af58e582 100644 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ResourceReferenceAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/ResourceReferenceCreateAspect.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.wicket.metrics.aspects; +package org.apache.wicket.metrics.aspects.resource; import org.apache.wicket.metrics.WicketMetrics; import org.aspectj.lang.ProceedingJoinPoint; @@ -28,7 +28,7 @@ * */ @Aspect -public class ResourceReferenceAspect extends WicketMetrics +public class ResourceReferenceCreateAspect extends WicketMetrics { /** @@ -43,6 +43,6 @@ public class ResourceReferenceAspect extends WicketMetrics @Around("execution(org.apache.wicket.request.resource.ResourceReference.new(..))") public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable { - return mark("core/resource/create", joinPoint); + return mark("core/resource/reference/create", joinPoint); } } diff --git a/wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml b/wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml new file mode 100644 index 00000000000..e59cb5125a7 --- /dev/null +++ b/wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java b/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java deleted file mode 100644 index e046a638265..00000000000 --- a/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/ComponentAspect.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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. - */ -package org.apache.wicket.metrics.aspects; - -import org.apache.wicket.metrics.WicketMetrics; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; - -/** - * Gets information how often different components are rendered - * - * @author Tobias Soloschenko - */ -@Aspect -public class ComponentAspect extends WicketMetrics -{ - - /** - * Collects data how often components are rendered - * - * @param joinPoint - * the join point (component) which is rendered - * @return the object returned from the join point - * @throws Throwable - * might occur while onRender - */ - @Around("execution(* org.apache.wicket.Component.onRender(..))") - public Object aroundOnRender(ProceedingJoinPoint joinPoint) throws Throwable - { - return measureTime("core/component/render", joinPoint); - } - - /** - * Collects data how often components are created - * - * @param joinPoint - * the join point (component) which is created - * @return the object returned from the join point - * @throws Throwable - * might occur while constructing a new component - */ - @Around("execution(org.apache.wicket.Component.new(..))") - public Object aroundNew(ProceedingJoinPoint joinPoint) throws Throwable - { - return measureTime("core/component/create", joinPoint); - } - - /** - * Collects data how often components calls onConfigure - * - * @param joinPoint - * the join point (component) which is configured - * @return the object returned from the join point - * - * @throws Throwable - * might occur while invoking onConfigure - */ - @Around("execution(* org.apache.wicket.Component.onConfigure(..))") - public Object aroundOnConfigure(ProceedingJoinPoint joinPoint) throws Throwable - { - return measureTime("core/component/configure", joinPoint); - } - - /** - * Collects data how often components calls onInitialize - * - * @param joinPoint - * the join point (component) which is initialized - * @return the object returned from the join point - * - * @throws Throwable - * might occur while invoking onInitialize - */ - @Around("execution(* org.apache.wicket.Component.onInitialize(..))") - public Object aroundOnInitialize(ProceedingJoinPoint joinPoint) throws Throwable - { - return measureTime("core/component/initialize", joinPoint); - } - - /** - * Collects data how often components calls onDetach - * - * @param joinPoint - * the join point (component) which is calling detach - * @return the object returned from the join point - * @throws Throwable - * might occur while invoking onDetach - */ - @Around("execution(* org.apache.wicket.Component.onDetach(..))") - public Object arroundOnDetach(ProceedingJoinPoint joinPoint) throws Throwable - { - return mark("core/component/detach", joinPoint); - } - - /** - * Collects data how often components redirect to another page - * - * @throws Throwable - * might occur while invoking setResponsePage - */ - @Before("call(* org.apache.wicket.Component.setResponsePage(..))") - public void beforeResponsePage() throws Throwable - { - mark("core/component/redirect", null); - } -} diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc index 6d2dab5d5fb..d63186dbf6b 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc @@ -3,7 +3,7 @@ This is a little example how to setup wicket-metrics within a Apache Tomcat. (1) Add the maven dependency to your project {code} - org.apache.wicket + org.apache.wicket.experimental.wicket8 wicket-metrics ${wicket.version} @@ -13,7 +13,7 @@ This is a little example how to setup wicket-metrics within a Apache Tomcat. (3) Add the java agent to the jvm start options of your tomcat: -javaagent:/pathToServer/lib/aspectjweaver-x.x.x.jar -(4) Add an aop.xml to your project with the metrics you want to use (aspect tags) - if you don't want to enable a metrics just remove the aspect tag: +(4) Add an aop.xml to your project's META-INF folder at the root of your classpath with the metrics you want to use (aspect tags) - if you don't want to enable a metrics just remove the aspect tag: {code} @@ -21,15 +21,31 @@ This is a little example how to setup wicket-metrics within a Apache Tomcat. - - - - - + + + + + + + + + + + + + + + + + {code} +* If you have set wicket-metrics as dependency you can open "wicket-metrics.template.xml" to get a full template of the "aop.xml" + +* For the weaver options refer to the "AspectJ LTW configuration documentation":https://eclipse.org/aspectj/doc/next/devguide/ltw-configuration.html + (5 - optional) To enable the JMX measurement write the following line into your init method of your Application (Now you are able to connect with jvisualvm to your server and have a look at the data): {code} Application.get().getMetaData(WicketMetrics.METRIC_SETTINGS).startJmxReporter(); diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc index be330cedbd4..e404345d880 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc @@ -1,5 +1,6 @@ To visualize the metrics with Graphite a little additional configuration is required: + (1) Add the additional maven dependency to your project: {code} @@ -11,15 +12,27 @@ To visualize the metrics with Graphite a little additional configuration is requ (2) Add the following code to your Application's init method: {code} -MetricRegistry metricRegistry = Application.get().getMetaData(WicketMetrics.METRIC_REGISTRY) -final Graphite graphite = new Graphite(new InetSocketAddress("127.0.0.1", 2003)); -final GraphiteReporter reporter = GraphiteReporter.forRegistry(metricRegistry) - .prefixedWith("WebApplications") - .convertRatesTo(TimeUnit.SECONDS) - .convertDurationsTo(TimeUnit.MILLISECONDS) - .filter(MetricFilter.ALL) - .build(graphite); -reporter.start(1, TimeUnit.SECONDS); + private GraphiteReporter reporter; + + @Override + protected void init() + { + MetricRegistry metricRegistry = this.getMetaData(WicketMetrics.METRIC_REGISTRY); + final Graphite graphite = new Graphite(new InetSocketAddress("127.0.0.1", 2003)); + reporter = GraphiteReporter.forRegistry(metricRegistry).prefixedWith("WebApplications") + .convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS) + .filter(MetricFilter.ALL).build(graphite); + + // Collects data every 5 seconds + reporter.start(5, TimeUnit.SECONDS); + } + + @Override + protected void onDestroy() + { + super.onDestroy(); + reporter.stop(); + } {code} (3) Install and setup graphite on your system. Example installation for mac (beware that this is only a quickstart setup!): diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_4.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_4.gdoc new file mode 100644 index 00000000000..004b26d7b12 --- /dev/null +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_4.gdoc @@ -0,0 +1,33 @@ +There are only a two steps required to write own measurements for life data statistics in wicket: + +(1) Write a class which is named very close to what it measures. This class should extends WicketMetrics and should annotated with @Aspect and provide one method with a join point scanning for the target signature. +{code} + @Aspect + public class MySpecialAspect extends WicketMetrics + { + @Around("execution(* my.package.MyClass.myMethod(..))") + public Object aroundRequestProcessed(ProceedingJoinPoint joinPoint) throws Throwable + { + return measureTime("mycategory/someinformation/", joinPoint); + } + } +{code} +* To measure time you need @Around because measureTime of WicketMetrics requires the joinPoint - the class name is appended with a slash at the end + +* To only mark that a method is called you can use mark of WicketMetrics and apply null as a second parameter - if you apply a join point to mark the class name is appended with a slash at the end + +(2) Add the class to your aop.xml and of course the package to scan for classes that are target for your measurements: +{code} + + + + + + + + + + ..... + + +{code} \ No newline at end of file diff --git a/wicket-user-guide/src/docs/guide/toc.yml b/wicket-user-guide/src/docs/guide/toc.yml index dab016ea6be..303903c0c1a 100644 --- a/wicket-user-guide/src/docs/guide/toc.yml +++ b/wicket-user-guide/src/docs/guide/toc.yml @@ -224,10 +224,11 @@ wicketstuff: wicketstuff_6: Module wicketstuff-rest-annotations wicketstuff_7: Module stateless monitoring: - title: Wicket Metrics Monitoring + title: Wicket Metrics Monitoring (Experimental) monitoring_1: Example setup monitoring_2: Visualization with Graphite monitoring_3: Measured data + monitoring_4: Write own measurements redirects: title: Lost In Redirection With Apache Wicket (Appendix) contributing: From b0578a28b7ae55bf527dc3c455327a44a67b227e Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Mon, 14 Mar 2016 18:28:07 +0100 Subject: [PATCH 12/16] Wicket Metrics - Added missing license headers --- .../model/LoadableDetachableModelLoadAspect.java | 16 ++++++++++++++++ .../IRequestHandlerDetachAspect.java | 16 ++++++++++++++++ .../IRequestHandlerRespondAspect.java | 16 ++++++++++++++++ .../aspects/resource/IResourceCreateAspect.java | 16 ++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java index 5b83de50d42..7d9207d20f9 100644 --- a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/model/LoadableDetachableModelLoadAspect.java @@ -1,3 +1,19 @@ +/* + * 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. + */ package org.apache.wicket.metrics.aspects.model; import org.apache.wicket.metrics.WicketMetrics; diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java index 7c658b48738..9daa4823213 100644 --- a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerDetachAspect.java @@ -1,3 +1,19 @@ +/* + * 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. + */ package org.apache.wicket.metrics.aspects.requesthandler; import org.apache.wicket.metrics.WicketMetrics; diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java index 45387f2d850..c953415e551 100644 --- a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/requesthandler/IRequestHandlerRespondAspect.java @@ -1,3 +1,19 @@ +/* + * 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. + */ package org.apache.wicket.metrics.aspects.requesthandler; import org.apache.wicket.metrics.WicketMetrics; diff --git a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java index 7a5f1f7300c..6b15f2937e0 100644 --- a/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java +++ b/wicket-experimental/wicket-metrics/src/main/java/org/apache/wicket/metrics/aspects/resource/IResourceCreateAspect.java @@ -1,3 +1,19 @@ +/* + * 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. + */ package org.apache.wicket.metrics.aspects.resource; import org.apache.wicket.metrics.WicketMetrics; From f020c78d1af4e06e95002982a8a41020ca79cf5d Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Mon, 14 Mar 2016 18:30:53 +0100 Subject: [PATCH 13/16] Wicket Metrics - Added the project as module --- wicket-experimental/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/wicket-experimental/pom.xml b/wicket-experimental/pom.xml index 9f9922d59eb..d6aa6a029c7 100644 --- a/wicket-experimental/pom.xml +++ b/wicket-experimental/pom.xml @@ -30,6 +30,7 @@ Wicket-Experimental contains experimental Wicket modules that may or may not be supported in the future. wicket-atmosphere + wicket-metrics From 785b4f84d84eab2c0ed94072c12682db1c9a9d20 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Wed, 16 Mar 2016 10:23:27 +0100 Subject: [PATCH 14/16] Fixed versions for experimental modules --- wicket-experimental/wicket-atmosphere/pom.xml | 1 + wicket-experimental/wicket-metrics/pom.xml | 1 + wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc | 2 +- wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/wicket-experimental/wicket-atmosphere/pom.xml b/wicket-experimental/wicket-atmosphere/pom.xml index bca4c364fb3..44fbf1958a0 100644 --- a/wicket-experimental/wicket-atmosphere/pom.xml +++ b/wicket-experimental/wicket-atmosphere/pom.xml @@ -24,6 +24,7 @@ ../pom.xml wicket-atmosphere + 0.24-SNAPSHOT jar Wicket-Atmosphere Wicket-Atmosphere provides integration of the Atmosphere Framework in Wicket. diff --git a/wicket-experimental/wicket-metrics/pom.xml b/wicket-experimental/wicket-metrics/pom.xml index 3ae58279d72..9e810622854 100644 --- a/wicket-experimental/wicket-metrics/pom.xml +++ b/wicket-experimental/wicket-metrics/pom.xml @@ -25,6 +25,7 @@ ../pom.xml wicket-metrics + 0.1-SNAPSHOT jar Wicket Metrics diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc index d63186dbf6b..6d41935cf98 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_1.gdoc @@ -5,7 +5,7 @@ This is a little example how to setup wicket-metrics within a Apache Tomcat. org.apache.wicket.experimental.wicket8 wicket-metrics - ${wicket.version} + 0.X-SNAPSHOT {code} diff --git a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc index e404345d880..0bd18b2485b 100644 --- a/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc +++ b/wicket-user-guide/src/docs/guide/monitoring/monitoring_2.gdoc @@ -1,6 +1,5 @@ To visualize the metrics with Graphite a little additional configuration is required: - (1) Add the additional maven dependency to your project: {code} @@ -10,6 +9,8 @@ To visualize the metrics with Graphite a little additional configuration is requ {code} +* the metrics.graphite.version should be the same as the metrics version of the wicket-metrics dependency. Check the maven dependencies to ensure this. + (2) Add the following code to your Application's init method: {code} private GraphiteReporter reporter; From b303feee2b69394f8403faaf1611e611876e8f2b Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Wed, 16 Mar 2016 13:00:28 +0100 Subject: [PATCH 15/16] Fixed version in parent pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 05d565f0605..5254637b6d4 100644 --- a/pom.xml +++ b/pom.xml @@ -407,7 +407,7 @@ org.apache.wicket.experimental.wicket8 wicket-metrics - 8.0.0-SNAPSHOT + 0.1-SNAPSHOT jar From c17628e22d4f11e0cbec9bd4bc8a224785fd8c67 Mon Sep 17 00:00:00 2001 From: Tobias Soloschenko Date: Wed, 16 Mar 2016 17:48:37 +0100 Subject: [PATCH 16/16] Wicket Metrics - Removed unwanted include --- .../src/main/resources/wicket-metrics.template.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml b/wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml index e59cb5125a7..377e451a5ed 100644 --- a/wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml +++ b/wicket-experimental/wicket-metrics/src/main/resources/wicket-metrics.template.xml @@ -1,8 +1,8 @@ + -