Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change filtering rules behavior #48

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Testing

on: [push]
on: [push, pull_request]

jobs:
build:
Expand Down
Binary file added package-0.3.0/datastax-mcac-agent-0.3.0.tar.gz
Binary file not shown.
60 changes: 16 additions & 44 deletions src/main/java/com/datastax/mcac/FilteringRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

Expand All @@ -10,18 +11,19 @@

import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FilteringRule
{
private static final Logger logger = LoggerFactory.getLogger(FilteringRule.class);
public static final String ALLOW = "allow";
public static final String DENY = "deny";
public static final String GLOBAL = "global";
public static final String DATALOG_ONLY = "datalog";

public static final FilteringRule FILTERED_GLOBALLY = new FilteringRule(DENY, ".*", GLOBAL);
public static final FilteringRule FILTERED_INSIGHTS = new FilteringRule(DENY, ".*", DATALOG_ONLY);
public static final FilteringRule ALLOWED_GLOBALLY = new FilteringRule(ALLOW, ".*", GLOBAL);
public static final FilteringRule ALLOWED_INSIGHTS = new FilteringRule(ALLOW, ".*", DATALOG_ONLY);


@JsonProperty("policy")
public final String policy;
Expand Down Expand Up @@ -82,60 +84,30 @@ public void init()
});
}

public boolean isAllowed(String name)
public boolean matches(String name)
{
boolean match = patternRegex.get().matcher(name).find();
return isAllowRule ? match : !match;
return patternRegex.get().matcher(name).find();
}

/**
* Returns the most applicable filtering rule for this name
* taking into account global vs insights level scope.
* Returns the most applicable filtering rule for this name.
*
* global taking precedent over insights and deny rules taking precedent over allow rules
* The last rule in the list of applicable rules wins.
* @param name
* @return The rule that applied for this name.
*/
public static FilteringRule applyFilters(String name, Collection<FilteringRule> rules)
{
FilteringRule allowRule = null;
FilteringRule denyRule = null;
boolean hasDenyRule = false;
boolean hasAllowRule = false;
Optional<FilteringRule> lastRule = rules.stream().filter(rule -> rule.matches(name)).reduce((first, second) -> second);

for (FilteringRule rule : rules)
{
if (rule.isAllowRule)
{
hasAllowRule = true;
if ((allowRule == null || !allowRule.isGlobal) && rule.isAllowed(name))
{
allowRule = rule;
}
}
else
{
hasDenyRule = true;
if ((denyRule == null || !denyRule.isGlobal) && !rule.isAllowed(name))
{
denyRule = rule;
}
}
}

if (rules.isEmpty())
return FilteringRule.ALLOWED_GLOBALLY;

if (denyRule != null)
return denyRule;

if (allowRule != null)
return allowRule;

if (hasDenyRule && !hasAllowRule)
if (!lastRule.isPresent())
return FilteringRule.ALLOWED_GLOBALLY;

return FilteringRule.FILTERED_GLOBALLY;
if (logger.isDebugEnabled()) {
logger.debug("Metric {}", name);
logger.debug(">>>>>> Applying rule {}", lastRule.get());
}
return lastRule.get();
}


Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/build_version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.0
0.3.0
30 changes: 29 additions & 1 deletion src/test/java/com/datastax/mcac/FilteringTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.Arrays;

import com.google.common.io.Resources;
import org.junit.Assert;
Expand All @@ -14,6 +15,33 @@ public void testConfig() throws URISyntaxException, MalformedURLException
{
Configuration c = ConfigurationLoader.loadConfig(Resources.getResource("metric-collector.yaml").toURI().toURL());

Assert.assertEquals(1, c.filtering_rules.size());
Assert.assertEquals(3, c.filtering_rules.size());
}

@Test
public void testAllowLastWins() {
// Check that allow takes precedence over deny if set last
FilteringRule firstRule = new FilteringRule("deny", "org.apache.cassandra.metrics", FilteringRule.GLOBAL);
FilteringRule secondRule = new FilteringRule("allow", "org.apache.cassandra.metrics.metric1", FilteringRule.GLOBAL);
Assert.assertTrue(FilteringRule.applyFilters("org.apache.cassandra.metrics.metric1", Arrays.asList(firstRule, secondRule)).isAllowRule);
}

@Test
public void testAllowFirstLoses() {
// Check that deny takes precedence over allow if set last
FilteringRule firstRule = new FilteringRule("allow", "org.apache.cassandra.metrics.metric1", FilteringRule.GLOBAL);
FilteringRule secondRule = new FilteringRule("deny", "org.apache.cassandra.metrics", FilteringRule.GLOBAL);
Assert.assertFalse(FilteringRule.applyFilters("org.apache.cassandra.metrics.metric1", Arrays.asList(firstRule, secondRule)).isAllowRule);
}

@Test
public void testMixedConditions() {
FilteringRule unaffectedByDenyRule = new FilteringRule("allow", "org.apache.cassandra.whatever.metric3", FilteringRule.GLOBAL);
FilteringRule firstRule = new FilteringRule("allow", "org.apache.cassandra.metrics.metric1", FilteringRule.GLOBAL);
FilteringRule secondRule = new FilteringRule("deny", "org.apache.cassandra.metrics", FilteringRule.GLOBAL);
FilteringRule thirdRule = new FilteringRule("allow", "org.apache.cassandra.metrics.metric2", FilteringRule.GLOBAL);
Assert.assertFalse(FilteringRule.applyFilters("org.apache.cassandra.metrics.metric1", Arrays.asList(unaffectedByDenyRule, firstRule, secondRule, thirdRule)).isAllowRule);
Assert.assertTrue(FilteringRule.applyFilters("org.apache.cassandra.metrics.metric2", Arrays.asList(unaffectedByDenyRule, firstRule, secondRule, thirdRule)).isAllowRule);
Assert.assertTrue(FilteringRule.applyFilters("org.apache.cassandra.whatever.metric3", Arrays.asList(unaffectedByDenyRule, firstRule, secondRule, thirdRule)).isAllowRule);
Comment on lines +43 to +45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: You could extract the List of rules once, and use it in each of the assert statements, as opposed to using Arrays.asList each time. But this is a test, so the efficiency is not really a big deal.

}
}
8 changes: 8 additions & 0 deletions src/test/resources/metric-collector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ write_to_disk_enabled: true
# Default: 5000
#data_dir_max_size_in_mb: 5000

# The last applicable rule for a metric wins.
# This allows to deny all metrics for a specific metric group and then allow them individually.
filtering_rules:
- policy: deny
pattern: jvm.fd.usage
scope: global
- policy: deny
pattern: org.apache.cassandra.metrics.Table
scope: global
- policy: allow
pattern: org.apache.cassandra.metrics.Table.LiveSSTableCount
scope: global

#To output tombstone counter metrics for integration tests
#metric_sampling_interval - The frequency that metrics are reported to Cassandra Metrics Collector.
Expand Down