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/11/30 17:00:43 UTC

[sling-org-apache-sling-resourceresolver] branch improvement/SLING-10945-mapping-metrics created (now 79c8122)

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

joerghoh pushed a change to branch improvement/SLING-10945-mapping-metrics
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git.


      at 79c8122  SLING-10945 add metrics

This branch includes the following new commits:

     new 79c8122  SLING-10945 add metrics

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[sling-org-apache-sling-resourceresolver] 01/01: SLING-10945 add metrics

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

joerghoh pushed a commit to branch improvement/SLING-10945-mapping-metrics
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git

commit 79c812238d6e7fc8911e2ad5e8f8b9cbdbb15070
Author: Joerg Hoh <jh...@adobe.com>
AuthorDate: Tue Nov 30 17:59:55 2021 +0100

    SLING-10945 add metrics
---
 pom.xml                                            |   5 +
 .../impl/CommonResourceResolverFactoryImpl.java    |   9 +-
 .../impl/ResourceResolverFactoryActivator.java     |  15 ++-
 .../impl/ResourceResolverMetrics.java              | 119 +++++++++++++++++++++
 .../resourceresolver/impl/mapping/MapEntries.java  |  15 ++-
 .../impl/EtcMappingResourceResolverTest.java       |   5 +
 .../impl/ResourceResolverMetricsTest.java          |  75 +++++++++++++
 .../mapping/AbstractMappingMapEntriesTest.java     |   6 +-
 .../impl/mapping/EtcMappingMapEntriesTest.java     |   3 +
 .../impl/mapping/MapEntriesTest.java               |  14 ++-
 .../impl/mapping/ResourceMapperImplTest.java       |   6 +-
 11 files changed, 254 insertions(+), 18 deletions(-)

diff --git a/pom.xml b/pom.xml
index daa5eee..88ad4a0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -149,6 +149,11 @@
             <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>
+        </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..a5a526f 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,12 @@ public class CommonResourceResolverFactoryImpl implements ResourceResolverFactor
             this.openingException = factory.logUnclosedResolvers && LOG.isInfoEnabled() ? new Exception("Opening Stacktrace") : null;
         }
 
