You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by jo...@apache.org on 2021/12/07 08:25:59 UTC

[sling-org-apache-sling-resourceresolver] branch master updated: SLING-10945 add metrics (#53)

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

joerghoh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git


The following commit(s) were added to refs/heads/master by this push:
     new 9554ba2  SLING-10945 add metrics (#53)
9554ba2 is described below

commit 9554ba22a25e91d94775d34afec95b84bca0a259
Author: Jörg Hoh <jo...@users.noreply.github.com>
AuthorDate: Tue Dec 7 09:25:01 2021 +0100

    SLING-10945 add metrics (#53)
    
    added metrics for
    * total number of aliases (sling:org.apache.sling.resourceresolver.numberOfAliases)
    * total number of vanity paths (sling:org.apache.sling.resourceresolver.numberOfVanityPaths)
    * number of unclosed resource resolvers (sling:org.apache.sling.resourceresolver.unclosedResourceResolvers)
---
 bnd.bnd                                            |   1 +
 pom.xml                                            |   6 +
 .../impl/CommonResourceResolverFactoryImpl.java    |  11 +-
 .../impl/ResourceResolverFactoryActivator.java     |  17 ++-
 .../impl/ResourceResolverMetrics.java              | 133 +++++++++++++++++++++
 .../resourceresolver/impl/mapping/MapEntries.java  |  21 +++-
 .../impl/EtcMappingResourceResolverTest.java       |   5 +
 .../impl/ResourceResolverMetricsTest.java          |  70 +++++++++++
 .../mapping/AbstractMappingMapEntriesTest.java     |   6 +-
 .../impl/mapping/EtcMappingMapEntriesTest.java     |   4 +
 .../impl/mapping/MapEntriesTest.java               |  13 +-
 .../impl/mapping/ResourceMapperImplTest.java       |   5 +-
 12 files changed, 273 insertions(+), 19 deletions(-)

diff --git a/bnd.bnd b/bnd.bnd
index abe9d05..d4d7e52 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -1,5 +1,6 @@
 Import-Package:\
   javax.jcr;resolution:=optional,\
+  org.apache.sling.commons.metrics;resolution:=optional,\
   *
 
 Provide-Capability:\
diff --git a/pom.xml b/pom.xml
index daa5eee..75768f9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -149,6 +149,12 @@
             <artifactId>annotations</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.metrics</artifactId>
+            <version>1.2.8</version>
+            <scope>provided</scope>
+        </dependency>
 
         <!-- For the Console Plugin of the ResourceResolverFactoryImpl -->
         <dependency>
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java b/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
index d9b6c08..4c6cfce 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
@@ -101,7 +101,7 @@ public class CommonResourceResolverFactoryImpl implements ResourceResolverFactor
                 while (isLive()) {
                     try {
                         final ResolverReference ref = (ResolverReference) resolverReferenceQueue.remove();
-                        ref.close();
+                        ref.close(activator.getResourceResolverMetrics());
                     } catch ( final InterruptedException ie) {
                         Thread.currentThread().interrupt();
                     }
@@ -315,7 +315,7 @@ public class CommonResourceResolverFactoryImpl implements ResourceResolverFactor
         }
         // set up the map entries from configuration
         try {
-            mapEntries = new MapEntries(this, bundleContext, this.activator.getEventAdmin(), this.activator.getStringInterpolationProvider());
+            mapEntries = new MapEntries(this, bundleContext, this.activator.getEventAdmin(), this.activator.getStringInterpolationProvider(), this.activator.getResourceResolverMetrics());
         } catch (final Exception e) {
             logger.error("activate: Cannot access repository, failed setting up Mapping Support", e);
         }
@@ -345,7 +345,7 @@ public class CommonResourceResolverFactoryImpl implements ResourceResolverFactor
         final Collection<ResolverReference> references = new ArrayList<>(refs.values());
         refs.clear();
         for(final ResolverReference ref : references) {
-            ref.close();
+            ref.close(activator.getResourceResolverMetrics());
         }
     }
 
@@ -538,11 +538,14 @@ public class CommonResourceResolverFactoryImpl implements ResourceResolverFactor
             this.openingException = factory.logUnclosedResolvers && LOG.isInfoEnabled() ? new Exception("Opening Stacktrace") : null;
         }
 
-        public void close() {
+        public void close(Optional<ResourceResolverMetrics> metrics) {
             try {
                 if (factory.unregisterControl(this.control) && factory.logUnclosedResolvers) {
                     if (factory.isLive()) {
                         LOG.warn("Closed unclosed ResourceResolver. The creation stacktrace is available on info log level.");
+                        if (metrics.isPresent()) {
+                            metrics.get().reportUnclosedResourceResolver();
+                        }
                     } else {
                         LOG.warn("Forced close of ResourceResolver because the ResourceResolverFactory is shutting down.");
                     }
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
index f2feca6..8dc71b4 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
@@ -51,6 +51,7 @@ import org.osgi.service.component.annotations.Modified;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
 import org.osgi.service.event.EventAdmin;
 import org.osgi.service.metatype.annotations.Designate;
 import org.slf4j.Logger;
@@ -113,6 +114,10 @@ public class ResourceResolverFactoryActivator {
 
     @Reference
     ResourceAccessSecurityTracker resourceAccessSecurityTracker;
+    
+    @SuppressWarnings("java:S3077")
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = ReferencePolicyOption.GREEDY, policy = ReferencePolicy.DYNAMIC)
+    private volatile ResourceResolverMetrics metrics;
 
     volatile ResourceProviderTracker resourceProviderTracker;
 
@@ -158,6 +163,10 @@ public class ResourceResolverFactoryActivator {
     public StringInterpolationProvider getStringInterpolationProvider() {
         return stringInterpolationProvider;
     }
+    
+    public Optional<ResourceResolverMetrics> getResourceResolverMetrics() {
+        return Optional.ofNullable(this.metrics);
+    }
 
     /**
      * This method is called from {@link MapEntries}
@@ -187,7 +196,7 @@ public class ResourceResolverFactoryActivator {
     }
 
     public boolean isMapConfiguration(String path) {
-        return path.equals(this.mapRoot)
+        return path.equals(this.getMapRoot())
                || path.startsWith(this.mapRootPrefix);
     }
 
@@ -526,7 +535,7 @@ public class ResourceResolverFactoryActivator {
                         }
                         final ResourceResolverFactoryImpl r = new ResourceResolverFactoryImpl(
                                 local.commonFactory, bundle,
-                            ResourceResolverFactoryActivator.this.serviceUserMapper);
+                            ResourceResolverFactoryActivator.this.getServiceUserMapper());
                         return r;
                     }
 
@@ -548,7 +557,7 @@ public class ResourceResolverFactoryActivator {
      * @return The runtime service
      */
     public RuntimeService getRuntimeService() {
-        return new RuntimeServiceImpl(this.resourceProviderTracker);
+        return new RuntimeServiceImpl(this.getResourceProviderTracker());
     }
 
     public ServiceUserMapper getServiceUserMapper() {
@@ -563,7 +572,7 @@ public class ResourceResolverFactoryActivator {
      * Check the preconditions and if it changed, either register factory or unregister
      */
     private void checkFactoryPreconditions(final String unavailableName, final String unavailableServicePid) {
-        final BundleContext localContext = this.bundleContext;
+        final BundleContext localContext = this.getBundleContext();
         if ( localContext != null ) {
             final boolean result = this.preconds.checkPreconditions(unavailableName, unavailableServicePid);
             if ( result && this.factoryRegistration == null ) {
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetrics.java b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetrics.java
new file mode 100644
index 0000000..1476987
--- /dev/null
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetrics.java
@@ -0,0 +1,133 @@
+/*
+ * 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.sling.resourceresolver.impl;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.function.Supplier;
+
+import org.apache.sling.commons.metrics.Counter;
+import org.apache.sling.commons.metrics.Gauge;
+import org.apache.sling.commons.metrics.MetricsService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ *  Export metrics for the resource resolver bundle:
+ *  
+ *  org.apache.sling.resourceresolver.numberOfVanityPaths - the total number of vanity paths
+ *  org.apache.sling.resourceresolver.numberOfAliases  -- the total number of aliases
+ *  org.apache.sling.resourceresolver.unclosedResourceResolvers  -- the total number of unclosed resource resolvers
+ *
+ */
+
+
+@Component(service=ResourceResolverMetrics.class)
+public class ResourceResolverMetrics {
+    
+    protected static final String METRICS_PREFIX = "org.apache.sling.resourceresolver";
+    
+    @Reference
+    MetricsService metricsService;
+    
+    private static final Supplier<Long> ZERO_SUPPLIER = () -> 0L;
+    
+    // number of vanity paths
+    private ServiceRegistration<Gauge<Long>> numberOfVanityPathsGauge;
+    private Supplier<Long> numberOfVanityPathsSupplier = ZERO_SUPPLIER;
+    
+    // number of aliases
+    private ServiceRegistration<Gauge<Long>> numberOfAliasesGauge;
+    private Supplier<Long> numberOfAliasesSupplier = ZERO_SUPPLIER;
+    
+    private Counter unclosedResourceResolvers;
+    
+    
+    @Activate
+    protected void activate(BundleContext bundleContext) {
+        numberOfVanityPathsGauge = registerGauge(bundleContext, METRICS_PREFIX + ".numberOfVanityPaths", () -> numberOfVanityPathsSupplier );
+        numberOfAliasesGauge = registerGauge(bundleContext, METRICS_PREFIX + ".numberOfAliases", () -> numberOfAliasesSupplier );
+        unclosedResourceResolvers = metricsService.counter(METRICS_PREFIX  + ".unclosedResourceResolvers");
+    }
+    
+    @Deactivate
+    protected void deactivate() {
+        numberOfVanityPathsGauge.unregister();
+        numberOfAliasesGauge.unregister();
+    }
+    
+    /**
+     * Set the number of vanity paths in the system
+     * @param supplier a supplier returning the number of vanity paths
+     */
+    public void setNumberOfVanityPathsSupplier(Supplier<Long> supplier) {
+        numberOfVanityPathsSupplier = supplier;
+    }
+    
+    /**
+     * Set the number of aliases in the system
+     * @param supplier a supplier returning the number of aliases
+     */
+    public void setNumberOfAliasesSupplier(Supplier<Long> supplier) {
+        numberOfAliasesSupplier = supplier;
+    }
+    
+    /**
+     * Increment the counter for the number of unresolved resource resolvers
+     */
+    public void reportUnclosedResourceResolver() {
+        unclosedResourceResolvers.increment();
+    }
+    
+    /**
+     * Create a gauge metrics.
+     *
+     * Sling Metrics does not directly offer a gauge as any other type, but only a whiteboard approach
+     * @param context the bundlecontext
+     * @param name the name of the metric
+     * @param supplier a supplier returning a supplier returning the requested value
+     * @return the ServiceRegistration for this metric (must be unregistered!)
+     */
+    @SuppressWarnings("unchecked")
+    private ServiceRegistration<Gauge<Long>> registerGauge(BundleContext context, String name, Supplier<Supplier<Long>> supplier) {
+
+        ResourceResolverGauge gauge = new ResourceResolverGauge(supplier);
+        @SuppressWarnings("all")
+        Dictionary props = new Hashtable();
+        props.put(Gauge.NAME, name);
+        return context.registerService(Gauge.class, gauge, props);
+    }
+
+    public class ResourceResolverGauge implements Gauge<Long> {
+        Supplier<Supplier<Long>> supplier;
+
+        public ResourceResolverGauge(Supplier<Supplier<Long>> supplier) {
+            this.supplier = supplier;
+        }
+
+        @Override
+        public Long getValue() {
+            return supplier.get().get();
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
index 9568dab..01c4df3 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
@@ -26,6 +26,7 @@ import org.apache.sling.api.resource.observation.ResourceChange;
 import org.apache.sling.api.resource.observation.ResourceChangeListener;
 import org.apache.sling.api.resource.path.Path;
 import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
+import org.apache.sling.resourceresolver.impl.ResourceResolverMetrics;
 import org.apache.sling.resourceresolver.impl.mapping.MapConfigurationProvider.VanityPathConfig;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -91,7 +92,7 @@ public class MapEntries implements
 
     private static final String JCR_SYSTEM_PREFIX = JCR_SYSTEM_PATH + '/';
 
-   static final String ALIAS_BASE_QUERY_DEFAULT = "SELECT sling:alias FROM nt:base AS page";
+    static final String ALIAS_BASE_QUERY_DEFAULT = "SELECT sling:alias FROM nt:base AS page";
 
     static final String ANY_SCHEME_HOST = "[^/]+/[^/]+";
 
@@ -103,6 +104,8 @@ public class MapEntries implements
     private volatile ResourceResolver resolver;
 
     private volatile EventAdmin eventAdmin;
+    
+    private Optional<ResourceResolverMetrics> metrics;
 
     private volatile ServiceRegistration<ResourceChangeListener> registration;
 
@@ -130,13 +133,19 @@ public class MapEntries implements
 
     private final boolean useOptimizeAliasResolution;
 
-    public MapEntries(final MapConfigurationProvider factory, final BundleContext bundleContext, final EventAdmin eventAdmin, final StringInterpolationProvider stringInterpolationProvider)
-        throws LoginException, IOException {
+    public MapEntries(final MapConfigurationProvider factory, 
+            final BundleContext bundleContext, 
+            final EventAdmin eventAdmin, 
+            final StringInterpolationProvider stringInterpolationProvider, 
+            final Optional<ResourceResolverMetrics> metrics) 
+                    throws LoginException, IOException {
 
     	this.resolver = factory.getServiceResourceResolver(factory.getServiceUserAuthenticationInfo("mapping"));
         this.factory = factory;
         this.eventAdmin = eventAdmin;
 
+
+
         this.resolveMapsMap = Collections.singletonMap(GLOBAL_LIST_KEY, Collections.emptyList());
         this.mapMaps = Collections.<MapEntry> emptyList();
         this.vanityTargets = Collections.<String,List <String>>emptyMap();
@@ -157,8 +166,14 @@ public class MapEntries implements
         this.registration = bundleContext.registerService(ResourceChangeListener.class, this, props);
 
         this.vanityCounter = new AtomicLong(0);
+
         this.vanityBloomFilterFile = bundleContext.getDataFile(VANITY_BLOOM_FILTER_NAME);
         initializeVanityPaths();
+        this.metrics = metrics;
+        if (metrics.isPresent()) {
+            this.metrics.get().setNumberOfVanityPathsSupplier(vanityCounter::get);
+            this.metrics.get().setNumberOfAliasesSupplier(() -> (long) aliasMap.size());
+        }
     }
 
     /**
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/EtcMappingResourceResolverTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/EtcMappingResourceResolverTest.java
index ca2d6a6..3a19ce1 100644
--- a/src/test/java/org/apache/sling/resourceresolver/impl/EtcMappingResourceResolverTest.java
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/EtcMappingResourceResolverTest.java
@@ -85,6 +85,9 @@ public class EtcMappingResourceResolverTest {
 
     @Mock
     EventAdmin eventAdmin;
+    
+    @Mock
+    ResourceResolverMetrics metrics;
 
     @Mock
     ResourceResolver resourceResolver;
@@ -128,6 +131,8 @@ public class EtcMappingResourceResolverTest {
         setInaccessibleField("mapRoot", activator, "/etc/map");
         setInaccessibleField("mapRootPrefix", activator, "/etc/map");
         setInaccessibleField("observationPaths", activator, new Path[] {new Path("/")});
+        setInaccessibleField("metrics", activator, metrics);
+        
         ServiceUserMapper serviceUserMapper = mock(ServiceUserMapper.class);
         setInaccessibleField("serviceUserMapper", activator, serviceUserMapper);
         commonFactory = spy(new CommonResourceResolverFactoryImpl(activator));
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetricsTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetricsTest.java
new file mode 100644
index 0000000..b21ca73
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetricsTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.sling.resourceresolver.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.CoreMatchers.is;
+
+import org.apache.sling.commons.metrics.Gauge;
+import org.apache.sling.commons.metrics.MetricsService;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class ResourceResolverMetricsTest {
+    
+    @Rule
+    public OsgiContext context = new OsgiContext();
+    
+    private MetricsService metricsService;
+    
+    private ResourceResolverMetrics metrics;
+    
+    @Before
+    public void setup() {
+        metrics = new ResourceResolverMetrics();
+        metricsService = Mockito.mock(MetricsService.class);
+        context.registerService(MetricsService.class, metricsService);
+        context.registerInjectActivateService(metrics);
+    }
+    
+    @Test
+    public void testGauges() {
+        Gauge<Long> vanityPaths =  getGauge(ResourceResolverMetrics.METRICS_PREFIX + ".numberOfVanityPaths");
+        Gauge<Long> aliases = getGauge(ResourceResolverMetrics.METRICS_PREFIX + ".numberOfAliases");
+        assertThat(vanityPaths.getValue(),is(0L));
+        assertThat(aliases.getValue(),is(0L));
+        
+        metrics.setNumberOfAliasesSupplier(() -> 3L);
+        metrics.setNumberOfVanityPathsSupplier(() -> 2L);
+        assertThat(vanityPaths.getValue(),is(2L));
+        assertThat(aliases.getValue(),is(3L));
+        
+    }
+    
+    private Gauge<Long> getGauge(String name) {
+        String filter = String.format("(%s=%s)", Gauge.NAME,name);
+        Gauge<Long>[] result = context.getServices(Gauge.class,filter);
+        assertThat(result.length,is(1));
+        return result[0];
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AbstractMappingMapEntriesTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AbstractMappingMapEntriesTest.java
index 44e04a9..f17ef2b 100644
--- a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AbstractMappingMapEntriesTest.java
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/AbstractMappingMapEntriesTest.java
@@ -23,6 +23,7 @@ import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.api.resource.path.Path;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.resourceresolver.impl.ResourceResolverMetrics;
 import org.junit.After;
 import org.junit.Before;
 import org.mockito.Mock;
@@ -41,6 +42,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
@@ -76,6 +78,8 @@ public abstract class AbstractMappingMapEntriesTest {
 
     @Mock
     EventAdmin eventAdmin;
+    
+    Optional<ResourceResolverMetrics> metrics = Optional.empty();
 
     @Mock
     ResourceResolver resourceResolver;
@@ -118,7 +122,7 @@ public abstract class AbstractMappingMapEntriesTest {
 
         stringInterpolationProviderConfiguration = createStringInterpolationProviderConfiguration();
         setupStringInterpolationProvider(stringInterpolationProvider, stringInterpolationProviderConfiguration, new String[] {});
-        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider);
+        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider, metrics);
 
         final Field aliasMapField = MapEntries.class.getDeclaredField("aliasMap");
         aliasMapField.setAccessible(true);
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/EtcMappingMapEntriesTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/EtcMappingMapEntriesTest.java
index a98ca6e..a9e390e 100644
--- a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/EtcMappingMapEntriesTest.java
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/EtcMappingMapEntriesTest.java
@@ -23,6 +23,7 @@ import org.apache.sling.resourceresolver.impl.CommonResourceResolverFactoryImpl;
 import org.apache.sling.resourceresolver.impl.ResourceAccessSecurityTracker;
 import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryActivator;
 import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.ResourceResolverMetrics;
 import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
 import org.apache.sling.resourceresolver.impl.providers.ResourceProviderStorage;
 import org.apache.sling.resourceresolver.impl.providers.ResourceProviderTracker;
@@ -31,6 +32,7 @@ import org.apache.sling.spi.resource.provider.ResolveContext;
 import org.apache.sling.spi.resource.provider.ResourceContext;
 import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 
@@ -38,6 +40,7 @@ import javax.servlet.http.HttpServletRequest;
 import java.lang.reflect.Method;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 
 import static java.util.Arrays.asList;
 import static org.apache.sling.resourceresolver.impl.MockedResourceResolverImplTest.createRPHandler;
@@ -180,6 +183,7 @@ public class EtcMappingMapEntriesTest extends AbstractMappingMapEntriesTest {
         when(activator.getStringInterpolationProvider()).thenReturn(stringInterpolationProvider);
         when(activator.getMapRoot()).thenReturn("/etc/map");
         when(activator.getObservationPaths()).thenReturn(new Path[] {new Path("/")});
+        when(activator.getResourceResolverMetrics()).thenReturn(Optional.of(Mockito.mock(ResourceResolverMetrics.class)));
         CommonResourceResolverFactoryImpl commonFactory = spy(new CommonResourceResolverFactoryImpl(activator));
         when(bundleContext.getBundle()).thenReturn(bundle);
         ServiceUserMapper serviceUserMapper = mock(ServiceUserMapper.class);
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
index cc2c670..ceda30a 100644
--- a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesTest.java
@@ -46,6 +46,7 @@ import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
 import org.apache.sling.api.resource.path.Path;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
 import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
+import org.apache.sling.resourceresolver.impl.ResourceResolverMetrics;
 import org.apache.sling.resourceresolver.impl.mapping.MapConfigurationProvider.VanityPathConfig;
 import org.junit.After;
 import org.junit.Before;
@@ -124,8 +125,10 @@ public class MapEntriesTest extends AbstractMappingMapEntriesTest {
           aliasPath.add("/parent"+i);
         }
         when(resourceResolverFactory.getAllowedAliasLocations()).thenReturn(aliasPath);
+        
+        Optional<ResourceResolverMetrics> metrics = Optional.empty();
 
-        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider);
+        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider, metrics);
         final Field aliasMapField = MapEntries.class.getDeclaredField("aliasMap");
         aliasMapField.setAccessible(true);
 
@@ -817,7 +820,7 @@ public class MapEntriesTest extends AbstractMappingMapEntriesTest {
         addResource.setAccessible(true);
 
         when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(false);
-        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider);
+        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider, metrics);
 
         Resource parent = mock(Resource.class);
         when(parent.getPath()).thenReturn("/parent");
@@ -842,7 +845,7 @@ public class MapEntriesTest extends AbstractMappingMapEntriesTest {
         addResource.setAccessible(true);
 
         when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(false);
-        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider);
+        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider, metrics);
 
         Resource parent = mock(Resource.class);
         when(parent.getPath()).thenReturn("/parent");
@@ -867,7 +870,7 @@ public class MapEntriesTest extends AbstractMappingMapEntriesTest {
         removeAlias.setAccessible(true);
 
         when(resourceResolverFactory.isOptimizeAliasResolutionEnabled()).thenReturn(false);
-        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider);
+        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider, metrics);
 
         Resource parent = mock(Resource.class);
         when(parent.getPath()).thenReturn("/parent");
@@ -2195,7 +2198,7 @@ public class MapEntriesTest extends AbstractMappingMapEntriesTest {
         // initialize with having vanity path disabled - must not throw errors here or on disposal
         when(resourceResolverFactory.isVanityPathEnabled()).thenReturn(false);
 
-        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider);
+        mapEntries = new MapEntries(resourceResolverFactory, bundleContext, eventAdmin, stringInterpolationProvider, metrics);
 
         mapEntries.doInit();
     }
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
index ee9a3be..9608601 100644
--- a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
@@ -42,6 +42,7 @@ import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.mapping.ResourceMapper;
 import org.apache.sling.resourceresolver.impl.ResourceAccessSecurityTracker;
 import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryActivator;
+import org.apache.sling.resourceresolver.impl.ResourceResolverMetrics;
 import org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl;
 import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
@@ -52,6 +53,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
+import org.mockito.Mockito;
 
 /**
  * Validates that the {@link ResourceMapperImpl} correctly queries all sources of mappings
@@ -78,8 +80,7 @@ public class ResourceMapperImplTest {
     public static Object[] data() {
         return new Object[] { false, true};
     }
-
-
+    
     @Rule
     public final OsgiContext ctx = new OsgiContext();