Skip to content

Commit

Permalink
Improve search, add MeterFilter#denyUnless, improve MeterNotFoundExce…
Browse files Browse the repository at this point in the history
…ption
  • Loading branch information
Jon Schneider committed Feb 20, 2018
1 parent 951fc93 commit 1715f07
Show file tree
Hide file tree
Showing 14 changed files with 541 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public String getName() {
/**
* @return A set of dimensions that allows you to break down the name.
*/
public Iterable<Tag> getTags() {
public List<Tag> getTags() {
return tags;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ public Config config() {
* @return A new search.
*/
public Search find(String name) {
return new Search(this, name);
return Search.in(this).name(name);
}

/**
Expand All @@ -303,7 +303,7 @@ public Search find(String name) {
* @return A new search.
*/
public RequiredSearch get(String name) {
return new RequiredSearch(this, name);
return RequiredSearch.in(this).name(name);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ static MeterFilter commonTags(Iterable<Tag> tags) {
return new MeterFilter() {
@Override
public Meter.Id map(Meter.Id id) {
List<Tag> allTags = new ArrayList<>();
id.getTags().forEach(allTags::add);
List<Tag> allTags = new ArrayList<>(id.getTags());
tags.forEach(allTags::add);
return new Meter.Id(id.getName(), allTags, id.getBaseUnit(), id.getDescription(), id.getType());
}
Expand Down Expand Up @@ -140,6 +139,20 @@ public Meter.Id map(Meter.Id id) {
};
}

/**
* Can be used to build a whitelist of metrics matching certain criteria. Opposite of {@link #deny(Predicate)}.
*
* @param iff When a meter id matches, allow its inclusion, otherwise deny.
*/
static MeterFilter denyUnless(Predicate<Meter.Id> iff) {
return new MeterFilter() {
@Override
public MeterFilterReply accept(Meter.Id id) {
return iff.test(id) ? MeterFilterReply.NEUTRAL : MeterFilterReply.DENY;
}
};
}

/**
* When the given predicate is {@code true}, the meter should be present in published metrics.
*
Expand All @@ -157,6 +170,7 @@ public MeterFilterReply accept(Meter.Id id) {

/**
* When the given predicate is {@code true}, the meter should NOT be present in published metrics.
* Opposite of {@link #denyUnless(Predicate)}.
*
* @param iff When a meter id matches, guarantee its exclusion in published metrics.
* @return A filter that guarantees the exclusion of matching meters.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,28 @@ public String toString() {
return "(" + count + " at " + bucket + ')';
}

public static CountAtBucket of(long bucket, double count) {
return new CountAtBucket(bucket, count);
public static CountAtBucket of(long bucketNanos, double count) {
return new CountAtBucket(bucketNanos, count);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

CountAtBucket that = (CountAtBucket) o;

if (bucket != that.bucket) return false;
return Double.compare(that.count, count) == 0;
}

@Override
public int hashCode() {
int result;
long temp;
result = (int) (bucket ^ (bucket >>> 32));
temp = Double.doubleToLongBits(count);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,26 @@ public String toString() {
public static ValueAtPercentile of(double percentile, double value) {
return new ValueAtPercentile(percentile, value);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

ValueAtPercentile that = (ValueAtPercentile) o;

if (Double.compare(that.percentile, percentile) != 0) return false;
return Double.compare(that.value, value) == 0;
}

@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(percentile);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(value);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,27 @@

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.lang.Nullable;

import java.util.List;
import java.util.Collection;
import java.util.stream.Collectors;

public class MeterNotFoundException extends RuntimeException {
public MeterNotFoundException(String meterName, List<Tag> tags, Class<? extends Meter> meterType) {
super("Unable to locate a meter named '" + meterName + "'" + tagDetail(tags) + " of type " + meterType.getCanonicalName());
public MeterNotFoundException(@Nullable String exactNameMatch, Collection<Tag> tags, Class<? extends Meter> meterType) {
super("Unable to locate a matching meter" + nameDetail(exactNameMatch) + tagDetail(tags) + " of type " + meterType.getCanonicalName());
}

private static String tagDetail(List<Tag> tags) {
String tagDetail = "";
private static String nameDetail(@Nullable String exactNameMatch) {
if (exactNameMatch != null) {
return " with name '" + exactNameMatch + "'";
}
return "";
}

private static String tagDetail(Collection<Tag> tags) {
if (!tags.isEmpty()) {
tagDetail = " with Tags:[" + tags.stream().map(t -> t.getKey() + ":" + t.getValue()).collect(Collectors.joining(",")) + "]";
return " with tags:[" + tags.stream().map(t -> t.getKey() + ":" + t.getValue()).collect(Collectors.joining(",")) + "]";
}
return tagDetail;
return "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,75 +16,166 @@
package io.micrometer.core.instrument.search;

import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.lang.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* Search that requires the search terms are satisfiable, or an {@link MeterNotFoundException} is thrown.
*
* @author Jon Schneider
*/
public final class RequiredSearch {
private final MeterRegistry registry;
private final String name;
private final List<Tag> tags = new ArrayList<>();
private Predicate<String> nameMatches = n -> true;
private final Set<String> requiredTagKeys = new HashSet<>();

public RequiredSearch(MeterRegistry registry, String name) {
@Nullable
private String exactNameMatch;

private RequiredSearch(MeterRegistry registry) {
this.registry = registry;
this.name = name;
}

/**
* Meter contains a tag with the exact name.
*
* @param exactName Name to match against.
* @return This search.
*/
public RequiredSearch name(String exactName) {
this.nameMatches = n -> n.equals(exactName);
this.exactNameMatch = exactName;
return this;
}

/**
* Meter contains a tag matching the name predicate.
*
* @param nameMatches Name matching predicate.
* @return This search.
*/
public RequiredSearch name(Predicate<String> nameMatches) {
this.nameMatches = nameMatches;
return this;
}

/**
* Meter contains a tag with the matching tag keys and values.
*
* @param tags The tags to match.
* @return This search.
*/
public RequiredSearch tags(Iterable<Tag> tags) {
tags.forEach(this.tags::add);
return this;
}

/**
* Meter contains a tag with the matching tag keys and values.
*
* @param tags Must be an even number of arguments representing key/value pairs of tags.
* @return This search.
*/
public RequiredSearch tags(String... tags) {
return tags(Tags.of(tags));
}

/**
* Meter contains a tag with the matching key and value.
*
* @param tagKey The tag key to match.
* @param tagValue The tag value to match.
* @return This search.
*/
public RequiredSearch tag(String tagKey, String tagValue) {
return tags(Tags.of(tagKey, tagValue));
}

/**
* Meter contains a tag with the matching keys.
*
* @param tagKeys The tag keys to match.
* @return This search.
*/
public RequiredSearch tagKeys(String... tagKeys) {
requiredTagKeys.addAll(Arrays.asList(tagKeys));
return this;
}

/**
* @return The first matching {@link Timer}
* @throws MeterNotFoundException if there is no match.
*/
public Timer timer() {
return findOne(Timer.class);
}

/**
* @return The first matching {@link Counter}.
* @throws MeterNotFoundException if there is no match.
*/
public Counter counter() {
return findOne(Counter.class);
}

/**
* @return The first matching {@link Gauge}.
* @throws MeterNotFoundException if there is no match.
*/
public Gauge gauge() {
return findOne(Gauge.class);
}

/**
* @return The first matching {@link FunctionCounter}.
* @throws MeterNotFoundException if there is no match.
*/
public FunctionCounter functionCounter() {
return findOne(FunctionCounter.class);
}

/**
* @return The first matching {@link TimeGauge}.
* @throws MeterNotFoundException if there is no match.
*/
public TimeGauge timeGauge() {
return findOne(TimeGauge.class);
}

/**
* @return The first matching {@link FunctionTimer}.
* @throws MeterNotFoundException if there is no match.
*/
public FunctionTimer functionTimer() {
return findOne(FunctionTimer.class);
}

/**
* @return The first matching {@link DistributionSummary}.
* @throws MeterNotFoundException if there is no match.
*/
public DistributionSummary summary() {
return findOne(DistributionSummary.class);
}

/**
* @return The first matching {@link LongTaskTimer}.
* @throws MeterNotFoundException if there is no match.
*/
public LongTaskTimer longTaskTimer() {
return findOne(LongTaskTimer.class);
}

/**
* @return The first matching {@link Meter}.
* @throws MeterNotFoundException if there is no match.
*/
public Meter meter() {
return findOne(Meter.class);
}
Expand All @@ -100,21 +191,45 @@ private <M extends Meter> M findOne(Class<M> clazz) {
return meter.get();
}

throw new MeterNotFoundException(name, tags, clazz);
throw new MeterNotFoundException(exactNameMatch, tags, clazz);
}

/**
* @return All matching meters.
* @throws MeterNotFoundException if there is no match.
*/
public Collection<Meter> meters() {
Stream<Meter> meterStream =
registry.getMeters().stream().filter(m -> m.getId().getName().equals(name));
Stream<Meter> meterStream = registry.getMeters().stream().filter(m -> nameMatches.test(m.getId().getName()));

if (!tags.isEmpty()) {
if (!tags.isEmpty() || !requiredTagKeys.isEmpty()) {
meterStream = meterStream.filter(m -> {
final List<Tag> idTags = new ArrayList<>();
m.getId().getTags().forEach(idTags::add);
return idTags.containsAll(tags);
boolean requiredKeysPresent = true;
if (!requiredTagKeys.isEmpty()) {
final List<String> tagKeys = new ArrayList<>();
m.getId().getTags().forEach(t -> tagKeys.add(t.getKey()));
requiredKeysPresent = tagKeys.containsAll(requiredTagKeys);
}

return m.getId().getTags().containsAll(tags) && requiredKeysPresent;
});
}

return meterStream.collect(Collectors.toList());
List<Meter> meters = meterStream.collect(Collectors.toList());

if(meters.isEmpty()) {
throw new MeterNotFoundException(exactNameMatch, tags, Meter.class);
}

return meters;
}

/**
* Initiate a new search for meters inside a registry.
*
* @param registry The registry to locate meters in.
* @return A new search.
*/
public static RequiredSearch in(MeterRegistry registry) {
return new RequiredSearch(registry);
}
}
Loading

0 comments on commit 1715f07

Please sign in to comment.