-        public void close() {
+        public void close(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.");
+                        metrics.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..c7335a6 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
@@ -113,6 +113,9 @@ public class ResourceResolverFactoryActivator {
 
     @Reference
     ResourceAccessSecurityTracker resourceAccessSecurityTracker;
+    
+    @Reference
+    private ResourceResolverMetrics metrics;
 
     volatile ResourceProviderTracker resourceProviderTracker;
 
@@ -158,6 +161,10 @@ public class ResourceResolverFactoryActivator {
     public StringInterpolationProvider getStringInterpolationProvider() {
         return stringInterpolationProvider;
     }
+    
+    public ResourceResolverMetrics getResourceResolverMetrics() {
+        return this.metrics;
+    }
 
     /**
      * This method is called from {@link MapEntries}
@@ -187,7 +194,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 +533,7 @@ public class ResourceResolverFactoryActivator {
                         }
                         final ResourceResolverFactoryImpl r = new ResourceResolverFactoryImpl(
                                 local.commonFactory, bundle,
-                            ResourceResolverFactoryActivator.this.serviceUserMapper);
+                            ResourceResolverFactoryActivator.this.getServiceUserMapper());
                         return r;
                     }
 
@@ -548,7 +555,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 +570,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..bab2a5f
--- /dev/null
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetrics.java
@@ -0,0 +1,119 @@
+/*
+ * 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.ComponentContext;
+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;
+
+@Component(service=ResourceResolverMetrics.class, immediate=true)
+public class ResourceResolverMetrics {
+    
+    @Reference
+    MetricsService metricsService;
+    
+    Supplier<Long> NULL_SUPPLIER = () -> { return 0L; };
+    
+    // number of vanity paths
+    private ServiceRegistration<Gauge<Long>> numberOfVanityPathsGauge;
+    private Supplier<Long> numberOfVanityPathsSupplier = NULL_SUPPLIER;
+    
+    // number of aliases
+    private ServiceRegistration<Gauge<Long>> numberOfAliasesGauge;
+    private Supplier<Long> numberOfAliasesSupplier = NULL_SUPPLIER;
+    
+    private Counter unclosedResourceResolvers;
+    
+    
+    @Activate
+    protected void activate(ComponentContext context) {
+        BundleContext bundleContext = context.getBundleContext();
+        numberOfVanityPathsGauge = registerGauge(bundleContext, "numberOfVanityPaths", () -> { return numberOfVanityPathsSupplier;} );
+        numberOfAliasesGauge = registerGauge(bundleContext, "numberOfAliases", () -> {return numberOfAliasesSupplier;} );
+        unclosedResourceResolvers = metricsService.counter("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;
+    }
+    
+    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);
+        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..a9cd5a8 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;
@@ -103,6 +104,8 @@ public class MapEntries implements
     private volatile ResourceResolver resolver;
 
     private volatile EventAdmin eventAdmin;
+    
+    private volatile ResourceResolverMetrics metrics;
 
     private volatile ServiceRegistration<ResourceChangeListener> registration;
 
@@ -130,12 +133,17 @@ 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 ResourceResolverMetrics metrics) throws LoginException, IOException {
 
     	this.resolver = factory.getServiceResourceResolver(factory.getServiceUserAuthenticationInfo("mapping"));
         this.factory = factory;
         this.eventAdmin = eventAdmin;
+        this.metrics = metrics;
+
 
         this.resolveMapsMap = Collections.singletonMap(GLOBAL_LIST_KEY, Collections.emptyList());
         this.mapMaps = Collections.<MapEntry> emptyList();
@@ -157,8 +165,11 @@ 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();
+        metrics.setNumberOfVanityPathsSupplier(() -> { return vanityCounter.get();});
+        metrics.setNumberOfAliasesSupplier(() -> { return (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..e00fc86
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverMetricsTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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("numberOfVanityPaths");
+        Gauge<Long> aliases = getGauge("numberOfAliases");
+        assertThat(vanityPaths.getValue(),is(0L));
+        assertThat(aliases.getValue(),is(0L));
+        
+        metrics.setNumberOfAliasesSupplier(() -> {return 3L;});
+        metrics.setNumberOfVanityPathsSupplier(() -> {return 2L;});
+        assertThat(vanityPaths.getValue(),is(2L));
+        assertThat(aliases.getValue(),is(3L));
+        
+    }
+    
+    @Test
+    public void testCounter() {
+        
+    }
+    
+    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..0d4b389 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;
@@ -76,6 +77,9 @@ public abstract class AbstractMappingMapEntriesTest {
 
     @Mock
     EventAdmin eventAdmin;
+    
+    @Mock
+    ResourceResolverMetrics metrics;
 
     @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..2402fcf 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;
 
@@ -180,6 +182,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(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..3963648 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;
@@ -73,6 +74,9 @@ public class MapEntriesTest extends AbstractMappingMapEntriesTest {
 
     @Mock
     private Bundle bundle;
+    
+    @Mock
+    private ResourceResolverMetrics metrics;
 
     @Mock
     private ResourceResolver resourceResolver;
@@ -125,7 +129,7 @@ public class MapEntriesTest extends AbstractMappingMapEntriesTest {
         }
         when(resourceResolverFactory.getAllowedAliasLocations()).thenReturn(aliasPath);
 
-        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 +821,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 +846,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 +871,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 +2199,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..69f9283 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();
 
@@ -94,6 +95,7 @@ public class ResourceMapperImplTest {
     @Before
     public void prepare() throws LoginException {
 
+        ctx.registerService(ResourceResolverMetrics.class, Mockito.mock(ResourceResolverMetrics.class));
         ctx.registerInjectActivateService(new ServiceUserMapperImpl());
         ctx.registerInjectActivateService(new ResourceAccessSecurityTracker());
         ctx.registerInjectActivateService(new StringInterpolationProviderImpl());