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

TaggedMetricRegistry composability #81

Merged
merged 9 commits into from
Jun 26, 2018
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
1 change: 1 addition & 0 deletions tritium-registry/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dependencies {
processor 'com.google.auto.service:auto-service'
processor 'org.immutables:value'

compile 'com.google.guava:guava'
compile 'com.palantir.safe-logging:safe-logging'
compile 'io.dropwizard.metrics:metrics-core'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
import com.codahale.metrics.Metric;
import com.codahale.metrics.Timer;
import com.google.auto.service.AutoService;
import java.util.Collections;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -36,6 +37,7 @@ public final class DefaultTaggedMetricRegistry implements TaggedMetricRegistry {
private static final TaggedMetricRegistry DEFAULT = new DefaultTaggedMetricRegistry();

private final Map<MetricName, Metric> registry = new ConcurrentHashMap<>();
private final Map<Map.Entry<String, String>, TaggedMetricSet> taggedRegistries = new ConcurrentHashMap<>();

public DefaultTaggedMetricRegistry() {}

Expand Down Expand Up @@ -93,14 +95,34 @@ public Timer timer(MetricName metricName, Supplier<Timer> timerSupplier) {

@Override
public Map<MetricName, Metric> getMetrics() {
return Collections.unmodifiableMap(registry);
ImmutableMap.Builder<MetricName, Metric> result = ImmutableMap.<MetricName, Metric>builder()
.putAll(registry);
taggedRegistries.forEach((tag, metrics) -> metrics.getMetrics()
.forEach((metricName, metric) -> result.put(
MetricName.builder()
.from(metricName)
.putSafeTags(tag.getKey(), tag.getValue())
.build(),
metric)));

return result.build();
}

@Override
public Optional<Metric> remove(MetricName metricName) {
return Optional.ofNullable(registry.remove(metricName));
}

@Override
public void addMetrics(String safeTagName, String safeTagValue, TaggedMetricSet other) {
taggedRegistries.put(Maps.immutableEntry(safeTagName, safeTagValue), other);
}

@Override
public Optional<TaggedMetricSet> removeMetrics(String safeTagName, String safeTagValue) {
return Optional.ofNullable(taggedRegistries.remove(Maps.immutableEntry(safeTagName, safeTagValue)));
}

private <T extends Metric> T getOrAdd(MetricName metricName, Class<T> metricClass, Supplier<T> metricSupplier) {
Metric metric = registry.computeIfAbsent(metricName, name -> metricSupplier.get());
if (!metricClass.isInstance(metric)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.tritium.metrics.registry;

import static java.util.stream.Collectors.toMap;

import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricSet;
import java.util.Map;

public final class DropwizardTaggedMetricSet implements TaggedMetricSet {
private final MetricSet metricSet;

public DropwizardTaggedMetricSet(MetricSet metricSet) {
this.metricSet = metricSet;
}

@Override
public Map<MetricName, Metric> getMetrics() {
return metricSet.getMetrics().entrySet().stream()
.collect(toMap(entry -> MetricName.builder().safeName(entry.getKey()).build(), Map.Entry::getValue));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
import com.codahale.metrics.Meter;
import com.codahale.metrics.Metric;
import com.codahale.metrics.Timer;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

/**
* Similar to {@link com.codahale.metrics.MetricRegistry} but allows tagging of {@link Metric}s.
*/
public interface TaggedMetricRegistry {
public interface TaggedMetricRegistry extends TaggedMetricSet {

/**
* Returns existing or new timer metric for the specified metric name.
Expand Down Expand Up @@ -81,13 +80,6 @@ public interface TaggedMetricRegistry {

Counter counter(MetricName metricName, Supplier<Counter> counterSupplier);

/**
* Returns a map of registered metrics.
*
* @return map of registered metrics
*/
Map<MetricName, Metric> getMetrics();
Copy link
Contributor

Choose a reason for hiding this comment

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

I haven't looked at how painful the API break would be, do you have a sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's not actually an API break; it's just moved into the super interface


/**
* Removes the tagged metric with the specified metric name.
*
Expand All @@ -96,4 +88,24 @@ public interface TaggedMetricRegistry {
*/
Optional<Metric> remove(MetricName metricName);

/**
* Adds a set of metrics to this TaggedMetricRegistry's metric set,
* which are to be uniquely identified by the tags provided.
* <p>
* So, if I have a metric registry with a single metric called 'foo', and I add it
* with tag (bar, baz), this registry will now contain 'foo', tagged with (bar, baz).
* <p>
* If a metric exists with duplicate tags, then calling {@link TaggedMetricSet#getMetrics}
* will be impossible.
*
* @param safeTagName a tag key which should be added to all metrics in the metrics set
* @param safeTagValue a tag value which should be added to all metrics in the metrics set
* @param metrics the metrics which should be added
*/
void addMetrics(String safeTagName, String safeTagValue, TaggedMetricSet metrics);

/**
* Removes a TaggedMetricsSet added via addMetrics from this metrics set.
*/
Optional<TaggedMetricSet> removeMetrics(String safeTagName, String safeTagValue);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.tritium.metrics.registry;

import com.codahale.metrics.Metric;
import java.util.Map;

public interface TaggedMetricSet {
/**
* Returns a map of metrics.
*
* @return map of metrics
*/
Map<MetricName, Metric> getMetrics();
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,18 @@ public void testRemoveMetric() {

assertThat(registry.remove(METRIC_1).isPresent()).isFalse();
}

@Test
public void testAddMetricRegistry() {
String name = "name";
String tagKey = "tagKey";
String tagValue = "tagValue";
TaggedMetricRegistry child = new DefaultTaggedMetricRegistry();
Meter meter = child.meter(MetricName.builder().safeName(name).build());
registry.addMetrics(tagKey, tagValue, child);
assertThat(registry.getMetrics())
.containsEntry(MetricName.builder().safeName(name).putSafeTags(tagKey, tagValue).build(), meter);
registry.removeMetrics(tagKey, tagValue);
assertThat(registry.getMetrics()).isEmpty();
}
}