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

frankgh pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 9a268ace CASSANDRASC-115 Add FilteringMetricRegistry to allow 
filtering of metrics (#109)
9a268ace is described below

commit 9a268ace28e5864f443ce0cb2768974b5b12fd3a
Author: Saranya Krishnakumar <sarany...@apple.com>
AuthorDate: Wed Apr 10 20:49:29 2024 -0700

    CASSANDRASC-115 Add FilteringMetricRegistry to allow filtering of metrics 
(#109)
    
    
    Patch by Saranya Krishnakumar; Reviewed by Yifan Cai, Francisco Guerrero 
for CASSANDRASC-115
---
 CHANGES.txt                                        |   1 +
 src/main/dist/conf/sidecar.yaml                    |  10 +-
 .../cluster/instance/InstanceMetadataImpl.java     |  23 +--
 .../sidecar/config/MetricsConfiguration.java       |  12 ++
 ...ion.java => MetricsFilteringConfiguration.java} |  12 +-
 .../config/yaml/MetricsConfigurationImpl.java      |  36 +++-
 .../yaml/MetricsFilteringConfigurationImpl.java    |  82 ++++++++
 .../sidecar/metrics/FilteringMetricRegistry.java   | 225 +++++++++++++++++++++
 .../cassandra/sidecar/metrics/MetricFilter.java    |  97 +++++++++
 .../sidecar/metrics/MetricRegistryFactory.java     | 103 ++++++++++
 .../cassandra/sidecar/server/MainModule.java       |  22 +-
 .../testing/CassandraSidecarTestContext.java       |   7 +-
 .../sidecar/config/SidecarConfigurationTest.java   |  51 ++++-
 .../metrics/FilteringMetricRegistryTest.java       | 213 +++++++++++++++++++
 .../cassandra/sidecar/snapshots/SnapshotUtils.java |  10 +-
 .../resources/config/sidecar_invalid_metrics.yaml  |  47 +++++
 src/test/resources/config/sidecar_metrics.yaml     |  83 +++++---
 17 files changed, 960 insertions(+), 74 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 7a882552..43873923 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
 1.0.0
 -----
+ * Add FilteringMetricRegistry to allow filtering of metrics (CASSANDRASC-115)
  * Allow for JmxClient to be extensible (CASSANDRASC-116)
  * Improve observability in Sidecar (CASSANDRASC-111)
  * Improve logging for slice restore task (CASSANDRASC-107)
diff --git a/src/main/dist/conf/sidecar.yaml b/src/main/dist/conf/sidecar.yaml
index 2369f252..6d99f1db 100644
--- a/src/main/dist/conf/sidecar.yaml
+++ b/src/main/dist/conf/sidecar.yaml
@@ -148,8 +148,14 @@ metrics:
     enabled: true
     expose_via_jmx: false
     jmx_domain_name: sidecar.vertx.jmx_domain
-    monitored_server_route_regexes:                # regex list to match 
server routes
-     - /api/v1/.*
+  include:                                    # empty include list means 
include all
+    - type: "regex"                           # possible filter types are 
"regex" and "equals"
+      value: "sidecar.*"
+    - type: "regex"
+      value: "vertx.*"
+  exclude:                                    # empty exclude list means 
exclude nothing
+#    - type: "regex"                          # possible filter types are 
"regex" and "equals"
+#      value: "vertx.eventbus.*"              # exclude all metrics starts 
with vertx.eventbus
 
 cassandra_input_validation:
   forbidden_keyspaces:
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/cluster/instance/InstanceMetadataImpl.java
 
b/src/main/java/org/apache/cassandra/sidecar/cluster/instance/InstanceMetadataImpl.java
index d0e4fd97..1f909332 100644
--- 
a/src/main/java/org/apache/cassandra/sidecar/cluster/instance/InstanceMetadataImpl.java
+++ 
b/src/main/java/org/apache/cassandra/sidecar/cluster/instance/InstanceMetadataImpl.java
@@ -24,7 +24,6 @@ import java.util.List;
 import java.util.Objects;
 
 import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.SharedMetricRegistries;
 import org.apache.cassandra.sidecar.cluster.CassandraAdapterDelegate;
 import org.apache.cassandra.sidecar.common.DataObjectBuilder;
 import org.apache.cassandra.sidecar.metrics.instance.InstanceMetrics;
@@ -114,7 +113,7 @@ public class InstanceMetadataImpl implements 
InstanceMetadata
         protected List<String> dataDirs;
         protected String stagingDir;
         protected CassandraAdapterDelegate delegate;
-        protected String globalRegistryName;
+        protected MetricRegistry metricRegistry;
         protected InstanceMetrics metrics;
 
         protected Builder()
@@ -205,15 +204,14 @@ public class InstanceMetadataImpl implements 
InstanceMetadata
         }
 
         /**
-         * Sets the {@code globalRegistryName} and returns a reference to this 
Builder enabling method chaining.
+         * Sets the {@code metricRegistry} and returns a reference to this 
Builder enabling method chaining.
          *
-         * @param registryName global {@link 
com.codahale.metrics.MetricRegistry} name
+         * @param metricRegistry instance specific metric registry
          * @return a reference to this Builder
          */
-        public Builder globalMetricRegistryName(String registryName)
-
+        public Builder metricRegistry(MetricRegistry metricRegistry)
         {
-            return update(b -> b.globalRegistryName = registryName);
+            return update(b -> b.metricRegistry = metricRegistry);
         }
 
         /**
@@ -225,18 +223,11 @@ public class InstanceMetadataImpl implements 
InstanceMetadata
         public InstanceMetadataImpl build()
         {
             Objects.requireNonNull(id);
-            Objects.requireNonNull(globalRegistryName);
+            Objects.requireNonNull(metricRegistry);
 
-            String instanceRegistryName = 
instanceRegistryName(globalRegistryName);
-            MetricRegistry instanceMetricRegistry = 
SharedMetricRegistries.getOrCreate(instanceRegistryName);
-            metrics = new InstanceMetricsImpl(instanceMetricRegistry);
+            metrics = new InstanceMetricsImpl(metricRegistry);
 
             return new InstanceMetadataImpl(this);
         }
-
-        private String instanceRegistryName(String globalRegistryName)
-        {
-            return globalRegistryName + "_" + id;
-        }
     }
 }
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/config/MetricsConfiguration.java 
b/src/main/java/org/apache/cassandra/sidecar/config/MetricsConfiguration.java
index 2fc622a0..22518fed 100644
--- 
a/src/main/java/org/apache/cassandra/sidecar/config/MetricsConfiguration.java
+++ 
b/src/main/java/org/apache/cassandra/sidecar/config/MetricsConfiguration.java
@@ -18,6 +18,8 @@
 
 package org.apache.cassandra.sidecar.config;
 
+import java.util.List;
+
 /**
  * Configuration needed for capturing metrics.
  */
@@ -32,4 +34,14 @@ public interface MetricsConfiguration
      * @return configuration needed for capturing metrics released by Vert.x 
