diff --git a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessor.java b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessor.java index cc4027280..4a1d1b500 100644 --- a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessor.java +++ b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessor.java @@ -100,7 +100,7 @@ PreProcessedSpan preProcessSpan(Span span) { String tenantId = maybeTenantId.get(); - if (spanFilter.shouldDropSpan(span, spanTags)) { + if (spanFilter.shouldDropSpan(span, spanTags, processTags)) { // increment dropped counter at tenant level tenantToSpansDroppedCount .computeIfAbsent( diff --git a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/SpanDropFilter.java b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/SpanDropFilter.java new file mode 100644 index 000000000..ff4460b21 --- /dev/null +++ b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/SpanDropFilter.java @@ -0,0 +1,61 @@ +package org.hypertrace.core.spannormalizer.jaeger; + +public class SpanDropFilter { + + public static final String TAG_KEY = "tagKey"; + public static final String OPERATOR = "operator"; + public static final String TAG_VALUE = "tagValue"; + + public enum Operator { + EQ("EQ"), + NEQ("NEQ"), + EXISTS("EXISTS"), + CONTAINS("CONTAINS"); + + private final String value; + + Operator(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } + + private String tagKey; + private Operator operator; + private String tagValue; + + public SpanDropFilter(String tagKey, String operator, String tagValue) { + this.tagKey = tagKey; + this.operator = Operator.valueOf(operator); + this.tagValue = tagValue; + } + + public String getTagKey() { + return tagKey; + } + + public Operator getOperator() { + return operator; + } + + public String getTagValue() { + return tagValue; + } + + @Override + public String toString() { + return "SpanDropFilter{" + + "tagKey='" + + tagKey + + '\'' + + ", operator=" + + operator + + ", tagValue='" + + tagValue + + '\'' + + '}'; + } +} diff --git a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/SpanFilter.java b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/SpanFilter.java index 0a04aadec..3d04ea141 100644 --- a/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/SpanFilter.java +++ b/span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/SpanFilter.java @@ -1,10 +1,16 @@ package org.hypertrace.core.spannormalizer.jaeger; +import static org.hypertrace.core.spannormalizer.jaeger.SpanDropFilter.OPERATOR; +import static org.hypertrace.core.spannormalizer.jaeger.SpanDropFilter.TAG_KEY; +import static org.hypertrace.core.spannormalizer.jaeger.SpanDropFilter.TAG_VALUE; + import com.google.common.util.concurrent.RateLimiter; import com.typesafe.config.Config; +import com.typesafe.config.ConfigList; import io.jaegertracing.api_v2.JaegerSpanInternalModel; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -35,6 +41,8 @@ public class SpanFilter { */ private static final String SPAN_DROP_CRITERION_CONFIG = "processor.spanDropCriterion"; + private static final String SPAN_DROP_FILTERS = "processor.spanDropFilters"; + public static final String ROOT_SPAN_DROP_CRITERION_CONFIG = "processor.rootExitSpanDropCriterion"; private static final String ROOT_SPAN_ALWAYS_DROP = "alwaysDrop"; @@ -44,6 +52,8 @@ public class SpanFilter { private static final String COLON = ":"; private List>> spanDropCriterion = Collections.emptyList(); + private List> spanDropFilters = Collections.emptyList(); + ; private boolean alwaysDropRootSpan = false; private List>> rootSpanDropExclusionCriterion = Collections.emptyList(); @@ -55,6 +65,27 @@ public SpanFilter(Config config) { this.spanDropCriterion = parseStringList(criterion); } + if (config.hasPath(SPAN_DROP_FILTERS)) { + ConfigList spanDropFiltersConfig = config.getList(SPAN_DROP_FILTERS); + LOG.info("Span drop filters: {}", spanDropFiltersConfig); + this.spanDropFilters = + spanDropFiltersConfig.stream() + .map( + orFilters -> { + List> andFilters = + (List>) orFilters.unwrapped(); + return andFilters.stream() + .map( + filter -> + new SpanDropFilter( + filter.get(TAG_KEY), + filter.get(OPERATOR), + filter.get(TAG_VALUE))) + .collect(Collectors.toList()); + }) + .collect(Collectors.toList()); + } + if (config.hasPath(ROOT_SPAN_DROP_CRITERION_CONFIG)) { Config rootSpanDropCriterionConfig = config.getConfig(ROOT_SPAN_DROP_CRITERION_CONFIG); LOG.info("Root Span drop criterion: {}", rootSpanDropCriterionConfig); @@ -88,7 +119,9 @@ private List>> parseStringList(List stringList * the span should be dropped, false otherwise. */ public boolean shouldDropSpan( - JaegerSpanInternalModel.Span span, Map tags) { + JaegerSpanInternalModel.Span span, + Map tags, + Map processTags) { if (anyCriteriaMatch(tags, spanDropCriterion)) { if (DROPPED_SPANS_RATE_LIMITER.tryAcquire()) { LOG.info("Dropping span: [{}] with drop criterion: [{}]", span, spanDropCriterion); @@ -96,6 +129,13 @@ public boolean shouldDropSpan( return true; } + if (anySpanDropFiltersMatch(spanDropFilters, tags, processTags)) { + if (LOG.isDebugEnabled() && DROPPED_SPANS_RATE_LIMITER.tryAcquire()) { + LOG.debug("Dropping span: [{}] with drop filters: [{}]", span, spanDropFilters.toString()); + } + return true; + } + if (isRootExitSpan(span, tags)) { boolean anyCriteriaMatch = anyCriteriaMatch(tags, rootSpanDropExclusionCriterion); boolean shouldDropSpan = @@ -147,4 +187,37 @@ private boolean isRootExitSpan( return SPAN_KIND_CLIENT.equals(spanKindKeyValue.getVStr()); } + + private boolean anySpanDropFiltersMatch( + List> spanDropFilters, + Map tags, + Map processTags) { + return spanDropFilters.stream() + .anyMatch( + andFilters -> + andFilters.stream() + .allMatch( + filter -> + matchSpanDropFilter(filter, tags) + || matchSpanDropFilter(filter, processTags))); + } + + private boolean matchSpanDropFilter( + SpanDropFilter filter, Map tags) { + switch (filter.getOperator()) { + case EQ: + return tags.containsKey(filter.getTagKey()) + && StringUtils.equals(tags.get(filter.getTagKey()).getVStr(), filter.getTagValue()); + case NEQ: + return tags.containsKey(filter.getTagKey()) + && !StringUtils.equals(tags.get(filter.getTagKey()).getVStr(), filter.getTagValue()); + case CONTAINS: + return tags.containsKey(filter.getTagKey()) + && StringUtils.contains(tags.get(filter.getTagKey()).getVStr(), filter.getTagValue()); + case EXISTS: + return tags.containsKey(filter.getTagKey()); + default: + return false; + } + } } diff --git a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/SpanNormalizerTest.java b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/SpanNormalizerTest.java index 1c0dc513a..86aab7a4f 100644 --- a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/SpanNormalizerTest.java +++ b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/SpanNormalizerTest.java @@ -1,6 +1,8 @@ package org.hypertrace.core.spannormalizer; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.protobuf.ByteString; import com.google.protobuf.Timestamp; @@ -130,5 +132,75 @@ public void whenJaegerSpansAreProcessedExpectRawSpansToBeOutput() { KeyValue keyValue = rawLogOutputTopic.readKeyValue(); LogEvents logEvents = keyValue.value; Assertions.assertEquals(2, logEvents.getLogEvents().size()); + + // pipe in one more span which doesn't match spanDropFilters + Span span2 = + Span.newBuilder() + .setSpanId(ByteString.copyFrom("2".getBytes())) + .setTraceId(ByteString.copyFrom("trace-2".getBytes())) + .addTags( + JaegerSpanInternalModel.KeyValue.newBuilder() + .setKey("jaeger.servicename") + .setVStr(SERVICE_NAME) + .build()) + .addTags( + JaegerSpanInternalModel.KeyValue.newBuilder() + .setKey("http.method") + .setVStr("GET") + .build()) + .build(); + + inputTopic.pipeInput(span2); + KeyValue kv1 = outputTopic.readKeyValue(); + assertNotNull(kv1); + assertEquals("__default", kv1.key.getTenantId()); + assertEquals( + HexUtils.getHex(ByteString.copyFrom("trace-2".getBytes()).toByteArray()), + HexUtils.getHex(kv1.key.getTraceId().array())); + + // pipe in one more span which match one of spanDropFilters (http.method & http.url) + Span span3 = + Span.newBuilder() + .setSpanId(ByteString.copyFrom("3".getBytes())) + .setTraceId(ByteString.copyFrom("trace-3".getBytes())) + .addTags( + JaegerSpanInternalModel.KeyValue.newBuilder() + .setKey("jaeger.servicename") + .setVStr(SERVICE_NAME) + .build()) + .addTags( + JaegerSpanInternalModel.KeyValue.newBuilder() + .setKey("http.method") + .setVStr("GET") + .build()) + .addTags( + JaegerSpanInternalModel.KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/health/check") + .build()) + .build(); + + inputTopic.pipeInput(span3); + assertTrue(outputTopic.isEmpty()); + + // pipe in one more span which match one of spanDropFilters (grpc.url) + Span span4 = + Span.newBuilder() + .setSpanId(ByteString.copyFrom("3".getBytes())) + .setTraceId(ByteString.copyFrom("trace-3".getBytes())) + .addTags( + JaegerSpanInternalModel.KeyValue.newBuilder() + .setKey("jaeger.servicename") + .setVStr(SERVICE_NAME) + .build()) + .addTags( + JaegerSpanInternalModel.KeyValue.newBuilder() + .setKey("grpc.url") + .setVStr("doesn't match with input filter set") + .build()) + .build(); + + inputTopic.pipeInput(span4); + assertTrue(outputTopic.isEmpty()); } } diff --git a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessorTest.java b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessorTest.java index f7d471236..24ebc1464 100644 --- a/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessorTest.java +++ b/span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessorTest.java @@ -1,5 +1,7 @@ package org.hypertrace.core.spannormalizer.jaeger; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.typesafe.config.ConfigFactory; import io.jaegertracing.api_v2.JaegerSpanInternalModel.KeyValue; import io.jaegertracing.api_v2.JaegerSpanInternalModel.Process; @@ -19,7 +21,7 @@ class JaegerSpanPreProcessorTest { @Test void testPreProcessSpan_missingTenantId() { - Assertions.assertThrows( + assertThrows( RuntimeException.class, () -> { // span dropped since tenant detail not present @@ -393,6 +395,346 @@ public void testDropSpan_RootSpan_NotAlwaysDrop_ExclusionList() { Assertions.assertNotNull(preProcessedSpan); } + @Test + public void testSpanDropFilters() { + String tenantId = "tenant-" + random.nextLong(); + Map configs = new HashMap<>(getCommonConfig()); + configs.putAll( + Map.of( + "processor", + Map.of( + "tenantIdTagKey", + "tenant-key", + "spanDropFilters", + List.of( + List.of( + Map.of("tagKey", "http.method", "operator", "EQ", "tagValue", "GET"), + Map.of("tagKey", "http.url", "operator", "CONTAINS", "tagValue", "health")), + List.of( + Map.of( + "tagKey", "grpc.url", + "operator", "EXISTS", + "tagValue", "Sent.TestGrpcService.GetEcho"), + Map.of("tagKey", "http.method", "operator", "EQ", "tagValue", "POST")), + List.of( + Map.of( + "tagKey", "http.status_code", + "operator", "NEQ", + "tagValue", "200")))))); + JaegerSpanPreProcessor jaegerSpanPreProcessor = + new JaegerSpanPreProcessor(ConfigFactory.parseMap(configs)); + Process process = Process.newBuilder().setServiceName("testService").build(); + + // case 1: match first case (http.method & http.url) + Span span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build()) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + PreProcessedSpan preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNull(preProcessedSpan); + + // case 2: match second case (grpc.url & http.method) + span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build()) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("POST").build()) + .addTags( + KeyValue.newBuilder() + .setKey("grpc.url") + .setVStr("Sent.TestGrpcService.GetEcho.Extra") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNull(preProcessedSpan); + + // case 3: match third case (http.status_code) + span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build()) + .addTags(KeyValue.newBuilder().setKey("http.status_code").setVStr("500").build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNull(preProcessedSpan); + + // case 4 : match no filters but key exists, but value doesn't match + span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build()) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/api/v1/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("http.status_code").setVStr("200").build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNotNull(preProcessedSpan); + + // case 4 : match no filters, no key exists + span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNotNull(preProcessedSpan); + } + + @Test + public void testSpanDropFiltersWithCombinationOfProcessAndSpanTags() { + String tenantId = "tenant-" + random.nextLong(); + Map configs = new HashMap<>(getCommonConfig()); + configs.putAll( + Map.of( + "processor", + Map.of( + "tenantIdTagKey", + "tenant-key", + "spanDropFilters", + List.of( + List.of( + Map.of("tagKey", "tenant-key", "operator", "EQ", "tagValue", tenantId), + Map.of("tagKey", "http.method", "operator", "EQ", "tagValue", "GET"), + Map.of("tagKey", "http.url", "operator", "CONTAINS", "tagValue", "health")), + List.of( + Map.of( + "tagKey", + "service_name", + "operator", + "CONTAINS", + "tagValue", + "drop-service"), + Map.of( + "tagKey", "grpc.url", "operator", "EXISTS", "tagValue", "health")))))); + + JaegerSpanPreProcessor jaegerSpanPreProcessor = + new JaegerSpanPreProcessor(ConfigFactory.parseMap(configs)); + + // case 1: {spanTags: [http.method & http.url], processTags:tenant_id } matches -> drop span + + Process process = + Process.newBuilder() + .setServiceName("testService") + .addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build()) + .build(); + + Span span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + PreProcessedSpan preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNull(preProcessedSpan); + + // case 2: {spanTags: [http.method & http.url], processTags:tenant_id } not matches tenantId + process = + Process.newBuilder() + .setServiceName("testService") + .addTags( + KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId + "not-match").build()) + .build(); + + span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNotNull(preProcessedSpan); + + // case 3: {spanTags: [http.method & http.url & tenant_id], processTags:tenant_id } + // match with spanTag's tenantId -> Drop span + process = + Process.newBuilder() + .setServiceName("testService") + .addTags( + KeyValue.newBuilder() + .setKey("tenant-key") + .setVStr(tenantId + "not-match-process") + .build()) + .build(); + + span = + Span.newBuilder() + .setProcess(process) + .addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build()) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNull(preProcessedSpan); + + // case 4: {spanTags: [http.method & http.url & tenant_id], processTags:tenant_id } + // not match with spanTag or processTag tenantId + process = + Process.newBuilder() + .setServiceName("testService") + .addTags( + KeyValue.newBuilder() + .setKey("tenant-key") + .setVStr(tenantId + "not-match-process") + .build()) + .build(); + + span = + Span.newBuilder() + .setProcess(process) + .addTags( + KeyValue.newBuilder() + .setKey("tenant-key") + .setVStr(tenantId + "not-match-span") + .build()) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNotNull(preProcessedSpan); + + // case 5: {spanTags: [!grpc.url], processTags:service_name } + // contains test for processTags -> matches + // grpc.url exists in spanTags -> matches + process = + Process.newBuilder() + .setServiceName("testService") + .addTags( + KeyValue.newBuilder() + .setKey("service_name") + .setVStr("drop-service-payment") + .build()) + .build(); + + span = + Span.newBuilder() + .setProcess(process) + .addTags( + KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId + "not-match-span")) + .addTags(KeyValue.newBuilder().setKey("http.method").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("grpc.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNull(preProcessedSpan); + + // case 6: {spanTags: [!grpc.url], processTags:service_name } + // contains test for processTags -> doesn't matches + // grpc.url exists in spanTags -> match + process = + Process.newBuilder() + .setServiceName("testService") + .addTags(KeyValue.newBuilder().setKey("service_name").setVStr("payment").build()) + .build(); + + span = + Span.newBuilder() + .setProcess(process) + .addTags( + KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId + "not-match-span")) + .addTags(KeyValue.newBuilder().setKey("http.url").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("grpc.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNotNull(preProcessedSpan); + + // case 6: {spanTags: [!grpc.url], processTags:service_name } + // contains test for processTags -> doesn't matches + // grpc.url doesn't exists in spanTags + process = + Process.newBuilder() + .setServiceName("testService") + .addTags(KeyValue.newBuilder().setKey("service_name").setVStr("payment").build()) + .build(); + + span = + Span.newBuilder() + .setProcess(process) + .addTags( + KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId + "not-match-span")) + .addTags(KeyValue.newBuilder().setKey("http.url").setVStr("GET").build()) + .addTags( + KeyValue.newBuilder() + .setKey("http.url") + .setVStr("http://xyz.com/api/v1/health/check") + .build()) + .addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build()) + .build(); + preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span); + Assertions.assertNotNull(preProcessedSpan); + } + + @Test + public void testSpanDropFiltersBadConfig() { + assertThrows( + IllegalArgumentException.class, + () -> { + Map configs = new HashMap<>(getCommonConfig()); + configs.putAll( + Map.of( + "processor", + Map.of( + "tenantIdTagKey", + "tenant-key", + "spanDropFilters", + List.of( + List.of( + Map.of( + "tagKey", + "http.method", + "operator", + "EQUAL", + "tagValue", + "GET")))))); + JaegerSpanPreProcessor jaegerSpanPreProcessor = + new JaegerSpanPreProcessor(ConfigFactory.parseMap(configs)); + }); + } + private Map getCommonConfig() { return Map.of( "span.type", diff --git a/span-normalizer/span-normalizer/src/test/resources/configs/span-normalizer/application.conf b/span-normalizer/span-normalizer/src/test/resources/configs/span-normalizer/application.conf index ffb1b2cfc..5e95ca97a 100644 --- a/span-normalizer/span-normalizer/src/test/resources/configs/span-normalizer/application.conf +++ b/span-normalizer/span-normalizer/src/test/resources/configs/span-normalizer/application.conf @@ -27,3 +27,27 @@ processor { defaultTenantId = "__default" } +processor { + spanDropFilters = [ + [ + { + "tagKey": "http.method", + "operator": "EQ", + "tagValue": "GET" + }, + { + "tagKey": "http.url", + "operator": "CONTAINS", + "tagValue": "health" + } + ], + [ + { + "tagKey": "grpc.url", + "operator": "NEQ", + "tagValue": "Sent.TestServiceGetEchos" + } + ] + ] +} +