Skip to content

Commit

Permalink
Add support for common/global tags (fixes #23)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkschneider committed Jul 25, 2017
1 parent b5082c9 commit 29424a0
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.micrometer.core.instrument;

import io.micrometer.core.instrument.*;
import io.micrometer.core.instrument.stats.hist.Histogram;
import io.micrometer.core.instrument.stats.quantile.Quantiles;

Expand All @@ -24,6 +23,8 @@

public abstract class AbstractMeterRegistry implements MeterRegistry {
protected final Clock clock;
protected final List<Tag> commonTags = new ArrayList<>();

protected AbstractMeterRegistry(Clock clock) {
this.clock = clock;
}
Expand Down Expand Up @@ -112,4 +113,9 @@ public DistributionSummary create() {
}

protected abstract DistributionSummary distributionSummary(String name, Iterable<Tag> tags, Quantiles quantiles, Histogram<?> histogram);

@Override
public void commonTags(Iterable<Tag> tags) {
tags.forEach(commonTags::add);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ public interface MeterRegistry {
*/
Collection<Meter> getMeters();

/**
* Append a list of common tags to apply to all metrics reported to the monitoring system.
*/
void commonTags(Iterable<Tag> tags);

/**
* Append a list of common tags to apply to all metrics reported to the monitoring system.
*/
default void commonTags(String... tags) {
commonTags(zip(tags));
}

default <M extends Meter> Optional<M> findMeter(Class<M> mClass, String name, String... tags) {
return findMeter(mClass, name, zip(tags));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;
Expand Down Expand Up @@ -111,33 +112,36 @@ public Optional<Meter> findMeter(Meter.Type type, String name, Iterable<Tag> tag

@Override
public Counter counter(String name, Iterable<Tag> tags) {
MeterId id = new MeterId(name, tags);
MeterId id = new MeterId(name, withCommonTags(tags));
io.prometheus.client.Counter counter = collectorByName(io.prometheus.client.Counter.class, name,
n -> buildCollector(id, io.prometheus.client.Counter.build()));
return MapAccess.computeIfAbsent(meterMap, id, c -> new PrometheusCounter(id, child(counter, id.getTags())));
}

@Override
public DistributionSummary distributionSummary(String name, Iterable<Tag> tags, Quantiles quantiles, Histogram<?> histogram) {
MeterId id = new MeterId(name, tags);
Iterable<Tag> allTags = withCommonTags(tags);
MeterId id = new MeterId(name, allTags);
final CustomPrometheusSummary summary = collectorByName(CustomPrometheusSummary.class, name,
n -> new CustomPrometheusSummary(name, stream(tags.spliterator(), false).map(Tag::getKey).collect(toList())).register(registry));
n -> new CustomPrometheusSummary(name, stream(allTags.spliterator(), false).map(Tag::getKey).collect(toList())).register(registry));
return MapAccess.computeIfAbsent(meterMap, id, t -> new PrometheusDistributionSummary(id, summary.child(tags, quantiles, histogram)));
}

@Override
protected io.micrometer.core.instrument.Timer timer(String name, Iterable<Tag> tags, Quantiles quantiles, Histogram<?> histogram) {
MeterId id = new MeterId(name, tags);
Iterable<Tag> allTags = withCommonTags(tags);
MeterId id = new MeterId(name, allTags);
final CustomPrometheusSummary summary = collectorByName(CustomPrometheusSummary.class, name,
n -> new CustomPrometheusSummary(name, stream(tags.spliterator(), false).map(Tag::getKey).collect(toList())).register(registry));
n -> new CustomPrometheusSummary(name, stream(allTags.spliterator(), false).map(Tag::getKey).collect(toList())).register(registry));
return MapAccess.computeIfAbsent(meterMap, id, t -> new PrometheusTimer(id, summary.child(tags, quantiles, histogram), getClock()));
}

@Override
public LongTaskTimer longTaskTimer(String name, Iterable<Tag> tags) {
MeterId id = new MeterId(name, tags);
Iterable<Tag> allTags = withCommonTags(tags);
MeterId id = new MeterId(name, allTags);
final CustomPrometheusLongTaskTimer longTaskTimer = collectorByName(CustomPrometheusLongTaskTimer.class, name,
n -> new CustomPrometheusLongTaskTimer(name, stream(tags.spliterator(), false).map(Tag::getKey).collect(toList()), getClock()).register(registry));
n -> new CustomPrometheusLongTaskTimer(name, stream(allTags.spliterator(), false).map(Tag::getKey).collect(toList()), getClock()).register(registry));
return MapAccess.computeIfAbsent(meterMap, id, t -> new PrometheusLongTaskTimer(id, longTaskTimer.child(tags)));
}

Expand Down Expand Up @@ -173,14 +177,16 @@ public double get() {

@Override
public MeterRegistry register(Meter meter) {
Iterable<Tag> allTags = withCommonTags(meter.getTags());

Collector collector = new Collector() {
@Override
public List<MetricFamilySamples> collect() {
List<MetricFamilySamples.Sample> samples = stream(meter.measure().spliterator(), false)
.map(m -> {
List<String> tagKeys = new ArrayList<>(m.getTags().size());
List<String> tagValues = new ArrayList<>(m.getTags().size());
for (Tag tag : m.getTags()) {
List<String> tagKeys = new ArrayList<>();
List<String> tagValues = new ArrayList<>();
for (Tag tag : allTags) {
tagKeys.add(tag.getKey());
tagValues.add(tag.getValue());
}
Expand Down Expand Up @@ -244,4 +250,10 @@ private <C extends Collector> C collectorByName(Class<C> collectorType, String n
}
return collector;
}

private Iterable<Tag> withCommonTags(Iterable<Tag> tags) {
if(commonTags.isEmpty())
return tags;
return Stream.concat(stream(tags.spliterator(), false), commonTags.stream()).collect(toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.ToDoubleFunction;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;
import static java.util.stream.StreamSupport.stream;

/**
* A minimal meter registry implementation primarily used for tests.
Expand All @@ -43,21 +47,27 @@ public SimpleMeterRegistry(Clock clock) {
super(clock);
}

private Iterable<Tag> withCommonTags(Iterable<Tag> tags) {
if(commonTags.isEmpty())
return tags;
return Stream.concat(stream(tags.spliterator(), false), commonTags.stream()).collect(toList());
}

@Override
public Counter counter(String name, Iterable<Tag> tags) {
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, tags), SimpleCounter::new);
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, withCommonTags(tags)), SimpleCounter::new);
}

@Override
public DistributionSummary distributionSummary(String name, Iterable<Tag> tags, Quantiles quantiles, Histogram<?> histogram) {
registerQuantilesGaugeIfNecessary(name, tags, quantiles);
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, tags), SimpleDistributionSummary::new);
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, withCommonTags(tags)), SimpleDistributionSummary::new);
}

@Override
protected io.micrometer.core.instrument.Timer timer(String name, Iterable<Tag> tags, Quantiles quantiles, Histogram<?> histogram) {
registerQuantilesGaugeIfNecessary(name, tags, quantiles);
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, tags), id -> new SimpleTimer(id, getClock()));
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, withCommonTags(tags)), id -> new SimpleTimer(id, getClock()));
}

private void registerQuantilesGaugeIfNecessary(String name, Iterable<Tag> tags, Quantiles quantiles) {
Expand All @@ -73,7 +83,7 @@ private void registerQuantilesGaugeIfNecessary(String name, Iterable<Tag> tags,

@Override
public LongTaskTimer longTaskTimer(String name, Iterable<Tag> tags) {
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, tags), id -> new SimpleLongTaskTimer(id, getClock()));
return MapAccess.computeIfAbsent(meterMap, new MeterId(name, withCommonTags(tags)), id -> new SimpleLongTaskTimer(id, getClock()));
}

@Override
Expand All @@ -84,7 +94,7 @@ public MeterRegistry register(Meter meter) {

@Override
public <T> T gauge(String name, Iterable<Tag> tags, T obj, ToDoubleFunction<T> f) {
MapAccess.computeIfAbsent(meterMap, new MeterId(name, tags), id -> new SimpleGauge<>(id, obj, f));
MapAccess.computeIfAbsent(meterMap, new MeterId(name, withCommonTags(tags)), id -> new SimpleGauge<>(id, obj, f));
return obj;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.*;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.StreamSupport.stream;
import static io.micrometer.core.instrument.spectator.SpectatorUtils.spectatorId;
Expand Down Expand Up @@ -75,7 +76,7 @@ public long monotonicTime() {
}

private Collection<com.netflix.spectator.api.Tag> toSpectatorTags(Iterable<io.micrometer.core.instrument.Tag> tags) {
return stream(tags.spliterator(), false)
return Stream.concat(commonTags.stream(), stream(tags.spliterator(), false))
.map(t -> new BasicTag(t.getKey(), t.getValue()))
.collect(Collectors.toList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package io.micrometer.core.instrument;

import com.netflix.spectator.api.DefaultRegistry;
import io.micrometer.core.instrument.datadog.DatadogConfig;
import io.micrometer.core.instrument.datadog.DatadogMeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.micrometer.core.instrument.spectator.SpectatorMeterRegistry;
import io.prometheus.client.CollectorRegistry;
Expand All @@ -32,7 +34,23 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) th
return Stream.of(
(Object) new SpectatorMeterRegistry(new DefaultRegistry(), new MockClock()),
new PrometheusMeterRegistry(new CollectorRegistry(true), new MockClock()),
new SimpleMeterRegistry(new MockClock())
new SimpleMeterRegistry(new MockClock()),
new DatadogMeterRegistry(new MockClock(), new DatadogConfig() {
@Override
public boolean enabled() {
return false;
}

@Override
public String apiKey() {
return "DOESNOTMATTER";
}

@Override
public String get(String k) {
return null;
}
})
).map(Arguments::of);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;

class AbstractMeterRegistryTest {
/**
* A suite of tests applicable to all MeterRegistry implementations
* @author Jon Schneider
*/
class MeterRegistryTest {

@ParameterizedTest
@ArgumentsSource(MeterRegistriesProvider.class)
Expand Down Expand Up @@ -80,4 +84,15 @@ void findMetersByType(MeterRegistry registry) {
assertThat(registry.findMeter(Meter.Type.Counter, "bar", "k", "v"))
.containsSame(c2);
}

@ParameterizedTest
@ArgumentsSource(MeterRegistriesProvider.class)
@DisplayName("common tags are added to every measurement")
void addCommonTags(MeterRegistry registry) {
registry.commonTags("k", "v");
Counter c = registry.counter("foo");

assertThat(registry.findMeter(Meter.Type.Counter, "foo", "k", "v"))
.containsSame(c);
}
}

0 comments on commit 29424a0

Please sign in to comment.