framework.
      */
     VertxMetricsConfiguration vertxConfiguration();
+
+    /**
+     * @return filters for metrics to be recorded
+     */
+    List<MetricsFilteringConfiguration> includeConfigurations();
+
+    /**
+     * @return filters for excluding metrics during capture
+     */
+    List<MetricsFilteringConfiguration> excludeConfigurations();
 }
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/config/MetricsConfiguration.java 
b/src/main/java/org/apache/cassandra/sidecar/config/MetricsFilteringConfiguration.java
similarity index 73%
copy from 
src/main/java/org/apache/cassandra/sidecar/config/MetricsConfiguration.java
copy to 
src/main/java/org/apache/cassandra/sidecar/config/MetricsFilteringConfiguration.java
index 2fc622a0..b64151e5 100644
--- 
a/src/main/java/org/apache/cassandra/sidecar/config/MetricsConfiguration.java
+++ 
b/src/main/java/org/apache/cassandra/sidecar/config/MetricsFilteringConfiguration.java
@@ -19,17 +19,17 @@
 package org.apache.cassandra.sidecar.config;
 
 /**
- * Configuration needed for capturing metrics.
+ * Configuration needed for filtering metrics captured.
  */
-public interface MetricsConfiguration
+public interface MetricsFilteringConfiguration
 {
     /**
-     * @return global registry name to be used for registering sidecar metrics
+     * @return type of metric filter. Possible values are regex, equals.
      */
-    String registryName();
+    String type();
 
     /**
-     * @return configuration needed for capturing metrics released by Vert.x 
framework.
+     * @return pattern supported by the filter.
      */
-    VertxMetricsConfiguration vertxConfiguration();
+    String value();
 }
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/config/yaml/MetricsConfigurationImpl.java
 
b/src/main/java/org/apache/cassandra/sidecar/config/yaml/MetricsConfigurationImpl.java
index fc60a6d2..53a4d0a2 100644
--- 
a/src/main/java/org/apache/cassandra/sidecar/config/yaml/MetricsConfigurationImpl.java
+++ 
b/src/main/java/org/apache/cassandra/sidecar/config/yaml/MetricsConfigurationImpl.java
@@ -18,8 +18,12 @@
 
 package org.apache.cassandra.sidecar.config.yaml;
 
+import java.util.Collections;
+import java.util.List;
+
 import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.cassandra.sidecar.config.MetricsConfiguration;
