You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2021/07/02 15:59:54 UTC

[syncope] branch master updated: [SYNCOPE-1455] Adding Route statistics to Console

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

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new a755318  [SYNCOPE-1455] Adding Route statistics to Console
a755318 is described below

commit a755318c4d192c6ea48046a06acdc282f73ef6b6
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Fri Jul 2 17:59:26 2021 +0200

    [SYNCOPE-1455] Adding Route statistics to Console
---
 .../apache/syncope/client/console/pages/SRA.java   |  20 ++-
 .../apache/syncope/client/console/pages/WA.java    |  20 ++-
 .../client/console/panels/SRAStatisticsPanel.java  | 151 +++++++++++++++++++++
 .../client/console/panels/WASessionPanel.java      |   4 +-
 .../syncope/client/console/rest/SRAStatistics.java | 124 +++++++++++++++++
 .../console/rest/SRAStatisticsRestClient.java      |  73 ++++++++++
 .../client/console/rest/WASessionRestClient.java   |   4 +-
 .../client/console/panels/SRAStatisticsPanel.html  |  42 ++++++
 .../client/console/widgets/NumberWidget.java       |  10 +-
 .../sra/src/main/resources/application.properties  |   6 +-
 .../org/apache/syncope/fit/sra/OIDCSRAITCase.java  |   3 +-
 sra/pom.xml                                        |   5 -
 sra/src/main/resources/application.properties      |   6 +-
 13 files changed, 421 insertions(+), 47 deletions(-)

diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java
index a82339e..45f23a2 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java
@@ -25,12 +25,11 @@ import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.annotations.AMPage;
 import org.apache.syncope.client.console.panels.SRARouteDirectoryPanel;
+import org.apache.syncope.client.console.panels.SRAStatisticsPanel;
 import org.apache.syncope.client.console.rest.SRARouteRestClient;
 import org.apache.syncope.client.ui.commons.Constants;
-import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.common.keymaster.client.api.ServiceOps;
 import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
-import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.AMEntitlement;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.AjaxLink;
@@ -38,7 +37,6 @@ import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
 import org.apache.wicket.extensions.markup.html.tabs.ITab;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.Model;
 import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.spring.injection.annot.SpringBean;
@@ -57,6 +55,8 @@ public class SRA extends BasePage {
         body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
         body.setOutputMarkupId(true);
 
+        List<NetworkService> instances = serviceOps.list(NetworkService.Type.SRA);
+
         AjaxLink<?> push = new AjaxLink<>("push") {
 
             @Override
@@ -64,7 +64,6 @@ public class SRA extends BasePage {
                 try {
                     SRARouteRestClient.push();
                     SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
-                    target.add(body);
                 } catch (Exception e) {
                     LOG.error("While pushing to SRA", e);
                     SyncopeConsoleSession.get().onException(e);
@@ -72,20 +71,20 @@ public class SRA extends BasePage {
                 ((BasePage) getPageReference().getPage()).getNotificationPanel().refresh(target);
             }
         };
-        push.setEnabled(!serviceOps.list(NetworkService.Type.SRA).isEmpty()
-                && SyncopeConsoleSession.get().owns(AMEntitlement.SRA_ROUTE_PUSH, SyncopeConstants.ROOT_REALM));
+        push.setEnabled(!instances.isEmpty() && SyncopeConsoleSession.get().owns(AMEntitlement.SRA_ROUTE_PUSH));
         body.add(push);
 
         WebMarkupContainer content = new WebMarkupContainer("content");
         content.setOutputMarkupId(true);
-        AjaxBootstrapTabbedPanel<ITab> tabbedPanel = new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList());
+        AjaxBootstrapTabbedPanel<ITab> tabbedPanel =
+                new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList(instances));
         content.add(tabbedPanel);
 
         body.add(content);
     }
 
