You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2019/10/18 11:27:05 UTC

[isis] 01/03: spikes using brave+zipkin

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2164
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 5bca197d6ad500c24c90fd6cbea5c83d83d452ed
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Oct 16 06:37:33 2019 +0200

    spikes using brave+zipkin
---
 core/pom.xml                                       |  23 ++++
 core/runtime/pom.xml                               |  23 ++++
 .../isis/core/webapp/TracingZipkinFilter.java      | 115 +++++++++++++++++
 .../integration/wicket/WebRequestCycleForIsis.java | 141 ++++++++++++++++++++-
 .../viewer/wicket/ui/ComponentFactoryAbstract.java |  16 ++-
 .../CollectionContentsAsAjaxTablePanel.java        |   2 +
 example/application/helloworld/pom.xml             |  51 ++++++++
 .../src/main/webapp/WEB-INF/logging.properties     |   4 +
 .../helloworld/src/main/webapp/WEB-INF/web.xml     |  18 +++
 example/application/simpleapp/webapp/pom.xml       |  15 +++
 10 files changed, 402 insertions(+), 6 deletions(-)

diff --git a/core/pom.xml b/core/pom.xml
index bb8079d..92567b7 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -180,6 +180,9 @@
         <javax-mail.version>1.4.7</javax-mail.version>
 
         <jboss-jaxrs-api_2.0_spec.version>1.0.0.Final</jboss-jaxrs-api_2.0_spec.version>
+        <brave.version>5.8.0</brave.version>
+        <okhttp.version>3.9.1</okhttp.version>
+        <brave-opentracing.version>0.34.2</brave-opentracing.version>
     </properties>
 
     <scm>