+import org.apache.cassandra.sidecar.config.MetricsFilteringConfiguration;
 import org.apache.cassandra.sidecar.config.VertxMetricsConfiguration;
 
 /**
@@ -35,16 +39,26 @@ public class MetricsConfigurationImpl implements 
MetricsConfiguration
     protected final String registryName;
     @JsonProperty(value = "vertx")
     protected final VertxMetricsConfiguration vertxConfiguration;
+    @JsonProperty(value = "include")
+    protected final List<MetricsFilteringConfiguration> includeConfigurations;
+    @JsonProperty(value = "exclude")
+    protected final List<MetricsFilteringConfiguration> excludeConfigurations;
 
     public MetricsConfigurationImpl()
     {
-        this(DEFAULT_DROPWIZARD_REGISTRY_NAME, 
DEFAULT_VERTX_METRICS_CONFIGURATION);
+        this(DEFAULT_DROPWIZARD_REGISTRY_NAME, 
DEFAULT_VERTX_METRICS_CONFIGURATION,
+             Collections.emptyList(), Collections.emptyList());
     }
 
-    public MetricsConfigurationImpl(String registryName, 
VertxMetricsConfiguration vertxConfiguration)
+    public MetricsConfigurationImpl(String registryName,
+                                    VertxMetricsConfiguration 
vertxConfiguration,
+                                    List<MetricsFilteringConfiguration> 
includeConfigurations,
+                                    List<MetricsFilteringConfiguration> 
excludeConfigurations)
     {
         this.registryName = registryName;
         this.vertxConfiguration = vertxConfiguration;
+        this.includeConfigurations = includeConfigurations;
+        this.excludeConfigurations = excludeConfigurations;
     }
 
     /**
@@ -64,4 +78,22 @@ public class MetricsConfigurationImpl implements 
MetricsConfiguration
     {
         return vertxConfiguration;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<MetricsFilteringConfiguration> includeConfigurations()
+    {
+        return includeConfigurations;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<MetricsFilteringConfiguration> excludeConfigurations()
+    {
+        return excludeConfigurations;
+    }
 }
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/config/yaml/MetricsFilteringConfigurationImpl.java
 
b/src/main/java/org/apache/cassandra/sidecar/config/yaml/MetricsFilteringConfigurationImpl.java
new file mode 100644
index 00000000..9024d6f8
--- /dev/null
+++ 
b/src/main/java/org/apache/cassandra/sidecar/config/yaml/MetricsFilteringConfigurationImpl.java
@@ -0,0 +1,82 @@
+/*
+ * 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.cassandra.sidecar.config.yaml;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.cassandra.sidecar.config.MetricsFilteringConfiguration;
+
+/**
+ * Holds configuration needed for filtering out metrics
+ */
+public class MetricsFilteringConfigurationImpl implements 
MetricsFilteringConfiguration
+{
+    public static final String REGEX_TYPE = "regex";
+    public static final String EQUALS_TYPE = "equals";
+    public static final String DEFAULT_TYPE = REGEX_TYPE;
+    public static final String DEFAULT_VALUE = ".*"; // include all metrics
+    private String type;
+    @JsonProperty("value")
+    private final String value;
+
+    public MetricsFilteringConfigurationImpl()
+    {
+        this(DEFAULT_TYPE, DEFAULT_VALUE);
+    }
+
+    public MetricsFilteringConfigurationImpl(String type, String value)
+    {
+        this.type = type;
+        verifyType(type);
+        this.value = value;
+    }
+
+    private void verifyType(String type)
+    {
+        if (REGEX_TYPE.equalsIgnoreCase(type) || 
EQUALS_TYPE.equalsIgnoreCase(type))
+        {
+            return;
+        }
+        throw new IllegalArgumentException(type + " passed for metric 
filtering is not recognized. Expected types are "
+                                           + REGEX_TYPE + " or " + 
EQUALS_TYPE);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String type()
+    {
+        return type;
+    }
+
+    @JsonProperty(value = "type")
+    public void setType(String type)
+    {
+        verifyType(type);
+        this.type = type;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String value()
+    {
+        return value;
+    }
+}
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/metrics/FilteringMetricRegistry.java
 
b/src/main/java/org/apache/cassandra/sidecar/metrics/FilteringMetricRegistry.java
new file mode 100644
index 00000000..ad08b58b
--- /dev/null
+++ 
b/src/main/java/org/apache/cassandra/sidecar/metrics/FilteringMetricRegistry.java
@@ -0,0 +1,225 @@
+/*
+ * 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.cassandra.sidecar.metrics;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.NoopMetricRegistry;
+import com.codahale.metrics.Timer;
+
+/**
+ * Allows filtering of metrics based on configured allow list. Metrics are 
filtered out before registering them.
+ */
+public class FilteringMetricRegistry extends MetricRegistry
+{
+    private static final NoopMetricRegistry NO_OP_METRIC_REGISTRY = new 
NoopMetricRegistry(); // supplies no-op metrics
+    private final Predicate<String> isAllowed;
+    private final Map<String, Metric> excludedMetrics = new 
ConcurrentHashMap<>();
+
+    public FilteringMetricRegistry(Predicate<String> isAllowedPredicate)
+    {
+        this.isAllowed = new CachedPredicate(isAllowedPredicate);
+    }
+
+    @Override
+    public Counter counter(String name)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.counter(name);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::counter), Counter.class);
+    }
+
+    @Override
+    public Counter counter(String name, MetricSupplier<Counter> supplier)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.counter(name, supplier);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::counter), Counter.class);
+    }
+
+    @Override
+    public Histogram histogram(String name)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.histogram(name);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::histogram), Histogram.class);
+    }
+
+    @Override
+    public Histogram histogram(String name, MetricSupplier<Histogram> supplier)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.histogram(name, supplier);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::histogram), Histogram.class);
+    }
+
+    @Override
+    public Meter meter(String name)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.meter(name);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::meter), Meter.class);
+    }
+
+    @Override
+    public Meter meter(String name, MetricSupplier<Meter> supplier)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.meter(name, supplier);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::meter), Meter.class);
+    }
+
+    @Override
+    public Timer timer(String name)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.timer(name);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::timer), Timer.class);
+    }
+
+    @Override
+    public Timer timer(String name, MetricSupplier<Timer> supplier)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.timer(name, supplier);
+        }
+        return typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::timer), Timer.class);
+    }
+
+    @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public <T extends Gauge> T gauge(String name)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.gauge(name);
+        }
+        return (T) typeChecked(excludedMetrics.computeIfAbsent(name, 
NO_OP_METRIC_REGISTRY::gauge), Gauge.class);
+    }
+
+    @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public <T extends Gauge> T gauge(String name, MetricSupplier<T> supplier)
+    {
+        if (isAllowed.test(name))
+        {
+            return super.gauge(name, supplier);
+        }
+        return (T) typeChecked(excludedMetrics.computeIfAbsent(name, k -> 
supplier.newMetric() /* unregistered metric */), Gauge.class);
+    }
+
+    /**
+     * @return all the metrics including the allowed and disallowed metrics. 
This is to prevent re-registering of
+     * excluded metrics
+     */
+    @Override
+    public Map<String, Metric> getMetrics()
+    {
+        Map<String, Metric> allMetrics = new HashMap<>();
+        allMetrics.putAll(super.getMetrics());
+        allMetrics.putAll(excludedMetrics);
+        return Collections.unmodifiableMap(allMetrics);
+    }
+
+    /**
+     * @return metrics registered with {@code super.register()}. This will be 
useful for testing purposes to check
+     * what metrics are actually captured
+     */
+    public Map<String, Metric> getIncludedMetrics()
+    {
+        return super.getMetrics();
+    }
+
+    /**
+     * Metric specific retrieve methods such as {@code counter(name)} retrieve 
a noop instance if metric is filtered.
+     * Prefer calling those over register method, register method returns an 
unregistered metric if the metric is
+     * filtered. In some cases Noop metric instance has a performance 
advantage.
+     */
+    public <T extends Metric> T register(String name, T metric) throws 
IllegalArgumentException
+    {
+        if (metric == null)
+        {
+            throw new IllegalArgumentException("Metric can not be null");
+        }
+
+        // The metric is registered by calling the register() directly
+        // We need to test whether it is allowed first
+        if (isAllowed.test(name))
+        {
+            return super.register(name, metric);
+        }
+
+        return (T) typeChecked(excludedMetrics.computeIfAbsent(name, key -> 
metric), metric.getClass());
+    }
+
+    private <T extends Metric> T typeChecked(Metric metric, Class<T> type)
+    {
+        if (type.isInstance(metric))
+        {
+            return (T) metric;
+        }
+        throw new IllegalArgumentException("Metric already present with type " 
+ metric.getClass());
+    }
+
+    /**
+     * {@link CachedPredicate} remembers results of the {@link Predicate} it 
maintains. This is to avoid
+     * redundant calls to delegate predicate.
+     */
+    static class CachedPredicate implements Predicate<String>
+    {
+        private final Predicate<String> delegate;
+        private final Map<String, Boolean> results = new ConcurrentHashMap<>();
+
+        CachedPredicate(Predicate<String> delegate)
+        {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public boolean test(String s)
+        {
+            return results.computeIfAbsent(s, t -> delegate.test(s));
+        }
+    }
+}
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/metrics/MetricFilter.java 
b/src/main/java/org/apache/cassandra/sidecar/metrics/MetricFilter.java
new file mode 100644
index 00000000..7f4e5253
--- /dev/null
+++ b/src/main/java/org/apache/cassandra/sidecar/metrics/MetricFilter.java
@@ -0,0 +1,97 @@
+/*
+ * 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.cassandra.sidecar.metrics;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+import org.apache.cassandra.sidecar.config.MetricsFilteringConfiguration;
+
+import static 
org.apache.cassandra.sidecar.config.yaml.MetricsFilteringConfigurationImpl.EQUALS_TYPE;
+import static 
org.apache.cassandra.sidecar.config.yaml.MetricsFilteringConfigurationImpl.REGEX_TYPE;
+
+/**
+ * Filter for deciding whether a metric should be captured
+ */
+public abstract class MetricFilter
+{
+    /**
+     * @return Boolean indicating whether the {@link MetricFilter} is 
satisfied for provided metric name.
+     */
+    public abstract boolean matches(String name);
+
+    public static List<MetricFilter> parse(List<MetricsFilteringConfiguration> 
filterConfigurations)
+    {
+        List<MetricFilter> filters = new ArrayList<>();
+        for (MetricsFilteringConfiguration filterConfiguration : 
filterConfigurations)
+        {
+            if (filterConfiguration.type().equalsIgnoreCase(REGEX_TYPE))
+            {
+                filters.add(new Regex(filterConfiguration.value()));
+            }
+            else if (filterConfiguration.type().equalsIgnoreCase(EQUALS_TYPE))
+            {
+                filters.add(new Equals(filterConfiguration.value()));
+            }
+        }
+        return filters;
+    }
+
+    /**
+     * Metric name based {@link MetricFilter} that checks if a metric name 
matches provided regex pattern
+     */
+    public static class Regex extends MetricFilter
+    {
+        private final Pattern pattern;
+
+        public Regex(String regex)
+        {
+            Objects.requireNonNull(regex);
+            this.pattern = Pattern.compile(regex);
+        }
+
+        @Override
+        public boolean matches(String name)
+        {
+            return pattern.matcher(name).matches();
+        }
+    }
+
+    /**
+     * Metric name based {@link MetricFilter} that checks if a metric name 
exactly matches provided value
+     */
+    public static class Equals extends MetricFilter
+    {
+        private final String value;
+
+        public Equals(String value)
+        {
+            Objects.requireNonNull(value);
+            this.value = value;
+        }
+
+        @Override
+        public boolean matches(String name)
+        {
+            return name.equals(value);
+        }
+    }
+}
diff --git 
a/src/main/java/org/apache/cassandra/sidecar/metrics/MetricRegistryFactory.java 
b/src/main/java/org/apache/cassandra/sidecar/metrics/MetricRegistryFactory.java
new file mode 100644
index 00000000..a27dca41
--- /dev/null
+++ 
b/src/main/java/org/apache/cassandra/sidecar/metrics/MetricRegistryFactory.java
@@ -0,0 +1,103 @@
+/*
+ * 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.cassandra.sidecar.metrics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.SharedMetricRegistries;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.cassandra.sidecar.config.SidecarConfiguration;
+
+/**
+ * Provider for getting {@link FilteringMetricRegistry} based on provided 
metrics configuration
+ */
+@Singleton
+public class MetricRegistryFactory
+{
+    private final String globalRegistryName;
+    private final List<MetricFilter> inclusions;
+    private final List<MetricFilter> exclusions;
+
+    @Inject
+    public MetricRegistryFactory(SidecarConfiguration sidecarConfiguration)
+    {
+        this(sidecarConfiguration.metricsConfiguration().registryName(),
+             
MetricFilter.parse(sidecarConfiguration.metricsConfiguration().includeConfigurations()),
+             
MetricFilter.parse(sidecarConfiguration.metricsConfiguration().excludeConfigurations()));
+    }
+
+    @VisibleForTesting
+    public MetricRegistryFactory(String globalRegistryName, List<MetricFilter> 
inclusions, List<MetricFilter> exclusions)
+    {
+        this.globalRegistryName = globalRegistryName;
+        this.inclusions = new ArrayList<>(inclusions);
+        this.exclusions = new ArrayList<>(exclusions);
+    }
+
+    public MetricRegistry getOrCreate()
+    {
+        return getOrCreate(globalRegistryName);
+    }
+
+    public MetricRegistry getOrCreate(int cassInstanceId)
+    {
+        String instanceRegistryName = globalRegistryName + "_" + 
cassInstanceId;
+        return getOrCreate(instanceRegistryName);
+    }
+
+    /**
+     * Provides a {@link FilteringMetricRegistry} with given name and provided 
filters in configuration.
+     * @param name registry name
+     * @return a {@link MetricRegistry} that can filter out metrics
+     */
+    public MetricRegistry getOrCreate(String name)
+    {
+        // the metric registry already exists
+        if (SharedMetricRegistries.names().contains(name))
+        {
+            return SharedMetricRegistries.getOrCreate(name);
+        }
+
+        FilteringMetricRegistry metricRegistry = new 
FilteringMetricRegistry(this::isAllowed);
+        SharedMetricRegistries.add(name, metricRegistry);
+        return SharedMetricRegistries.getOrCreate(name);
+    }
+
+    /**
+     * Check if the metric is allowed to register
+     * The evaluation order is inclusions first, then exclusions. In other 
words,
+     * a metric name is allowed if it is in the inclusions, but not in the 
exclusions.
+     * <p>
+     * Note that an empty inclusions means including all
+     *
+     * @param name  metric name
+     * @return true if allowed; false otherwise
+     */
+    private boolean isAllowed(String name)
+    {
+        boolean included = inclusions.isEmpty() || 
inclusions.stream().anyMatch(filter -> filter.matches(name));
+        boolean excluded = exclusions.stream().anyMatch(filter -> 
filter.matches(name));
+        return included && !excluded;
+    }
+}
diff --git a/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java 
b/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java
index 9db7d95a..448bcbb6 100644
--- a/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java
+++ b/src/main/java/org/apache/cassandra/sidecar/server/MainModule.java
@@ -30,7 +30,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.SharedMetricRegistries;
 import com.datastax.driver.core.NettyOptions;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
