/*
* Copyright 2016 Google, Inc.
*
* Licensed 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 com.netflix.spectator.controllers.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Represents the specification for a PrototypeMeasurementFilter.
*/
public class PrototypeMeasurementFilterSpecification {
/**
* Specifies how to filter an individual tag (name and value).
*/
public static class TagFilterSpecification {
private String key; // regex
private String value; // regex
public String getKey() {
return key;
}
public String getValue() {
return value;
}
/**
* Default constructor.
*/
public TagFilterSpecification() {
key = null;
value = null;
}
/**
* Construct a filter with particular regular expressions.
*/
public TagFilterSpecification(String key, String value) {
this.key = key;
this.value = value;
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof TagFilterSpecification)) {
return false;
}
TagFilterSpecification other = (TagFilterSpecification) obj;
return key.equals(other.key) && value.equals(other.value);
}
@Override
public int hashCode() {
return Objects.hash(key, value);
}
@Override
public String toString() {
return String.format("%s=%s", key, value);
}
}
/**
* Specifies how to filter values.
*
* Values are identified by a collection of tags, so the filter
* is based on having a particular collection of name/value bindings.
*
* Actual values are not currently considered, but could be added later.
*/
public static class ValueFilterSpecification {
/**
* A filter that allows everything.
*/
static final ValueFilterSpecification ALL = new ValueFilterSpecification();
static {
ALL.tags.add(new TagFilterSpecification(".*", ".*"));
}
/**
* Default constructor.
*/
ValueFilterSpecification() {
// empty.
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof ValueFilterSpecification)) {
return false;
}
ValueFilterSpecification other = (ValueFilterSpecification) obj;
return tags.equals(other.tags);
}
@Override
public int hashCode() {
return tags.hashCode();
}
@Override
public String toString() {
return tags.toString();
}
/**
* The tag specifications.
*/
public List<TagFilterSpecification> getTags() {
return tags;
}
/**
* The minimal list of tag bindings that are covered by this specification.
*/
private final List<TagFilterSpecification> tags
= new ArrayList<TagFilterSpecification>();
};
/**
* A specification for filtering on a Spectator Meter.
*
* A meter is a name pattern and collection of tag bindings.
*/
public static class MeterFilterSpecification {
/**
* Default constructor.
*/
public MeterFilterSpecification() {
// empty.
}
/**
* Constructor injecting a value specification.
*/
public MeterFilterSpecification(List<ValueFilterSpecification> values) {
this.values.addAll(values);
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof MeterFilterSpecification)) {
return false;
}
MeterFilterSpecification other = (MeterFilterSpecification) obj;
return values.equals(other.values);
}
@Override
public int hashCode() {
return values.hashCode();
}
@Override
public String toString() {
return values.toString();
}
/**
* The metric vlaue specifications.
*/
public List<ValueFilterSpecification> getValues() {
return values;
}
/**
* The meter can be filtered on one or more collection of tag bindings.
* In essence, this permits certain aspects of a meter to be considered
* but not others.
*/
private final List<ValueFilterSpecification> values
= new ArrayList<ValueFilterSpecification>();
};
/**
* Loads a specification from a file.
*/
public static PrototypeMeasurementFilterSpecification loadFromPath(String path)
throws IOException {
byte[] jsonData = Files.readAllBytes(Paths.get(path));
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(
jsonData, PrototypeMeasurementFilterSpecification.class);
}
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof PrototypeMeasurementFilterSpecification)) {
return false;
}
PrototypeMeasurementFilterSpecification other
= (PrototypeMeasurementFilterSpecification) obj;
return include.equals(other.include) && exclude.equals(other.exclude);
}
@Override
public int hashCode() {
return Objects.hash(include, exclude);
}
@Override
public String toString() {
return String.format("INCLUDE=%s%nEXCLUDE=%s",
include.toString(), exclude.toString());
}
/**
* The list of specifications for when meters should be included.
*/
public Map<String, MeterFilterSpecification> getInclude() {
return include;
}
/**
* The list of specifications for when meters should be excluded.
*/
public Map<String, MeterFilterSpecification> getExclude() {
return exclude;
}
/**
* Maps meter name patterns to the meter specification for that pattern.
* The specified filter only passes meter/measurements that can be
* traced back to a specification in this list.
*/
private final Map<String, MeterFilterSpecification> include
= new HashMap<String, MeterFilterSpecification>();
/**
* Maps meter name patterns to the meter specification for that pattern.
* The specified filter does not pass meter/measurements that can be
* traced back to a specification in this list.
*/
private final Map<String, MeterFilterSpecification> exclude
= new HashMap<String, MeterFilterSpecification>();
};