Skip to content

Commit

Permalink
Consume URL_PATH and evaluate according for span exclusion (#451)
Browse files Browse the repository at this point in the history
* Consume URL_PATH and evaluate according for span exclusion

* update ht config service version
  • Loading branch information
sanket-mundra authored Feb 14, 2024
1 parent ed7b189 commit 7610898
Show file tree
Hide file tree
Showing 3 changed files with 307 additions and 10 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[versions]
hypertrace-entity-service = "0.8.90"
hypertrace-attribute-service = "0.14.38"
hypertrace-config-service = "0.1.54"
hypertrace-config-service = "0.1.60"
hypertrace-grpc-utils = "0.12.6"
hypertrace-serviceFramework = "0.1.62"
hypertrace-kafkaStreams = "0.4.4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ private boolean matchesRelationalSpanFilter(
relationalSpanFilterExpression.getRightOperand(),
relationalSpanFilterExpression.getOperator()))
.isPresent();
case FIELD_URL_PATH:
Optional<String> maybeUrlPath = getUrlPath(event);
return maybeUrlPath
.filter(
urlPath ->
spanFilterMatcher.matches(
urlPath,
relationalSpanFilterExpression.getRightOperand(),
relationalSpanFilterExpression.getOperator()))
.isPresent();
default:
log.error("Unknown filter field: {}", field);
return false;
Expand All @@ -148,6 +158,10 @@ private Optional<String> getUrl(final Event event) {
.or(() -> HttpSemanticConventionUtils.getHttpPath(event));
}

private Optional<String> getUrlPath(final Event event) {
return HttpSemanticConventionUtils.getHttpPath(event);
}

private boolean matches(
Map<String, JaegerSpanInternalModel.KeyValue> tags,
Map<String, JaegerSpanInternalModel.KeyValue> processTags,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -818,20 +818,303 @@ public void testSpanDropFiltersBadConfig() {
});
}