@@ -76,6 +75,7 @@ import 
org.apache.cassandra.sidecar.db.schema.RestoreSlicesSchema;
 import org.apache.cassandra.sidecar.db.schema.SidecarInternalKeyspace;
 import org.apache.cassandra.sidecar.db.schema.SidecarSchema;
 import org.apache.cassandra.sidecar.logging.SidecarLoggerHandler;
+import org.apache.cassandra.sidecar.metrics.MetricRegistryFactory;
 import org.apache.cassandra.sidecar.routes.CassandraHealthHandler;
 import org.apache.cassandra.sidecar.routes.DiskSpaceProtectionHandler;
 import org.apache.cassandra.sidecar.routes.FileStreamHandler;
@@ -142,14 +142,14 @@ public class MainModule extends AbstractModule
 
     @Provides
     @Singleton
-    public Vertx vertx(SidecarConfiguration sidecarConfiguration)
+    public Vertx vertx(SidecarConfiguration sidecarConfiguration, 
MetricRegistryFactory metricRegistryFactory)
     {
         VertxMetricsConfiguration metricsConfig = 
sidecarConfiguration.metricsConfiguration().vertxConfiguration();
         DropwizardMetricsOptions dropwizardMetricsOptions
         = new DropwizardMetricsOptions().setEnabled(metricsConfig.enabled())
                                         
.setJmxEnabled(metricsConfig.exposeViaJMX())
                                         
.setJmxDomain(metricsConfig.jmxDomainName())
-                                        
.setRegistryName(sidecarConfiguration.metricsConfiguration().registryName());
+                                        
.setMetricRegistry(metricRegistryFactory.getOrCreate());
         for (String regex : metricsConfig.monitoredServerRouteRegexes())
         {
             dropwizardMetricsOptions.addMonitoredHttpServerRoute(new 
Match().setType(MatchType.REGEX).setValue(regex));
@@ -370,7 +370,8 @@ public class MainModule extends AbstractModule
                                            SidecarVersionProvider 
sidecarVersionProvider,
                                            DnsResolver dnsResolver,
                                            CQLSessionProvider 
cqlSessionProvider,
-                                           DriverUtils driverUtils)
+                                           DriverUtils driverUtils,
+                                           MetricRegistryFactory 
registryProvider)
     {
         List<InstanceMetadata> instanceMetadataList =
         configuration.cassandraInstances()
@@ -384,7 +385,7 @@ public class MainModule extends AbstractModule
                                                       jmxConfiguration,
                                                       cqlSessionProvider,
                                                       driverUtils,
-                                                      
configuration.metricsConfiguration().registryName());
+                                                      registryProvider);
                      })
                      .collect(Collectors.toList());
 
@@ -525,9 +526,9 @@ public class MainModule extends AbstractModule
 
     @Provides
     @Singleton