@@ -2055,6 +2058,26 @@ ${license.additional-notes}
                 <version>${webjars-servlet-2.x.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>io.zipkin.brave</groupId>
+                <artifactId>brave-bom</artifactId>
+                <version>${brave.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>com.squareup.okhttp3</groupId>
+                <artifactId>okhttp</artifactId>
+                <version>${okhttp.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>io.opentracing.brave</groupId>
+                <artifactId>brave-opentracing</artifactId>
+                <version>${brave-opentracing.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 
diff --git a/core/runtime/pom.xml b/core/runtime/pom.xml
index 1c79759..db0c10c 100644
--- a/core/runtime/pom.xml
+++ b/core/runtime/pom.xml
@@ -32,6 +32,7 @@
     <properties>
         <jar-plugin.automaticModuleName>org.apache.isis.core.runtime</jar-plugin.automaticModuleName>
         <git-plugin.propertiesDir>org/apache/isis/core/runtime</git-plugin.propertiesDir>
+        <zipkin-sender-okhttp3.version>2.10.3</zipkin-sender-okhttp3.version>
     </properties>
 
     <build>
@@ -127,6 +128,28 @@
         </dependency>
 
         <dependency>
+            <groupId>io.zipkin.brave</groupId>
+            <artifactId>brave-instrumentation-servlet</artifactId>
+            <version>${brave.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.zipkin.reporter2</groupId>
+            <artifactId>zipkin-sender-okhttp3</artifactId>
+            <version>${zipkin-sender-okhttp3.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.opentracing.brave</groupId>
+            <artifactId>brave-opentracing</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.apache.geronimo.specs</groupId>
             <artifactId>geronimo-servlet_3.0_spec</artifactId>
             <scope>provided</scope>
diff --git a/core/runtime/src/main/java/org/apache/isis/core/webapp/TracingZipkinFilter.java b/core/runtime/src/main/java/org/apache/isis/core/webapp/TracingZipkinFilter.java
new file mode 100644
index 0000000..51820fe
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/webapp/TracingZipkinFilter.java
@@ -0,0 +1,115 @@
+/*
+ *  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.isis.core.webapp;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import brave.Tracer;
+import brave.Tracing;
+import brave.propagation.B3Propagation;
+import brave.propagation.ExtraFieldPropagation;
+import brave.servlet.TracingFilter;
+import zipkin2.Span;
+import zipkin2.reporter.AsyncReporter;
+import zipkin2.reporter.Sender;
+import zipkin2.reporter.okhttp3.OkHttpSender;
+
+public class TracingZipkinFilter implements Filter {
+
+    Sender sender;
+    AsyncReporter<Span> spanReporter;
+    Tracing tracing;
+    Filter delegate ;
+    ExtraFieldPropagation.Factory propagationFactory;
+    Tracer tracer;
+
+    @Override
+    public void init(final FilterConfig filterConfig) {
+
+        final String tracingEndpoint = initParamFrom(filterConfig, "tracingEndpoint", null);
+        if(tracingEndpoint == null) {
+            return;
+        }
+        sender = OkHttpSender.create(tracingEndpoint);
+        spanReporter = AsyncReporter.create(sender);
+
+        propagationFactory = ExtraFieldPropagation.newFactoryBuilder(B3Propagation.FACTORY)
+                .addPrefixedFields("baggage-", Arrays.asList("country-code", "user-id"))
+                .build();
+
+        final String tracingLocalServiceName = initParamFrom(filterConfig, "tracingLocalServiceName", "apache-isis-app");
+        tracing = Tracing.newBuilder()
+                .localServiceName(tracingLocalServiceName)
+                .propagationFactory(propagationFactory)
+                .spanReporter(spanReporter)
+                .build();
+
+        tracer = tracing.tracer();
+
+//        tracer = BraveTracer.create(tracing);
+        delegate = TracingFilter.create(tracing);
+    }
+
+    private static String initParamFrom(
+            final FilterConfig filterConfig,
+            final String paramName,
+            final String defaultValue) {
+        final String value = filterConfig.getInitParameter(paramName);
+        return value != null ? value : defaultValue;
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException {
+        if(delegate != null) {
+
+            request.setAttribute("isis.tracer.zipkin.brave", tracer);
+
+            delegate.doFilter(request, response, chain);
+        } else {
+            chain.doFilter(request, response);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        try {
+            if(tracing != null) {
+                tracing.close(); // disables Tracing.current()
+            }
+            if(spanReporter != null) {
+                spanReporter.close(); // stops reporting thread and flushes data
+            }
+            if(sender != null) {
+                sender.close(); // closes any transport resources
+            }
+        } catch (IOException e) {
+            // do something real
+        }
+    }
+}
diff --git a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
index 854a427..b315a4b 100644
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/wicket/WebRequestCycleForIsis.java
@@ -23,6 +23,8 @@ import java.lang.reflect.Constructor;
 import java.util.List;
 import java.util.Set;
 
+import javax.servlet.http.HttpServletRequest;
+
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Throwables;
@@ -73,6 +75,11 @@ import org.apache.isis.viewer.wicket.ui.pages.login.WicketSignInPage;
 import org.apache.isis.viewer.wicket.ui.pages.mmverror.MmvErrorPage;
 import org.apache.isis.viewer.wicket.ui.panels.PromptFormAbstract;
 
+import brave.Span;
+import brave.Tracer;
+import brave.opentracing.BraveTracer;
+import brave.propagation.ThreadLocalSpan;
+
 /**
  * Isis-specific implementation of the Wicket's {@link RequestCycle},
  * automatically opening a {@link IsisSession} at the beginning of the request
@@ -86,10 +93,12 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
 
     @Override
     public synchronized void onBeginRequest(RequestCycle requestCycle) {
-        
+
         if (!Session.exists()) {
             return;
         }
+        LOG.debug("onBeginRequest");
+
 
         final AuthenticatedWebSessionForIsis wicketSession = AuthenticatedWebSessionForIsis.get();
         final AuthenticationSession authenticationSession = wicketSession.getAuthenticationSession();
@@ -97,13 +106,40 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
             return;
         }
 
+//        final Span span = ThreadLocalSpan.CURRENT_TRACER.next()
+//                .name("WebRequestCycleForIsis#onBeginRequest")
+//                .tag("started-by", "onBeginRequest")
+//                .tag("requestCycle.request.url", requestCycle.getRequest().getUrl().toString())
+//                .start();
+
+//        final Tracer tracerIfAny = tracerFrom(requestCycle);
+//        if(tracerIfAny != null) {
+//            final Span span = tracerIfAny.nextSpan().name("WebRequestCycleForIsis#onBeginRequest");
+//            span.start();
+//            span.tag("requestCycle.request.url", requestCycle.getRequest().getUrl().toString());
+//        }
         getIsisSessionFactory().openSession(authenticationSession);
         getTransactionManager().startTransaction();
+
+    }
+
+    private static BraveTracer tracerFrom(final RequestCycle requestCycle) {
+        final Object containerRequest = requestCycle.getRequest().getContainerRequest();
+        if (!(containerRequest instanceof HttpServletRequest)) {
+            return null;
+        }
+        final HttpServletRequest httpServletRequest = (HttpServletRequest) containerRequest;
+        final Object tracerObj = httpServletRequest.getAttribute("isis.tracer.zipkin.brave");
+        if (!(tracerObj instanceof BraveTracer)) {
+            return null;
+        }
+        return (BraveTracer) tracerObj;
     }
 
     @Override
-    public void onRequestHandlerResolved(final RequestCycle cycle, final IRequestHandler handler)
-    {
+    public void onRequestHandlerResolved(final RequestCycle cycle, final IRequestHandler handler) {
+
+        LOG.debug("onRequestHandlerResolved");
 
         if(handler instanceof RenderPageRequestHandler) {
             AdapterManager.ConcurrencyChecking.disable();
@@ -136,13 +172,40 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
             AdapterManager.ConcurrencyChecking.reset(AdapterManager.ConcurrencyChecking.CHECK);
         }
 
+        final ThreadLocalSpan tracer = ThreadLocalSpan.CURRENT_TRACER;
+        final Tracer tracerIfAny = tracerFrom(cycle);
         if (getIsisSessionFactory().inSession()) {
             try {
                 // will commit (or abort) the transaction;
                 // an abort will cause the exception to be thrown.
                 getTransactionManager().endTransaction();
+                final Span span = tracer.remove();
+                if(span != null) {
+                    span.tag("finished-by", "onRequestHandlerExecuted");
+                    span.finish();
+                }
+//                if(tracerIfAny != null) {
+//                    final Span span = tracerIfAny.currentSpan();
+//                    span.finish();
+//                }
             } catch(Exception ex) {
-                // will redirect to error page after this, 
+
+                final Span span = tracer.remove();
+                if(span != null) {
+                    span.tag("errored-by", "onRequestHandlerExecuted");
+                    span.error(ex);
+                }
+
+                final Span nextSpan = tracer.next().name("restart response after fail to commit xactn").start();
+
+//                if(tracerIfAny != null) {
+//                    final Span span = tracerIfAny.currentSpan();
+//                    span.error(ex);
+//
+//                    tracerIfAny.nextSpan().name("restart response after fail to commit xactn").start();
+//                }
+
+                // will redirect to error page after this,
                 // so make sure there is a new transaction ready to go.
                 if(getTransactionManager().getCurrentTransaction().getState().isComplete()) {
                     getTransactionManager().startTransaction();
@@ -167,6 +230,9 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
      */
     @Override
     public synchronized void onEndRequest(RequestCycle cycle) {
+
+        LOG.debug("onEndRequest");
+
         if (getIsisSessionFactory().inSession()) {
             try {
                 // belt and braces
@@ -175,16 +241,48 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
                 getIsisSessionFactory().closeSession();
             }
         }
+        final Span span = ThreadLocalSpan.CURRENT_TRACER.remove();
+        if(span != null) {
+            span.tag("finished-by", "onEndRequest");
+            span.finish();
+        }
+//        final Tracer tracerIfAny = tracerFrom(cycle);
+//        if(tracerIfAny != null) {
+//            final Span span = tracerIfAny.currentSpan();
+//            span.finish();
+//        }
     }
 
 
     @Override
     public IRequestHandler onException(RequestCycle cycle, Exception ex) {
 
+        LOG.debug("onException");
+
+        final Span span = ThreadLocalSpan.CURRENT_TRACER.remove();
+        if(span != null) {
+            span.tag("errored-by", "onException");
+            span.error(ex);
+        }
+//        final Tracer tracerIfAny = tracerFrom(cycle);
+//        if(tracerIfAny != null) {
+//            final Span span = tracerIfAny.currentSpan();
+//            span.error(ex);
+//        }
+
         final MetaModelInvalidException mmie = IsisContext.getMetaModelInvalidExceptionIfAny();
         if(mmie != null) {
             final Set<String> validationErrors = mmie.getValidationErrors();
             final MmvErrorPage mmvErrorPage = new MmvErrorPage(validationErrors);
+
+            final Span nextSpan = ThreadLocalSpan.CURRENT_TRACER.next().name("redirect to error page on MetaModelInvalidException")
+                    .tag("started-by", "onException")
+                    .start();
+//            if(tracerIfAny != null) {
+//                final Span span = tracerIfAny.currentSpan();
+//                tracerIfAny.nextSpan().name("redirect to error page on MetaModelInvalidException").start();
+//            }
+
             return new RenderPageRequestHandler(new PageProvider(mmvErrorPage), RedirectPolicy.ALWAYS_REDIRECT);
         }
 
@@ -200,6 +298,13 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
                     addMessage(null);
 
                 }
+                final Span nextSpan = ThreadLocalSpan.CURRENT_TRACER.next().name("respond gracefully after ListenerInvocationNotAllowedException")
+                        .tag("started-by", "onException")
+                        .start();
+//                if(tracerIfAny != null) {
+//                    tracerIfAny.nextSpan().name("respond gracefully after ListenerInvocationNotAllowedException").start();
+//                }
+
                 return respondGracefully(cycle);
             }
 
@@ -209,6 +314,12 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
                     getServicesInjector().lookupServices(ExceptionRecognizer2.class);
             String recognizedMessageIfAny = new ExceptionRecognizerComposite(exceptionRecognizers).recognize(ex);
             if(recognizedMessageIfAny != null) {
+                final Span nextSpan = ThreadLocalSpan.CURRENT_TRACER.next().name("respond gracefully after recognised exception")
+                        .tag("started-by", "onException")
+                        .start();
+//                if(tracerIfAny != null) {
+//                    tracerIfAny.nextSpan().name("respond gracefully after recognised exception").start();
+//                }
                 return respondGracefully(cycle);
             }
 
@@ -217,12 +328,24 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
                     ObjectMember.HiddenException.isInstanceOf()).first();
             if(hiddenIfAny.isPresent()) {
                 addMessage("hidden");
+                final Span nextSpan = ThreadLocalSpan.CURRENT_TRACER.next().name("respond gracefully if hidden")
+                        .tag("started-by", "onException")
+                        .start();
+//                if(tracerIfAny != null) {
+//                    tracerIfAny.nextSpan().name("respond gracefully if hidden").start();
+//                }
                 return respondGracefully(cycle);
             }
             final Optional<Throwable> disabledIfAny = FluentIterable.from(causalChain).filter(
                     ObjectMember.DisabledException.isInstanceOf()).first();
             if(disabledIfAny.isPresent()) {
                 addTranslatedMessage(disabledIfAny.get().getMessage());
+                final Span nextSpan = ThreadLocalSpan.CURRENT_TRACER.next().name("respond gracefully if disabled")
+                        .tag("started-by", "onException")
+                        .start();
+//                if(tracerIfAny != null) {
+//                    tracerIfAny.nextSpan().name("respond gracefully if disabled").start();
+//                }
                 return respondGracefully(cycle);
             }
 
@@ -235,7 +358,15 @@ public class WebRequestCycleForIsis extends AbstractRequestCycleListener {
         RedirectPolicy redirectPolicy = ex instanceof PageExpiredException
                 ? RedirectPolicy.NEVER_REDIRECT
                 : RedirectPolicy.ALWAYS_REDIRECT;
-        return errorPageProvider != null 
+
+        final Span nextSpan = ThreadLocalSpan.CURRENT_TRACER.next().name("redirect to error page on " + ex.getClass().getSimpleName())
+                .tag("started-by", "onException")
+                .start();
+//        if(tracerIfAny != null) {
+//            tracerIfAny.nextSpan().name("redirect to error page on " + ex.getClass().getSimpleName()).start();
+//        }
+
+        return errorPageProvider != null
                 ? new RenderPageRequestHandler(errorPageProvider, redirectPolicy)
                 : null;
     }
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentFactoryAbstract.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentFactoryAbstract.java
index e018a74..048ea4f 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentFactoryAbstract.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/ComponentFactoryAbstract.java
@@ -25,6 +25,9 @@ import org.apache.wicket.request.resource.CssResourceReference;
 
 import org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
 
+import brave.propagation.CurrentTraceContext;
+import brave.propagation.ThreadLocalCurrentTraceContext;
+
 /**
  * Adapter implementation for {@link ComponentFactory}.
  */
@@ -95,7 +98,18 @@ public abstract class ComponentFactoryAbstract implements ComponentFactory {
 
     @Override
     public final Component createComponent(final IModel<?> model) {
-        return createComponent(getComponentType().toString(), model);
+        final String id = getComponentType().toString();
+        final CurrentTraceContext ctc = ThreadLocalCurrentTraceContext.Default.inheritable();
+        final CurrentTraceContext.Scope scope = ctc.newScope(ctc.get());
+
+        //final Span start = ThreadLocalSpan.CURRENT_TRACER.next().tag("createComponent.id", id).start();
+        try {
+            return createComponent(id, model);
+        } finally {
+            scope.close();
+//            final Span remove = ThreadLocalSpan.CURRENT_TRACER.remove();
+//            remove.finish();
+        }
     }
 
     @Override
diff --git a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
index d796a9e..c3e96b8 100644
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -57,6 +57,8 @@ import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterToggleboxColumn;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 
+import brave.propagation.ThreadLocalSpan;
+
 /**
  * {@link PanelAbstract Panel} that represents a {@link EntityCollectionModel
  * collection of entity}s rendered using {@link AjaxFallbackDefaultDataTable}.
diff --git a/example/application/helloworld/pom.xml b/example/application/helloworld/pom.xml
index 532bdd5..5cb2bb5 100644
--- a/example/application/helloworld/pom.xml
+++ b/example/application/helloworld/pom.xml
@@ -186,6 +186,57 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>isis-mavendeps-intellij</id>
+            <activation>
+                <property>
+                    <name>idea.version</name>
+                </property>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.isis.core</groupId>
+                    <artifactId>isis-core-webserver</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>zipkin</id>
+            <activation>
+                <property>
+                    <name>!skip.zipkin</name>
+                </property>
+            </activation>
+            <dependencyManagement>
+                <dependencies>
+                    <dependency>
+                        <groupId>io.zipkin.brave</groupId>
+                        <artifactId>brave-bom</artifactId>
+                        <version>5.8.0</version>
+                        <type>pom</type>
+                        <scope>import</scope>
+                    </dependency>
+                </dependencies>
+            </dependencyManagement>
+            <dependencies>
+ <!--               <dependency>
+                    <groupId>io.zipkin.brave</groupId>
+                    <artifactId>brave-http</artifactId>
+                        <version>5.8.0</version>
+                </dependency>
+                <dependency>
+                    <groupId>io.zipkin.brave</groupId>
+                    <artifactId>brave-core</artifactId>
+                    <version>5.8.0</version>
+                </dependency>
+ -->
+                <dependency>
+                    <groupId>io.zipkin.brave</groupId>
+                    <artifactId>brave-instrumentation-servlet</artifactId>
+                        <version>5.8.0</version>
+                </dependency>
+            </dependencies>
+        </profile>
 
         <profile>
             <id>skinny-war</id>
diff --git a/example/application/helloworld/src/main/webapp/WEB-INF/logging.properties b/example/application/helloworld/src/main/webapp/WEB-INF/logging.properties
index 573a664..1b3dfc2 100644
--- a/example/application/helloworld/src/main/webapp/WEB-INF/logging.properties
+++ b/example/application/helloworld/src/main/webapp/WEB-INF/logging.properties
@@ -242,3 +242,7 @@ log4j.additivity.dom.simple.SimpleObject=false
 # ERROR to suppress the WARNings we get as of 1.15.0
 log4j.logger.org.apache.wicket.page.XmlPartialPageUpdate=ERROR,Console
 log4j.additivity.org.apache.wicket.page.XmlPartialPageUpdate=false
+
+
+log4j.logger.org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleForIsis=DEBUG,Console
+log4j.additivity.org.apache.isis.viewer.wicket.viewer.integration.wicket.WebRequestCycleForIsis=false
diff --git a/example/application/helloworld/src/main/webapp/WEB-INF/web.xml b/example/application/helloworld/src/main/webapp/WEB-INF/web.xml
index cd4ee01..6496ba3 100644
--- a/example/application/helloworld/src/main/webapp/WEB-INF/web.xml
+++ b/example/application/helloworld/src/main/webapp/WEB-INF/web.xml
@@ -33,6 +33,24 @@
     </listener>
 
     <filter>
+        <filter-name>TracingZipkinFilter</filter-name>
+        <filter-class>org.apache.isis.core.webapp.TracingZipkinFilter</filter-class>
+        <init-param>
+            <param-name>tracingEndpoint</param-name>
+            <param-value>http://localhost:9411/api/v2/spans</param-value>
+        </init-param>
+        <init-param>
+            <param-name>tracingLocalServiceName</param-name>
+            <param-value>helloworld-app</param-value>
+        </init-param>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>TracingZipkinFilter</filter-name>
+        <url-pattern>/wicket/*</url-pattern>
+    </filter-mapping>
+
+    <filter>
         <filter-name>ShiroFilter</filter-name>
         <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
     </filter>
diff --git a/example/application/simpleapp/webapp/pom.xml b/example/application/simpleapp/webapp/pom.xml
index 8f943e3..9dd65f2 100644
--- a/example/application/simpleapp/webapp/pom.xml
+++ b/example/application/simpleapp/webapp/pom.xml
@@ -245,6 +245,21 @@
         </profile>
 
         <profile>
+            <id>isis-mavendeps-intellij</id>
+            <activation>
+                <property>
+                    <name>idea.version</name>
+                </property>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.isis.core</groupId>
+                    <artifactId>isis-core-webserver</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+
+        <profile>
             <id>skinny-war</id>
             <activation>
                 <property>