@Test
public void testExcludeSpanRules_urlPath() throws ExecutionException {
String tenantId = "tenant-" + random.nextLong();
Map<String, Object> configs = new HashMap<>(getCommonConfig());
configs.put(
"processor",
Map.of(
"tenantIdTagKey",
"tenant-key",
"spanDropFilters",
Collections.emptyList(),
"late.arrival.threshold.duration",
"1d"));

JaegerSpanPreProcessor jaegerSpanPreProcessor =
new JaegerSpanPreProcessor(
ConfigFactory.parseMap(configs), excludeSpanRulesCache, new GrpcChannelRegistry());

// case 1: {spanTags: [http.request.path], processTags:tenant_id, rule: urlPath contains
// health } matches -> drop span
when(excludeSpanRulesCache.get(any()))
.thenReturn(
List.of(
ExcludeSpanRule.newBuilder()
.setRuleInfo(
ExcludeSpanRuleInfo.newBuilder()
.setFilter(
buildRelationalFilter(
Field.FIELD_URL_PATH,
null,
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
"health"))
.build())
.build()));

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.request.path")
.setVStr("/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.request.path], processTags:tenant_id, urlPath not contains health }
// should not drop span
span =
Span.newBuilder()
.setProcess(process)
.addTags(
KeyValue.newBuilder().setKey("http.request.path").setVStr("/api/v1/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.path], processTags:tenant_id, rule: urlPath contains
// health } matches -> drop span
span =
Span.newBuilder()
.setProcess(process)
.addTags(
KeyValue.newBuilder().setKey("http.path").setVStr("/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.target], processTags:tenant_id, rule: urlPath contains
// health } matches -> drop span
span =
Span.newBuilder()
.setProcess(process)
.addTags(
KeyValue.newBuilder().setKey("http.target").setVStr("/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 5: {spanTags: [http.request.path & tenant_id], processTags:tenant_id, rule - service
// name is
// testService } drop span
when(excludeSpanRulesCache.get(any()))
.thenReturn(
List.of(
ExcludeSpanRule.newBuilder()
.setRuleInfo(
ExcludeSpanRuleInfo.newBuilder()
.setFilter(
buildRelationalFilter(
Field.FIELD_SERVICE_NAME,
null,
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
"testService"))
.build())
.build()));
process =
Process.newBuilder()
.setServiceName("testService")
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
.build();

span =
Span.newBuilder()
.setProcess(process)
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
.addTags(
KeyValue.newBuilder().setKey("http.request.path").setVStr("/api/v1/check").build())
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
.build();
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
Assertions.assertNull(preProcessedSpan);

// case 6: {spanTags: [http.request.path], processTags:tenant_id, url:
// service name is testService and url contains health } drop span
when(excludeSpanRulesCache.get(any()))
.thenReturn(
List.of(
ExcludeSpanRule.newBuilder()
.setRuleInfo(
ExcludeSpanRuleInfo.newBuilder()
.setFilter(
buildLogicalFilterSpanProcessing(
LogicalOperator.LOGICAL_OPERATOR_AND,
List.of(
buildRelationalFilter(
Field.FIELD_SERVICE_NAME,
null,
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
"testService"),
buildRelationalFilter(
Field.FIELD_URL_PATH,
null,
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
"health"))))
.build())
.build()));
span =
Span.newBuilder()
.setProcess(process)
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
.addTags(
KeyValue.newBuilder().setKey("http.target").setVStr("/api/v1/health/check").build())
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
.build();
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
Assertions.assertNull(preProcessedSpan);

// same as above but filter fails - should not drop span
when(excludeSpanRulesCache.get(any()))
.thenReturn(
List.of(
ExcludeSpanRule.newBuilder()
.setRuleInfo(
ExcludeSpanRuleInfo.newBuilder()
.setFilter(
buildLogicalFilterSpanProcessing(
LogicalOperator.LOGICAL_OPERATOR_AND,
List.of(
buildRelationalFilter(
Field.FIELD_SERVICE_NAME,
null,
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
"testServiceAttribute"),
buildRelationalFilter(
Field.FIELD_URL_PATH,
null,
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
"health"))))
.build())
.build()));

preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
Assertions.assertNotNull(preProcessedSpan);

// case7 : {[http.request.path, deployment.environment], rule -> env equals env1 and url
// contains health}
// drop span
when(excludeSpanRulesCache.get(any()))
.thenReturn(
List.of(
ExcludeSpanRule.newBuilder()
.setRuleInfo(
ExcludeSpanRuleInfo.newBuilder()
.setFilter(
buildLogicalFilterSpanProcessing(
LogicalOperator.LOGICAL_OPERATOR_AND,
List.of(
buildRelationalFilter(
Field.FIELD_ENVIRONMENT_NAME,
null,
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
"env1"),
buildRelationalFilter(
Field.FIELD_URL_PATH,
null,
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
"health"))))
.build())
.build()));
span =
Span.newBuilder()
.setProcess(process)
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
.addTags(KeyValue.newBuilder().setKey("deployment.environment").setVStr("env1").build())
.addTags(
KeyValue.newBuilder()
.setKey("http.request.path")
.setVStr("/api/v1/health/check")
.build())
.build();
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
Assertions.assertNull(preProcessedSpan);

// case8 : {[http.request.path, deployment.environment], rule -> env in [env,env1] and url
// contains
// health}
// drop span
when(excludeSpanRulesCache.get(any()))
.thenReturn(
List.of(
ExcludeSpanRule.newBuilder()
.setRuleInfo(
ExcludeSpanRuleInfo.newBuilder()
.setFilter(
buildLogicalFilterSpanProcessing(
LogicalOperator.LOGICAL_OPERATOR_AND,
List.of(
buildRelationalFilter(
null,
"deployment.environment",
RelationalOperator.RELATIONAL_OPERATOR_IN,
List.of("env", "env1")),
buildRelationalFilter(
Field.FIELD_URL_PATH,
null,
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
"health"))))
.build())
.build()));
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
Assertions.assertNull(preProcessedSpan);

// case9 : {[http.request.path, deployment.environment], rule -> env in [env,env2] and url
// contains
// health}
// should not drop span
when(excludeSpanRulesCache.get(any()))
.thenReturn(
List.of(
ExcludeSpanRule.newBuilder()
.setRuleInfo(
ExcludeSpanRuleInfo.newBuilder()
.setFilter(
buildLogicalFilterSpanProcessing(
LogicalOperator.LOGICAL_OPERATOR_AND,
List.of(
buildRelationalFilter(
null,
"deployment.environment",
RelationalOperator.RELATIONAL_OPERATOR_IN,
List.of("env", "env2")),
buildRelationalFilter(
Field.FIELD_URL_PATH,
null,
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
"health"))))
.build())
.build()));
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
Assertions.assertNotNull(preProcessedSpan);
}

@Test
public void testExcludeSpanRules() throws ExecutionException {
String tenantId = "tenant-" + random.nextLong();
Map<String, Object> configs = new HashMap<>(getCommonConfig());
configs.putAll(
configs.put(
"processor",
Map.of(
"processor",
Map.of(
"tenantIdTagKey",
"tenant-key",
"spanDropFilters",
Collections.emptyList(),
"late.arrival.threshold.duration",
"1d")));
"tenantIdTagKey",
"tenant-key",
"spanDropFilters",
Collections.emptyList(),
"late.arrival.threshold.duration",
"1d"));

JaegerSpanPreProcessor jaegerSpanPreProcessor =
new JaegerSpanPreProcessor(
Expand Down

0 comments on commit 7610898

Please sign in to comment.