-    public MetricRegistry globalMetricRegistry(SidecarConfiguration 
sidecarConfiguration)
+    public MetricRegistry globalMetricRegistry(MetricRegistryFactory 
registryProvider)
     {
-        return 
SharedMetricRegistries.getOrCreate(sidecarConfiguration.metricsConfiguration().registryName());
+        return registryProvider.getOrCreate();
     }
 
     /**
@@ -559,7 +560,7 @@ public class MainModule extends AbstractModule
      * @param sidecarVersion        the version of the Sidecar from the 
current binary
      * @param jmxConfiguration      the configuration for the JMX Client
      * @param session               the CQL Session provider
-     * @param globalRegistryName    global registry name used for tracking 
Sidecar metrics
+     * @param registryFactory       factory for creating cassandra instance 
specific registry
      * @return the build instance metadata object
      */
     private static InstanceMetadata buildInstanceMetadata(Vertx vertx,
@@ -569,7 +570,7 @@ public class MainModule extends AbstractModule
                                                           JmxConfiguration 
jmxConfiguration,
                                                           CQLSessionProvider 
session,
                                                           DriverUtils 
driverUtils,
-                                                          String 
globalRegistryName)
+                                                          
MetricRegistryFactory registryFactory)
     {
         String host = cassandraInstance.host();
         int port = cassandraInstance.port();
@@ -592,6 +593,7 @@ public class MainModule extends AbstractModule
                                                                          
sidecarVersion,
                                                                          host,
                                                                          port);
+
         return InstanceMetadataImpl.builder()
                                    .id(cassandraInstance.id())
                                    .host(host)
@@ -599,7 +601,7 @@ public class MainModule extends AbstractModule
                                    .dataDirs(cassandraInstance.dataDirs())
                                    .stagingDir(cassandraInstance.stagingDir())
                                    .delegate(delegate)
-                                   
.globalMetricRegistryName(globalRegistryName)
+                                   
.metricRegistry(registryFactory.getOrCreate(cassandraInstance.id()))
                                    .build();
     }
 }
diff --git 
a/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java
 
b/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java
index e101e391..e3ce1121 100644
--- 
a/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java
+++ 
b/src/test/integration/org/apache/cassandra/sidecar/testing/CassandraSidecarTestContext.java
@@ -23,6 +23,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -46,6 +47,7 @@ import org.apache.cassandra.sidecar.common.CQLSessionProvider;
 import org.apache.cassandra.sidecar.common.JmxClient;
 import org.apache.cassandra.sidecar.common.dns.DnsResolver;
 import org.apache.cassandra.sidecar.common.utils.DriverUtils;
+import org.apache.cassandra.sidecar.metrics.MetricRegistryFactory;
 import org.apache.cassandra.sidecar.utils.CassandraVersionProvider;
 import org.apache.cassandra.sidecar.utils.SimpleCassandraVersion;
 import org.apache.cassandra.testing.AbstractCassandraTestContext;
@@ -59,6 +61,9 @@ import static org.assertj.core.api.Assertions.assertThat;
 public class CassandraSidecarTestContext implements AutoCloseable
 {
     public final SimpleCassandraVersion version;
+    private final MetricRegistryFactory metricRegistryProvider = new 
MetricRegistryFactory("cassandra_sidecar",
+                                                                               
            Collections.emptyList(),
+                                                                               
            Collections.emptyList());
     private final CassandraVersionProvider versionProvider;
     private final DnsResolver dnsResolver;
     private final AbstractCassandraTestContext abstractCassandraTestContext;
@@ -257,7 +262,7 @@ public class CassandraSidecarTestContext implements 
AutoCloseable
                                              
.dataDirs(Arrays.asList(dataDirectories))
                                              .stagingDir(stagingDir)
                                              .delegate(delegate)
-                                             
.globalMetricRegistryName("cassandra_sidecar")
+                                             
.metricRegistry(metricRegistryProvider.getOrCreate(i + 1))
                                              .build());
         }
         return new InstancesConfigImpl(metadata, dnsResolver);
diff --git 
a/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
 
b/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
index 3498d970..221132b7 100644
--- 
a/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
+++ 
b/src/test/java/org/apache/cassandra/sidecar/config/SidecarConfigurationTest.java
@@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
 
 import com.fasterxml.jackson.databind.JsonMappingException;
+import 
org.apache.cassandra.sidecar.config.yaml.MetricsFilteringConfigurationImpl;
 import org.apache.cassandra.sidecar.config.yaml.SidecarConfigurationImpl;
 import org.apache.cassandra.sidecar.config.yaml.VertxMetricsConfigurationImpl;
 import org.assertj.core.api.Condition;
@@ -38,7 +39,8 @@ import static 
org.apache.cassandra.sidecar.common.ApiEndpointsV1.KEYSPACE_SCHEMA
 import static 
org.apache.cassandra.sidecar.common.ApiEndpointsV1.RESTORE_JOB_SLICES_ROUTE;
 import static 
org.apache.cassandra.sidecar.common.ApiEndpointsV1.TIME_SKEW_ROUTE;
 import static 
org.apache.cassandra.sidecar.common.ResourceUtils.writeResourceToPath;
-import static 
org.apache.cassandra.sidecar.config.yaml.MetricsConfigurationImpl.DEFAULT_DROPWIZARD_REGISTRY_NAME;
+import static 
org.apache.cassandra.sidecar.config.yaml.MetricsFilteringConfigurationImpl.EQUALS_TYPE;
+import static 
org.apache.cassandra.sidecar.config.yaml.MetricsFilteringConfigurationImpl.REGEX_TYPE;
 import static 
org.apache.cassandra.sidecar.config.yaml.VertxMetricsConfigurationImpl.DEFAULT_JMX_DOMAIN_NAME;
 import static org.assertj.core.api.Assertions.assertThat;
 import static 
org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
@@ -221,14 +223,40 @@ class SidecarConfigurationTest
         SidecarConfiguration config = 
SidecarConfigurationImpl.readYamlConfiguration(yamlPath);
 
         MetricsConfiguration configuration = config.metricsConfiguration();
-        
assertThat(configuration.registryName()).isEqualTo(DEFAULT_DROPWIZARD_REGISTRY_NAME);
+        
assertThat(configuration.registryName()).isEqualTo("cassandra_sidecar_metrics");
         VertxMetricsConfiguration vertxMetricsConfiguration = 
configuration.vertxConfiguration();
         assertThat(vertxMetricsConfiguration.enabled()).isTrue();
         assertThat(vertxMetricsConfiguration.exposeViaJMX()).isFalse();
         