-    private List<ITab> buildTabList() {
-        List<ITab> tabs = new ArrayList<>(2);
+    private List<ITab> buildTabList(final List<NetworkService> instances) {
+        List<ITab> tabs = new ArrayList<>();
 
         tabs.add(new AbstractTab(new ResourceModel("routes")) {
 
@@ -97,7 +96,6 @@ public class SRA extends BasePage {
             }
         });
 
-        List<NetworkService> instances = serviceOps.list(NetworkService.Type.SRA);
         if (!instances.isEmpty()) {
             tabs.add(new AbstractTab(new ResourceModel("metrics")) {
 
@@ -105,7 +103,7 @@ public class SRA extends BasePage {
 
                 @Override
                 public Panel getPanel(final String panelId) {
-                    return new AjaxTextFieldPanel(panelId, panelId, Model.of(instances.get(0).getAddress()));
+                    return new SRAStatisticsPanel(panelId, instances, getPageReference());
                 }
             });
         }
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
index cc283b1..6287b19 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java
@@ -74,7 +74,7 @@ public class WA extends BasePage {
         body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
         body.setOutputMarkupId(true);
 
-        List<NetworkService> waInstances = serviceOps.list(NetworkService.Type.WA);
+        List<NetworkService> instances = serviceOps.list(NetworkService.Type.WA);
 
         AjaxLink<?> push = new AjaxLink<>("push") {
 
@@ -83,7 +83,6 @@ public class WA extends BasePage {
                 try {
                     WAConfigRestClient.push();
                     SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
-                    target.add(body);
                 } catch (Exception e) {
                     LOG.error("While pushing to WA", e);
                     SyncopeConsoleSession.get().onException(e);
@@ -91,20 +90,19 @@ public class WA extends BasePage {
                 ((BaseWebPage) getPageReference().getPage()).getNotificationPanel().refresh(target);
             }
         };
-        push.setEnabled(!waInstances.isEmpty()
-                && SyncopeConsoleSession.get().owns(AMEntitlement.WA_CONFIG_PUSH));
+        push.setEnabled(!instances.isEmpty() && SyncopeConsoleSession.get().owns(AMEntitlement.WA_CONFIG_PUSH));
         body.add(push);
 
         WebMarkupContainer content = new WebMarkupContainer("content");
         content.setOutputMarkupId(true);
         AjaxBootstrapTabbedPanel<ITab> tabbedPanel =
-                new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList(waInstances));
+                new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList(instances));
         content.add(tabbedPanel);
 
         body.add(content);
 
-        if (!waInstances.isEmpty()) {
-            String actuatorEndpoint = waInstances.get(0).getAddress() + "/actuator/env";
+        if (!instances.isEmpty()) {
+            String actuatorEndpoint = instances.get(0).getAddress() + "actuator/env";
             try {
                 Response response = WebClient.create(
                         actuatorEndpoint,
@@ -134,8 +132,8 @@ public class WA extends BasePage {
         }
     }
 
-    private List<ITab> buildTabList(final List<NetworkService> waInstances) {
-        List<ITab> tabs = new ArrayList<>(0);
+    private List<ITab> buildTabList(final List<NetworkService> instances) {
+        List<ITab> tabs = new ArrayList<>();
 
         if (SyncopeConsoleSession.get().owns(AMEntitlement.AUTH_MODULE_LIST)) {
             tabs.add(new AbstractTab(new ResourceModel("authModules")) {
@@ -205,14 +203,14 @@ public class WA extends BasePage {
             });
         }
 
-        if (!waInstances.isEmpty() && SyncopeConsoleSession.get().owns(AMEntitlement.WA_SESSION_LIST)) {
+        if (!instances.isEmpty() && SyncopeConsoleSession.get().owns(AMEntitlement.WA_SESSION_LIST)) {
             tabs.add(new AbstractTab(new ResourceModel("sessions")) {
 
                 private static final long serialVersionUID = 5211692813425391144L;
 
                 @Override
                 public Panel getPanel(final String panelId) {
-                    return new WASessionPanel(panelId, waInstances, getPageReference());
+                    return new WASessionPanel(panelId, instances, getPageReference());
                 }
             });
         }
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRAStatisticsPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRAStatisticsPanel.java
new file mode 100644
index 0000000..5c6e2b7
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRAStatisticsPanel.java
@@ -0,0 +1,151 @@
+/*
+ * 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.syncope.client.console.panels;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.client.console.rest.SRARouteRestClient;
+import org.apache.syncope.client.console.rest.SRAStatistics;
+import org.apache.syncope.client.console.rest.SRAStatisticsRestClient;
+import org.apache.syncope.client.console.widgets.NumberWidget;
+import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
+import org.apache.syncope.common.lib.to.SRARouteTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.Model;
+
+public class SRAStatisticsPanel extends Panel {
+
+    private static final long serialVersionUID = 23816535591360L;
+
+    private static final List<Buttons.Type> TYPES = List.of(
+            Buttons.Type.Info, Buttons.Type.Success, Buttons.Type.Warning, Buttons.Type.Danger, Buttons.Type.Dark);
+
+    private final NumberWidget count;
+
+    private final NumberWidget totalTime;
+
+    private final NumberWidget max;
+
+    private final List<Pair<String, String>> selected = new ArrayList<>();
+
+    private final LoadableDetachableModel<Map<String, String>> routes =
+            new LoadableDetachableModel<Map<String, String>>() {
+
+        @Override
+        protected Map<String, String> load() {
+            return SRARouteRestClient.list().stream().
+                    collect(Collectors.toMap(SRARouteTO::getKey, SRARouteTO::getName));
+        }
+    };
+
+    private int current;
+
+    public SRAStatisticsPanel(final String id, final List<NetworkService> instances, final PageReference pageRef) {
+        super(id);
+
+        SRAStatistics stats = SRAStatisticsRestClient.get(instances, selected);
+
+        count = new NumberWidget("count", "bg-green", stats.getMeasurement("COUNT").orElse(0F),
+                "count", "fas fa-pen-nib");
+        add(count);
+
+        totalTime = new NumberWidget("totalTime", "bg-info", stats.getMeasurement("TOTAL_TIME").orElse(0F),
+                "total time", "fas fa-stopwatch");
+        add(totalTime);
+
+        max = new NumberWidget("max", "bg-yellow", stats.getMeasurement("MAX").orElse(0F),
+                "max", "fas fa-greater-than");
+        add(max);
+
+        ListView<SRAStatistics.Tag> availableTags = new ListView<>("availableTags", stats.getAvailableTags()) {
+
+            @Override
+            protected void populateItem(final ListItem<SRAStatistics.Tag> tag) {
+                String btnCss = next().cssClassName();
+                tag.add(new Label("label", tag.getModelObject().getTag()));
+                tag.add(new ListView<String>("tag", tag.getModelObject().getValues()) {
+
+                    @Override
+                    protected void populateItem(final ListItem<String> value) {
+                        AjaxLink<String> valueLink = new AjaxLink<>("valueLink") {
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target) {
+                                Pair<String, String> selection =
+                                        Pair.of(tag.getModelObject().getTag(), value.getModelObject());
+                                if (selected.contains(selection)) {
+                                    selected.remove(selection);
+                                } else {
+                                    selected.add(selection);
+                                }
+
+                                SRAStatistics refresh = SRAStatisticsRestClient.get(instances, selected);
+
+                                count.refresh(refresh.getMeasurement("COUNT").orElse(0F));
+                                totalTime.refresh(refresh.getMeasurement("TOTAL_TIME").orElse(0F));
+                                max.refresh(refresh.getMeasurement("MAX").orElse(0F));
+
+                                target.add(count);
+                                target.add(totalTime);
+                                target.add(max);
+                            }
+
+                            @Override
+                            protected void onComponentTag(final ComponentTag tag) {
+                                super.onComponentTag(tag);
+                                tag.append("class", btnCss, " ");
+                            }
+                        };
+
+                        IModel<String> valueLabel = routes.getObject().containsKey(value.getModelObject())
+                                ? Model.of(routes.getObject().get(value.getModelObject()))
+                                : value.getModel();
+                        valueLink.add(new Label("valueLabel", valueLabel));
+                        value.add(valueLink);
+                    }
+                });
+            }
+        };
+        add(availableTags);
+    }
+
+    private Buttons.Type next() {
+        if (current < TYPES.size()) {
+            Buttons.Type type = TYPES.get(current);
+            current++;
+            return type;
+        }
+
+        current = 0;
+        return next();
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WASessionPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WASessionPanel.java
index 24439d9..407de1a 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WASessionPanel.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WASessionPanel.java
@@ -36,7 +36,7 @@ public class WASessionPanel extends Panel {
 
     private static final long serialVersionUID = 30189416462011L;
 
-    public WASessionPanel(final String id, final List<NetworkService> waInstances, final PageReference pageRef) {
+    public WASessionPanel(final String id, final List<NetworkService> instances, final PageReference pageRef) {
         super(id);
 
         Model<String> keywordModel = new Model<>(StringUtils.EMPTY);
@@ -44,7 +44,7 @@ public class WASessionPanel extends Panel {
         WebMarkupContainer searchBoxContainer = new WebMarkupContainer("searchBox");
         add(searchBoxContainer);
 
-        WASessionDirectoryPanel directoryPanel = new WASessionDirectoryPanel("directoryPanel", waInstances, pageRef);
+        WASessionDirectoryPanel directoryPanel = new WASessionDirectoryPanel("directoryPanel", instances, pageRef);
         add(directoryPanel);
 
         Form<?> form = new Form<>("form");
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatistics.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatistics.java
new file mode 100644
index 0000000..7d265f3
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatistics.java
@@ -0,0 +1,124 @@
+/*
+ * 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.syncope.client.console.rest;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+public class SRAStatistics implements Serializable {
+
+    private static final long serialVersionUID = 25070367703725L;
+
+    public static class Measurement implements Serializable {
+
+        private static final long serialVersionUID = 24933964529045L;
+
+        private String statistic;
+
+        private Float value;
+
+        public String getStatistic() {
+            return statistic;
+        }
+
+        public void setStatistic(final String statistic) {
+            this.statistic = statistic;
+        }
+
+        public Float getValue() {
+            return value;
+        }
+
+        public void setValue(final Float value) {
+            this.value = value;
+        }
+    }
+
+    public static class Tag implements Serializable {
+
+        private static final long serialVersionUID = 25010610267446L;
+
+        private String tag;
+
+        private final List<String> values = new ArrayList<>();
+
+        public String getTag() {
+            return tag;
+        }
+
+        public void setTag(final String tag) {
+            this.tag = tag;
+        }
+
+        public List<String> getValues() {
+            return values;
+        }
+    }
+
+    private String name;
+
+    private String description;
+
+    private String baseUnit;
+
+    private final List<Measurement> measurements = new ArrayList<>();
+
+    private final List<Tag> availableTags = new ArrayList<>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    public String getBaseUnit() {
+        return baseUnit;
+    }
+
+    public void setBaseUnit(final String baseUnit) {
+        this.baseUnit = baseUnit;
+    }
+
+    @JsonIgnore
+    public Optional<Float> getMeasurement(final String statistic) {
+        return measurements.stream().filter(m -> statistic.equals(m.getStatistic())).
+                findFirst().map(Measurement::getValue);
+    }
+
+    public List<Measurement> getMeasurements() {
+        return measurements;
+    }
+
+    public List<Tag> getAvailableTags() {
+        return availableTags;
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java
new file mode 100644
index 0000000..cd56204
--- /dev/null
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java
@@ -0,0 +1,73 @@
+/*
+ * 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.syncope.client.console.rest;
+
+import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
+import java.util.List;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.console.SyncopeWebApplication;
+import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class SRAStatisticsRestClient {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SRAStatisticsRestClient.class);
+
+    private static final List<?> JAX_RS_PROVIDERS = List.of(new JacksonJsonProvider());
+
+    private static String getActuatorEndpoint(final List<NetworkService> instances) {
+        return instances.get(0).getAddress() + "actuator/metrics/spring.cloud.gateway.requests";
+    }
+
+    public static SRAStatistics get(final List<NetworkService> waInstances, final List<Pair<String, String>> selected) {
+        try {
+            WebClient client = WebClient.create(
+                    getActuatorEndpoint(waInstances),
+                    JAX_RS_PROVIDERS,
+                    SyncopeWebApplication.get().getAnonymousUser(),
+                    SyncopeWebApplication.get().getAnonymousKey(),
+                    null).
+                    accept(MediaType.APPLICATION_JSON_TYPE);
+
+            if (!selected.isEmpty()) {
+                client.query("tag", selected.stream().map(s -> s.getKey() + ":" + s.getValue()).toArray());
+            }
+
+            Response response = client.get();
+            if (response.getStatus() == Response.Status.OK.getStatusCode()) {
+                return response.readEntity(SRAStatistics.class);
+            }
+
+            LOG.error("Unexpected response for SRA statistics from {}: {}",
+                    getActuatorEndpoint(waInstances), response.getStatus());
+        } catch (Exception e) {
+            LOG.error("Could not fetch SRA statistics from {}", getActuatorEndpoint(waInstances), e);
+        }
+
+        return new SRAStatistics();
+    }
+
+    private SRAStatisticsRestClient() {
+        // private constructor for static utility class
+    }
+}
diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java
index 94aaf65..d903b34 100644
--- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java
+++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java
@@ -42,8 +42,8 @@ public final class WASessionRestClient implements RestClient {
 
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
-    private static String getActuatorEndpoint(final List<NetworkService> waInstances) {
-        return waInstances.get(0).getAddress() + "/actuator/ssoSessions";
+    private static String getActuatorEndpoint(final List<NetworkService> instances) {
+        return instances.get(0).getAddress() + "actuator/ssoSessions";
     }
 
     public static List<WASession> list(final List<NetworkService> waInstances) {
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SRAStatisticsPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SRAStatisticsPanel.html
new file mode 100644
index 0000000..e3bc608
--- /dev/null
+++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/SRAStatisticsPanel.html
@@ -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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div class="row">
+      <div class="col-lg-4 col-xs-4" wicket:id="count"/>
+      <div class="col-lg-4 col-xs-4" wicket:id="totalTime"/>
+      <div class="col-lg-4 col-xs-4" wicket:id="max"/>
+    </div>
+
+
+    <span wicket:id="availableTags">
+      <div class="row mt-1">
+        <div class="col-md-2">
+          <label wicket:id="label"/>
+        </div>
+        <div class="col-md-10">
+          <span wicket:id="tag">
+            <a href="#" wicket:id="valueLink" class="btn" data-toggle="button" aria-pressed="false">
+              <span wicket:id="valueLabel"/></a>
+          </span>
+        </div>
+      </div>
+    </span>
+  </wicket:panel>
+</html>
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/NumberWidget.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/NumberWidget.java
index ae5a855..e6e577f 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/NumberWidget.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/NumberWidget.java
@@ -36,11 +36,11 @@ public class NumberWidget extends BaseWidget {
 
     private static final long serialVersionUID = -816175678514035085L;
 
-    private int number;
+    private Number number;
 
     private final Label numberLabel;
 
-    public NumberWidget(final String id, final String bg, final int number, final String label, final String icon) {
+    public NumberWidget(final String id, final String bg, final Number number, final String label, final String icon) {
         super(id);
         this.number = number;
         setOutputMarkupId(true);
@@ -49,8 +49,8 @@ public class NumberWidget extends BaseWidget {
         box.add(new AttributeAppender("class", ' ' + bg));
 
         boolean isAuthorized = true;
-        final PageParameters pageParameters = new PageParameters();
-        final Class<? extends IRequestablePage> responsePage;
+        PageParameters pageParameters = new PageParameters();
+        Class<? extends IRequestablePage> responsePage;
         List<String> anyTypes = AnyTypeRestClient.list();
         switch (id) {
             case "totalUsers":
@@ -124,7 +124,7 @@ public class NumberWidget extends BaseWidget {
         box.add(iconLabel);
     }
 
-    public boolean refresh(final int number) {
+    public boolean refresh(final Number number) {
         if (this.number != number) {
             this.number = number;
             numberLabel.setDefaultModelObject(number);
diff --git a/docker/sra/src/main/resources/application.properties b/docker/sra/src/main/resources/application.properties
index 22a059e..92fcc3c 100644
--- a/docker/sra/src/main/resources/application.properties
+++ b/docker/sra/src/main/resources/application.properties
@@ -20,12 +20,8 @@ spring.main.banner-mode=log
 
 server.port=8080
 
-spring.cloud.gateway.metrics.enabled=true
- 
 management.security.enabled=true
 management.endpoint.gateway.enabled=true
-management.endpoints.web.exposure.include=health,loggers,metrics,prometheus,gateway
-management.endpoint.health.show-details=always
-management.endpoint.metrics.enabled=true
+management.endpoints.web.exposure.include=health,loggers,metrics,gateway
 
 service.discovery.address=${SERVICE_DISCOVERY_ADDRESS}
diff --git a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
index 6369ad4..6d19811 100644
--- a/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
+++ b/fit/wa-reference/src/test/java/org/apache/syncope/fit/sra/OIDCSRAITCase.java
@@ -76,7 +76,8 @@ public class OIDCSRAITCase extends AbstractSRAITCase {
     public static void startSRA() throws IOException, InterruptedException, TimeoutException {
         assumeTrue(OIDCSRAITCase.class.equals(MethodHandles.lookup().lookupClass()));
 
-        doStartSRA("oidc");
+        // doStartSRA("oidc");
+        sraRouteService.pushToSRA();
     }
 
     protected static void oidcClientAppSetup(
diff --git a/sra/pom.xml b/sra/pom.xml
index 9c78820..3daf441 100644
--- a/sra/pom.xml
+++ b/sra/pom.xml
@@ -94,11 +94,6 @@ under the License.
     </dependency>
 
     <dependency>
-      <groupId>io.micrometer</groupId>
-      <artifactId>micrometer-registry-prometheus</artifactId>
-    </dependency>
-
-    <dependency>
       <groupId>org.jsoup</groupId>
       <artifactId>jsoup</artifactId>
     </dependency>
diff --git a/sra/src/main/resources/application.properties b/sra/src/main/resources/application.properties
index c77fcaa..145bfcc 100644
--- a/sra/src/main/resources/application.properties
+++ b/sra/src/main/resources/application.properties
@@ -20,12 +20,8 @@ spring.main.banner-mode=log
 
 server.port=8080
 
-spring.cloud.gateway.metrics.enabled=true
- 
 management.security.enabled=true
 management.endpoint.gateway.enabled=true
-management.endpoints.web.exposure.include=health,loggers,metrics,prometheus,gateway
-management.endpoint.health.show-details=always
-management.endpoint.metrics.enabled=true
+management.endpoints.web.exposure.include=health,loggers,metrics,gateway
 
 service.discovery.address=http://localhost:8080/