Skip to content

Commit

Permalink
Add AttributesProcessor toString, add attribute filter helper (#5765)
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-berg authored Aug 25, 2023
1 parent 2f7b3c2 commit 2deb6d1
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.metrics.ViewBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.metrics.ViewBuilder setAttributeFilter(java.util.Set<java.lang.String>)
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@

package io.opentelemetry.sdk.metrics;

import static io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor.setIncludes;

import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil;
import io.opentelemetry.sdk.metrics.internal.aggregator.AggregatorFactory;
import io.opentelemetry.sdk.metrics.internal.state.MetricStorage;
import io.opentelemetry.sdk.metrics.internal.view.AttributesProcessor;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -64,6 +67,12 @@ public ViewBuilder setAggregation(Aggregation aggregation) {
return this;
}

/** Sets a filter which retains attribute keys included in {@code keysToRetain}. */
public ViewBuilder setAttributeFilter(Set<String> keysToRetain) {
Objects.requireNonNull(keysToRetain, "keysToRetain");
return setAttributeFilter(setIncludes(keysToRetain));
}

/**
* Sets a filter for attributes keys.
*
Expand All @@ -73,7 +82,8 @@ public ViewBuilder setAggregation(Aggregation aggregation) {
*/
public ViewBuilder setAttributeFilter(Predicate<String> keyFilter) {
Objects.requireNonNull(keyFilter, "keyFilter");
return addAttributesProcessor(AttributesProcessor.filterByKeyName(keyFilter));
this.processor = AttributesProcessor.filterByKeyName(keyFilter);
return this;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
import static io.opentelemetry.sdk.metrics.internal.view.NoopAttributesProcessor.NOOP;

import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.context.Context;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import java.util.Set;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import javax.annotation.concurrent.Immutable;

/**
Expand Down Expand Up @@ -73,11 +73,7 @@ public static AttributesProcessor noop() {
* @param nameFilter a filter for which attribute keys to preserve.
*/
public static AttributesProcessor filterByKeyName(Predicate<String> nameFilter) {
return simple(
incoming ->
incoming.toBuilder()
.removeIf(attributeKey -> !nameFilter.test(attributeKey.getKey()))
.build());
return new AttributeKeyFilteringProcessor(nameFilter);
}

/**
Expand All @@ -88,19 +84,7 @@ public static AttributesProcessor filterByKeyName(Predicate<String> nameFilter)
* @param nameFilter a filter for which baggage keys to select.
*/
public static AttributesProcessor appendBaggageByKeyName(Predicate<String> nameFilter) {
return onBaggage(
(incoming, baggage) -> {
AttributesBuilder result = Attributes.builder();
baggage.forEach(
(k, v) -> {
if (nameFilter.test(k)) {
result.put(k, v.getValue());
}
});
// Override any baggage keys with existing keys.
result.putAll(incoming);
return result.build();
});
return new BaggageAppendingAttributesProcessor(nameFilter);
}

/**
Expand All @@ -111,43 +95,126 @@ public static AttributesProcessor appendBaggageByKeyName(Predicate<String> nameF
* @param attributes Attributes to append to measurements.
*/
public static AttributesProcessor append(Attributes attributes) {
return simple(incoming -> attributes.toBuilder().putAll(incoming).build());
return new AppendingAttributesProcessor(attributes);
}

/** Creates a simple attributes processor with no access to context. */
static AttributesProcessor simple(UnaryOperator<Attributes> processor) {
return new AttributesProcessor() {
/** Creates a {@link Predicate} which tests if the {@code set} includes the input. */
public static Predicate<String> setIncludes(Set<String> set) {
return new SetIncludesPredicate(set);
}

@Override
public Attributes process(Attributes incoming, Context context) {
return processor.apply(incoming);
}
/** Predicate which tests if the {@code set} includes the input. */
private static class SetIncludesPredicate implements Predicate<String> {
private final Set<String> set;

@Override
public boolean usesContext() {
return false;
}
};
private SetIncludesPredicate(Set<String> set) {
this.set = set;
}

@Override
public boolean test(String s) {
return set.contains(s);
}

@Override
public String toString() {
return "SetIncludesPredicate{set=" + set + "}";
}
}

/** Creates an Attributes processor that has access to baggage. */
static AttributesProcessor onBaggage(BiFunction<Attributes, Baggage, Attributes> processor) {
return new AttributesProcessor() {
@Override
public Attributes process(Attributes incoming, Context context) {
return processor.apply(incoming, Baggage.fromContext(context));
}
/**
* Processor which filters attributes according to a {@link AttributeKey#getKey()} {@link
* Predicate}.
*/
private static class AttributeKeyFilteringProcessor extends AttributesProcessor {

@Override
public boolean usesContext() {
return true;
}
};
private final Predicate<String> nameFilter;

private AttributeKeyFilteringProcessor(Predicate<String> nameFilter) {
this.nameFilter = nameFilter;
}

@Override
public Attributes process(Attributes incoming, Context context) {
return incoming.toBuilder()
.removeIf(attributeKey -> !nameFilter.test(attributeKey.getKey()))
.build();
}

@Override
public boolean usesContext() {
return false;
}

@Override
public String toString() {
return "AttributeKeyFilteringProcessor{nameFilter=" + nameFilter + "}";
}
}

/** Processor which appends a static set of {@link Attributes}. */
private static class AppendingAttributesProcessor extends AttributesProcessor {

private final Attributes additionalAttributes;

private AppendingAttributesProcessor(Attributes additionalAttributes) {
this.additionalAttributes = additionalAttributes;
}

@Override
public Attributes process(Attributes incoming, Context context) {
return additionalAttributes.toBuilder().putAll(incoming).build();
}

@Override
public boolean usesContext() {
return false;
}

@Override
public String toString() {
return "AppendingAttributesProcessor{additionalAttributes=" + additionalAttributes + "}";
}
}

/** Processor which appends entries from {@link Baggage} with keys that match a predicate. */
private static final class BaggageAppendingAttributesProcessor extends AttributesProcessor {

private final Predicate<String> nameFilter;

private BaggageAppendingAttributesProcessor(Predicate<String> nameFilter) {
this.nameFilter = nameFilter;
}

@Override
public Attributes process(Attributes incoming, Context context) {
AttributesBuilder result = Attributes.builder();
Baggage.fromContext(context)
.forEach(
(k, v) -> {
if (nameFilter.test(k)) {
result.put(k, v.getValue());
}
});
// Override any baggage keys with existing keys.
result.putAll(incoming);
return result.build();
}

@Override
public boolean usesContext() {
return true;
}

@Override
public String toString() {
return "BaggageAppendingAttributesProcessor{nameFilter=" + nameFilter + "}";
}
}

/** A {@link AttributesProcessor} that runs a sequence of processors. */
@Immutable
static final class JoinedAttributesProcessor extends AttributesProcessor {
private static final class JoinedAttributesProcessor extends AttributesProcessor {
private final Collection<AttributesProcessor> processors;
private final boolean usesContextCache;

Expand Down Expand Up @@ -188,5 +255,10 @@ AttributesProcessor prepend(AttributesProcessor other) {
newList.addAll(processors);
return new JoinedAttributesProcessor(newList);
}

@Override
public String toString() {
return "JoinedAttributesProcessor{processors=" + processors + "}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;
import java.util.HashSet;
import org.junit.jupiter.api.Test;

class ViewTest {
Expand All @@ -26,14 +28,15 @@ void stringRepresentation() {
.setDescription("description")
.setAggregation(Aggregation.sum())
.setCardinalityLimit(10)
.setAttributeFilter(new HashSet<>(Arrays.asList("key1", "key2")))
.build()
.toString())
.isEqualTo(
"View{"
+ "name=name, "
+ "description=description, "
+ "aggregation=SumAggregation, "
+ "attributesProcessor=NoopAttributesProcessor{}, "
+ "attributesProcessor=AttributeKeyFilteringProcessor{nameFilter=SetIncludesPredicate{set=[key1, key2]}}, "
+ "cardinalityLimit=10"
+ "}");
}
Expand Down
Loading

0 comments on commit 2deb6d1

Please sign in to comment.