assertThat(vertxMetricsConfiguration.jmxDomainName()).isEqualTo(DEFAULT_JMX_DOMAIN_NAME);
-        
assertThat(vertxMetricsConfiguration.monitoredServerRouteRegexes().size()).isEqualTo(2);
-        
assertThat(vertxMetricsConfiguration.monitoredServerRouteRegexes().get(0)).isEqualTo("/api/v1/keyspaces/.*");
-        
assertThat(vertxMetricsConfiguration.monitoredServerRouteRegexes().get(1)).isEqualTo("/api/v1/cassandra/.*");
+        List<MetricsFilteringConfiguration> includeConfigurations = 
configuration.includeConfigurations();
+        List<MetricsFilteringConfiguration> excludeConfigurations = 
configuration.excludeConfigurations();
+        assertThat(includeConfigurations.size()).isEqualTo(1);
+        assertThat(excludeConfigurations.size()).isEqualTo(2);
+        assertThat(includeConfigurations.get(0).type()).isEqualTo("regex");
+        assertThat(includeConfigurations.get(0).value()).isEqualTo(".*");
+        if (excludeConfigurations.get(0).type().equals("regex"))
+        {
+            
assertThat(excludeConfigurations.get(0).value()).isEqualTo("vertx.eventbus.*");
+            
assertThat(excludeConfigurations.get(1).type()).isEqualTo("equals");
+            
assertThat(excludeConfigurations.get(1).value()).isEqualTo("instances_up");
+        }
+        else
+        {
+            
assertThat(excludeConfigurations.get(1).value()).isEqualTo("vertx.eventbus.*");
+            assertThat(excludeConfigurations.get(1).type()).isEqualTo("regex");
+            
assertThat(excludeConfigurations.get(0).value()).isEqualTo("instances_up");
+        }
+    }
+
+    @Test
+    void testInvalidMetricOptions()
+    {
+        Path yamlPath = yaml("config/sidecar_invalid_metrics.yaml");
+        assertThatExceptionOfType(JsonMappingException.class)
+        .isThrownBy(() -> 
SidecarConfigurationImpl.readYamlConfiguration(yamlPath))
+        .withRootCauseInstanceOf(IllegalArgumentException.class)
+        .withMessageContaining("contains passed for metric filtering is not 
recognized. Expected types are "
+                               + REGEX_TYPE + " or " + EQUALS_TYPE);
     }
 
     @Test
@@ -243,6 +271,16 @@ class SidecarConfigurationTest
         assertThat(pattern.matcher(RESTORE_JOB_SLICES_ROUTE)).matches();
     }
 
+    @Test
+    void testMetricsAllowedWithDefaultRegexFilter()
+    {
+        Pattern pattern = 
Pattern.compile(MetricsFilteringConfigurationImpl.DEFAULT_VALUE);
+        
assertThat(pattern.matcher("vertx.http.servers.localhost:0.responses-5xx")).matches();
+        
assertThat(pattern.matcher("sidecar.schema.cassandra_instances_up")).matches();
+        
assertThat(pattern.matcher("vertx.eventbus.messages.bytes-read")).matches();
+        assertThat(pattern.matcher("throttled_429")).matches();
+    }
+
     void validateSingleInstanceSidecarConfiguration(SidecarConfiguration 
config)
     {
         assertThat(config.cassandraInstances()).isNotNull().hasSize(1);
@@ -431,8 +469,11 @@ class SidecarConfigurationTest
 
     void validateMetricsConfiguration(MetricsConfiguration config)
     {
+        assertThat(config.registryName()).isNotEmpty();
         assertThat(config.vertxConfiguration()).isNotNull();
         
assertThat(config.vertxConfiguration().monitoredServerRouteRegexes()).isNotNull();
+        assertThat(config.includeConfigurations()).isNotNull();
+        assertThat(config.excludeConfigurations()).isNotNull();
     }
 
     private Path yaml(String resourceName)
diff --git 
a/src/test/java/org/apache/cassandra/sidecar/metrics/FilteringMetricRegistryTest.java
 
b/src/test/java/org/apache/cassandra/sidecar/metrics/FilteringMetricRegistryTest.java
new file mode 100644
index 00000000..bfeb8d9c
--- /dev/null
+++ 
b/src/test/java/org/apache/cassandra/sidecar/metrics/FilteringMetricRegistryTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.cassandra.sidecar.metrics;
+
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+
+import com.codahale.metrics.DefaultSettableGauge;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.NoopMetricRegistry;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import io.vertx.core.Vertx;
+import io.vertx.ext.dropwizard.ThroughputMeter;
+import io.vertx.junit5.Checkpoint;
+import io.vertx.junit5.VertxExtension;
+import io.vertx.junit5.VertxTestContext;
+import org.apache.cassandra.sidecar.server.MainModule;
+import org.apache.cassandra.sidecar.server.Server;
+import org.apache.cassandra.sidecar.server.SidecarServerEvents;
+
+import static 
org.apache.cassandra.sidecar.common.ResourceUtils.writeResourceToPath;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * Test for filtering of metrics
+ */
+@ExtendWith(VertxExtension.class)
+public class FilteringMetricRegistryTest
+{
+    private static final MetricRegistry NO_OP_METRIC_REGISTRY = new 
NoopMetricRegistry();
+    @TempDir
+    private Path confPath;
+
+    @Test
+    void testNoopInstanceRetrieved()
+    {
+        MetricFilter.Regex testFilter = new MetricFilter.Regex("testMetric.*");
+        MetricRegistryFactory registryFactory = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                          
Collections.emptyList(),
+                                                                          
Collections.singletonList(testFilter));
+        FilteringMetricRegistry metricRegistry = (FilteringMetricRegistry) 
registryFactory.getOrCreate();
+
+        
assertThat(metricRegistry.timer("testMetricTimer")).isSameAs(NO_OP_METRIC_REGISTRY.timer("any"));
+        
assertThat(metricRegistry.meter("testMetricMeter")).isSameAs(NO_OP_METRIC_REGISTRY.meter("any"));
+        
assertThat(metricRegistry.counter("testMetricCounter")).isSameAs(NO_OP_METRIC_REGISTRY.counter("any"));
+        
assertThat(metricRegistry.histogram("testMetricHistogram")).isSameAs(NO_OP_METRIC_REGISTRY.histogram("any"));
+
+        metricRegistry.register("testMetricThroughputMeter", new 
ThroughputMeter());
+        
assertThat(metricRegistry.getIncludedMetrics()).doesNotContainKey("testMetricThroughputMeter");
+    }
+
+    @Test
+    void testDuplicateMetricsNotAllowed()
+    {
+        MetricRegistry metricRegistry = new MetricRegistry();
+        assertThat(metricRegistry.timer("testMetric")).isNotNull();
+        assertThatThrownBy(() -> metricRegistry.meter("testMetric"))
+        .isInstanceOf(IllegalArgumentException.class);
+
+        MetricRegistryFactory registryFactory = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                          
Collections.emptyList(),
+                                                                          
Collections.emptyList());
+        FilteringMetricRegistry filteringMetricRegistry = 
(FilteringMetricRegistry) registryFactory.getOrCreate();
+
+        filteringMetricRegistry.timer("testMetric");
+        assertThatThrownBy(() -> filteringMetricRegistry.meter("testMetric"))
+        .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void testGaugeMetricExclusion()
+    {
+        MetricFilter.Regex testFilter = new MetricFilter.Regex("testMetric.*");
+        MetricRegistryFactory registryFactory = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                          
Collections.emptyList(),
+                                                                          
Collections.singletonList(testFilter));
+        FilteringMetricRegistry metricRegistry = (FilteringMetricRegistry) 
registryFactory.getOrCreate();
+
+        assertThat(metricRegistry.gauge("testMetricGauge", () -> new 
DefaultSettableGauge<>(0L)))
+        .isInstanceOf(DefaultSettableGauge.class);
+        
assertThat(metricRegistry.getIncludedMetrics()).doesNotContainKey("testMetricGauge");
+
+        metricRegistry.register("testMetricDefaultSettableGaugeLong", new 
DefaultSettableGauge<>(0L));
+        
assertThat(metricRegistry.getIncludedMetrics()).doesNotContainKey("testMetricDefaultSettableGaugeLong");
+
+        metricRegistry.register("testMetricDefaultSettableGaugeDouble", new 
DefaultSettableGauge<>(0d));
+        
assertThat(metricRegistry.getIncludedMetrics()).doesNotContainKey("testMetricDefaultSettableGaugeDouble");
+    }
+
+    @Test
+    void testOneMatchingFilter()
+    {
+        MetricFilter.Equals exactFilter = new 
MetricFilter.Equals("sidecar.metric.exact");
+        MetricFilter.Regex regexFilter = new MetricFilter.Regex("vertx.*");
+        MetricRegistryFactory registryFactory = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                          
Collections.singletonList(exactFilter),
+                                                                          
Collections.singletonList(regexFilter));
+        FilteringMetricRegistry metricRegistry = (FilteringMetricRegistry) 
registryFactory.getOrCreate();
+
+        metricRegistry.meter("sidecar.metric.exact");
+        
assertThat(metricRegistry.getIncludedMetrics()).containsKey("sidecar.metric.exact");
+    }
+
+    @Test
+    void testMultipleMatchingFilter()
+    {
+        MetricFilter.Equals exactFilter = new 
MetricFilter.Equals("sidecar.metric.exact");
+        MetricFilter.Regex regexFilter = new MetricFilter.Regex("sidecar.*");
+        MetricRegistryFactory registryFactory = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                          
Arrays.asList(exactFilter, regexFilter),
+                                                                          
Collections.emptyList());
+        FilteringMetricRegistry metricRegistry = (FilteringMetricRegistry) 
registryFactory.getOrCreate();
+
+        metricRegistry.meter("sidecar.metric.exact");
+        
assertThat(metricRegistry.getIncludedMetrics()).containsKey("sidecar.metric.exact");
+    }
+
+    @Test
+    void testExcludingEqualsMetricFilter()
+    {
+        MetricFilter.Equals exactFilter = new 
MetricFilter.Equals("sidecar.metric.exact");
+        MetricRegistryFactory registryFactory = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                          
Collections.emptyList(),
+                                                                          
Collections.singletonList(exactFilter));
+        FilteringMetricRegistry metricRegistry = (FilteringMetricRegistry) 
registryFactory.getOrCreate();
+
+        metricRegistry.meter("sidecar.metric.exact");
+        
assertThat(metricRegistry.getIncludedMetrics()).doesNotContainKey("sidecar.metric.exact");
+    }
+
+    @Test
+    void testExcludingRegexMetricFilter()
+    {
+        MetricFilter.Regex vertxFilter = new MetricFilter.Regex("vertx.*");
+        MetricFilter.Regex sidecarFilter = new MetricFilter.Regex("sidecar.*");
+        MetricRegistryFactory registryProvider = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                           
Collections.singletonList(sidecarFilter),
+                                                                           
Collections.singletonList(vertxFilter));
+        FilteringMetricRegistry metricRegistry = (FilteringMetricRegistry) 
registryProvider.getOrCreate();
+
+        metricRegistry.meter("sidecar.metric.exact");
+        
assertThat(metricRegistry.getMetrics()).containsKey("sidecar.metric.exact");
+        metricRegistry.timer("vertx.eventbus.message_transfer_time");
+        
assertThat(metricRegistry.getIncludedMetrics()).doesNotContainKey("vertx.eventbus.message_transfer_time");
+    }
+
+    @Test
+    void testMultipleMatchingFilterWithOneExclude()
+    {
+        MetricFilter.Equals exactFilter = new 
MetricFilter.Equals("sidecar.metric.exact");
+        MetricFilter.Regex regexFilter = new MetricFilter.Regex("sidecar.*");
+        MetricRegistryFactory registryFactory = new 
MetricRegistryFactory("cassandra_sidecar_" + UUID.randomUUID(),
+                                                                          
Collections.singletonList(regexFilter),
+                                                                          
Collections.singletonList(exactFilter));
+        FilteringMetricRegistry metricRegistry = (FilteringMetricRegistry) 
registryFactory.getOrCreate();
+
+        metricRegistry.meter("sidecar.metric.exact");
+        
assertThat(metricRegistry.getIncludedMetrics()).doesNotContainKey("sidecar.metric.exact");
+    }
+
+    @Test
+    void testExclusionsWithServer(VertxTestContext context)
+    {
+        ClassLoader classLoader = 
FilteringMetricRegistryTest.class.getClassLoader();
+        Path yamlPath = writeResourceToPath(classLoader, confPath, 
"config/sidecar_metrics.yaml");
+        Injector injector = Guice.createInjector(new MainModule(yamlPath));
+        Server server = injector.getInstance(Server.class);
+        Vertx vertx = injector.getInstance(Vertx.class);
+
+        Checkpoint serverStarted = context.checkpoint();
+        Checkpoint waitUntilCheck = context.checkpoint();
+
+        
vertx.eventBus().localConsumer(SidecarServerEvents.ON_SERVER_START.address(), 
message -> serverStarted.flag());
+
+        server.start()
+              .onFailure(context::failNow)
+              .onSuccess(v -> {
+                  MetricRegistryFactory registryFactory = 
injector.getInstance(MetricRegistryFactory.class);
+                  Pattern excludedPattern = 
Pattern.compile("vertx.eventbus.*");
+                  FilteringMetricRegistry globalRegistry = 
(FilteringMetricRegistry) registryFactory.getOrCreate();
+                  
assertThat(globalRegistry.getIncludedMetrics().size()).isGreaterThanOrEqualTo(1);
+                  
assertThat(globalRegistry.getIncludedMetrics().keySet().stream())
+                  .noneMatch(key -> excludedPattern.matcher(key).matches());
+                  waitUntilCheck.flag();
+                  context.completeNow();
+              });
+    }
+}
diff --git 
a/src/test/java/org/apache/cassandra/sidecar/snapshots/SnapshotUtils.java 
b/src/test/java/org/apache/cassandra/sidecar/snapshots/SnapshotUtils.java
index 744daa2e..85cba26e 100644
--- a/src/test/java/org/apache/cassandra/sidecar/snapshots/SnapshotUtils.java
+++ b/src/test/java/org/apache/cassandra/sidecar/snapshots/SnapshotUtils.java
@@ -40,6 +40,8 @@ import org.apache.cassandra.sidecar.common.JmxClient;
 import org.apache.cassandra.sidecar.common.MockCassandraFactory;
 import org.apache.cassandra.sidecar.common.dns.DnsResolver;
 import org.apache.cassandra.sidecar.common.utils.DriverUtils;
+import org.apache.cassandra.sidecar.metrics.MetricFilter;
+import org.apache.cassandra.sidecar.metrics.MetricRegistryFactory;
 import org.apache.cassandra.sidecar.utils.CassandraVersionProvider;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -51,6 +53,10 @@ import static org.mockito.Mockito.mock;
 public class SnapshotUtils
 {
     public static final String STAGING_DIR = "staging";
+    public static final List<MetricFilter> INCLUDE_ALL = 
Collections.singletonList(new MetricFilter.Regex(".*"));
+    public static final MetricRegistryFactory METRIC_REGISTRY_PROVIDER = new 
MetricRegistryFactory("cassandra_sidecar",
+                                                                               
                    INCLUDE_ALL,
+                                                                               
                    Collections.emptyList());
 
     public static String makeStagingDir(String rootPath)
     {
@@ -124,7 +130,7 @@ public class SnapshotUtils
                                                              
.dataDirs(Collections.singletonList(rootPath + "/d1"))
                                                              
.stagingDir(stagingDir)
                                                              
.delegate(delegate)
-                                                             
.globalMetricRegistryName("cassandra_sidecar")
+                                                             
.metricRegistry(METRIC_REGISTRY_PROVIDER.getOrCreate(1))
                                                              .build();
         InstanceMetadataImpl localhost2 = InstanceMetadataImpl.builder()
                                                               .id(2)
@@ -133,7 +139,7 @@ public class SnapshotUtils
                                                               
.dataDirs(Collections.singletonList(rootPath + "/d2"))
                                                               
.stagingDir(stagingDir)
                                                               
.delegate(delegate)
-                                                              
.globalMetricRegistryName("cassandra_sidecar")
+                                                              
.metricRegistry(METRIC_REGISTRY_PROVIDER.getOrCreate(2))
                                                               .build();
         List<InstanceMetadata> instanceMetas = Arrays.asList(localhost, 
localhost2);
         return new InstancesConfigImpl(instanceMetas, DnsResolver.DEFAULT);
diff --git a/src/test/resources/config/sidecar_invalid_metrics.yaml 
b/src/test/resources/config/sidecar_invalid_metrics.yaml
new file mode 100644
index 00000000..32d377c2
--- /dev/null
+++ b/src/test/resources/config/sidecar_invalid_metrics.yaml
@@ -0,0 +1,47 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Cassandra SideCar configuration file
+#
+cassandra:
+  host: localhost
+  port: 9042
+  data_dirs: /cassandra/d1/data, /cassandra/d2/data
+  jmx_host: 127.0.0.1
+  jmx_port: 7199
+  jmx_role: controlRole
+  jmx_role_password: controlPassword
+  jmx_ssl_enabled: true
+
+sidecar:
+  host: 0.0.0.0
+  port: 1234
+  request_idle_timeout_millis: 500000 # this field expects integer value
+  request_timeout_millis: 1200000
+  allowable_time_skew_in_minutes: 1
+
+metrics:
+  registry_name: cassandra_sidecar_metrics
+  vertx:
+    enabled: true
+    expose_via_jmx: false
+    jmx_domain_name: sidecar.vertx.jmx_domain
+  exclude:
+    - type: "contains"
+      value: "vertx"
diff --git a/src/test/resources/config/sidecar_metrics.yaml 
b/src/test/resources/config/sidecar_metrics.yaml
index 689f157e..2cc734db 100644
--- a/src/test/resources/config/sidecar_metrics.yaml
+++ b/src/test/resources/config/sidecar_metrics.yaml
@@ -1,36 +1,39 @@
+#
+# 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.
+#
+
 #
 # Cassandra SideCar configuration file
 #
-cassandra:
+cassandra_instances:
   host: localhost
   port: 9042
-  data_dirs: /cassandra/d1/data, /cassandra/d2/data
+  username: cassandra
+  password: cassandra
+  data_dirs:
+    - /ccm/test/node1/data0
+    - /ccm/test/node1/data1
+  staging_dir: /ccm/test/node1/sstable-staging
   jmx_host: 127.0.0.1
   jmx_port: 7199
   jmx_role: controlRole
   jmx_role_password: controlPassword
   jmx_ssl_enabled: true
 
-cassandra_instances:
-  - id: 1
-    host: localhost1
-    port: 9042
-    data_dirs: /cassandra/d1/data, /cassandra/d2/data
-    jmx_host: 127.0.0.1
-    jmx_port: 7100
-    jmx_role: controlRole
-    jmx_role_password: controlPassword
-    jmx_ssl_enabled: true
-  - id: 2
-    host: localhost2
-    port: 9042
-    data_dirs: /cassandra/d3/data, /cassandra/d4/data
-    jmx_host: 127.0.0.1
-    jmx_port: 7200
-    jmx_role: controlRole
-    jmx_role_password: controlPassword
-    jmx_ssl_enabled: true
-
 sidecar:
   host: 0.0.0.0
   port: 9043
@@ -40,9 +43,9 @@ sidecar:
     timeout_sec: 10
   allowable_time_skew_in_minutes: 60
   jmx:
-    connection:
-      max_retries: 40
-      retry_delay_millis: 2000
+    max_retries: 42
+    retry_delay_millis: 1234
+
 #
 # Enable SSL configuration (Disabled by default)
 #
@@ -56,14 +59,34 @@ sidecar:
 #          - password: password
 
 metrics:
-  registry_name: cassandra_sidecar
+  registry_name: cassandra_sidecar_metrics
   vertx:
     enabled: true
     expose_via_jmx: false
     jmx_domain_name: sidecar.vertx.jmx_domain
-    monitored_server_route_regexes:                # regex list to match 
server routes
-      - /api/v1/keyspaces/.*
-      - /api/v1/cassandra/.*
+  include:
+    - type: "regex"
+      value: ".*"
+  exclude:
+    - type: "regex"
+      value: "vertx.eventbus.*"
+    - type: "equals"
+      value: "instances_up"
 
 healthcheck:
-  poll_freq_millis: 30000
\ No newline at end of file
+  initial_delay_millis: 100
+  poll_freq_millis: 30000
+
+cassandra_input_validation:
+  forbidden_keyspaces:
+    - system_schema
+    - system_traces
+    - system_distributed
+    - system
+    - system_auth
+    - system_views
+    - system_virtual_schema
+  allowed_chars_for_directory: "[a-zA-Z][a-zA-Z0-9_]{0,47}"
+  allowed_chars_for_quoted_name: "[a-zA-Z_0-9]{1,48}"
+  allowed_chars_for_component_name: 
"[a-zA-Z0-9_-]+(.db|.cql|.json|.crc32|TOC.txt)"
+  allowed_chars_for_restricted_component_name: "[a-zA-Z0-9_-]+(.db|TOC.txt)"
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to