Skip to content

Commit 7610898

Browse files
Consume URL_PATH and evaluate according for span exclusion (#451)
* Consume URL_PATH and evaluate according for span exclusion * update ht config service version
1 parent ed7b189 commit 7610898

File tree

3 files changed

+307
-10
lines changed

3 files changed

+307
-10
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22
hypertrace-entity-service = "0.8.90"
33
hypertrace-attribute-service = "0.14.38"
4-
hypertrace-config-service = "0.1.54"
4+
hypertrace-config-service = "0.1.60"
55
hypertrace-grpc-utils = "0.12.6"
66
hypertrace-serviceFramework = "0.1.62"
77
hypertrace-kafkaStreams = "0.4.4"

span-normalizer/span-normalizer/src/main/java/org/hypertrace/core/spannormalizer/jaeger/ExcludeSpanRuleEvaluator.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ private boolean matchesRelationalSpanFilter(
130130
relationalSpanFilterExpression.getRightOperand(),
131131
relationalSpanFilterExpression.getOperator()))
132132
.isPresent();
133+
case FIELD_URL_PATH:
134+
Optional<String> maybeUrlPath = getUrlPath(event);
135+
return maybeUrlPath
136+
.filter(
137+
urlPath ->
138+
spanFilterMatcher.matches(
139+
urlPath,
140+
relationalSpanFilterExpression.getRightOperand(),
141+
relationalSpanFilterExpression.getOperator()))
142+
.isPresent();
133143
default:
134144
log.error("Unknown filter field: {}", field);
135145
return false;
@@ -148,6 +158,10 @@ private Optional<String> getUrl(final Event event) {
148158
.or(() -> HttpSemanticConventionUtils.getHttpPath(event));
149159
}
150160

161+
private Optional<String> getUrlPath(final Event event) {
162+
return HttpSemanticConventionUtils.getHttpPath(event);
163+
}
164+
151165
private boolean matches(
152166
Map<String, JaegerSpanInternalModel.KeyValue> tags,
153167
Map<String, JaegerSpanInternalModel.KeyValue> processTags,

span-normalizer/span-normalizer/src/test/java/org/hypertrace/core/spannormalizer/jaeger/JaegerSpanPreProcessorTest.java

Lines changed: 292 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -818,20 +818,303 @@ public void testSpanDropFiltersBadConfig() {
818818
});
819819
}
820820

821+
@Test
822+
public void testExcludeSpanRules_urlPath() throws ExecutionException {
823+
String tenantId = "tenant-" + random.nextLong();
824+
Map<String, Object> configs = new HashMap<>(getCommonConfig());
825+
configs.put(
826+
"processor",
827+
Map.of(
828+
"tenantIdTagKey",
829+
"tenant-key",
830+
"spanDropFilters",
831+
Collections.emptyList(),
832+
"late.arrival.threshold.duration",
833+
"1d"));
834+
835+
JaegerSpanPreProcessor jaegerSpanPreProcessor =
836+
new JaegerSpanPreProcessor(
837+
ConfigFactory.parseMap(configs), excludeSpanRulesCache, new GrpcChannelRegistry());
838+
839+
// case 1: {spanTags: [http.request.path], processTags:tenant_id, rule: urlPath contains
840+
// health } matches -> drop span
841+
when(excludeSpanRulesCache.get(any()))
842+
.thenReturn(
843+
List.of(
844+
ExcludeSpanRule.newBuilder()
845+
.setRuleInfo(
846+
ExcludeSpanRuleInfo.newBuilder()
847+
.setFilter(
848+
buildRelationalFilter(
849+
Field.FIELD_URL_PATH,
850+
null,
851+
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
852+
"health"))
853+
.build())
854+
.build()));
855+
856+
Process process =
857+
Process.newBuilder()
858+
.setServiceName("testService")
859+
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
860+
.build();
861+
862+
Span span =
863+
Span.newBuilder()
864+
.setProcess(process)
865+
.addTags(
866+
KeyValue.newBuilder()
867+
.setKey("http.request.path")
868+
.setVStr("/api/v1/health/check")
869+
.build())
870+
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
871+
.build();
872+
PreProcessedSpan preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
873+
Assertions.assertNull(preProcessedSpan);
874+
875+
// case 2: {spanTags: [http.request.path], processTags:tenant_id, urlPath not contains health }
876+
// should not drop span
877+
span =
878+
Span.newBuilder()
879+
.setProcess(process)
880+
.addTags(
881+
KeyValue.newBuilder().setKey("http.request.path").setVStr("/api/v1/check").build())
882+
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
883+
.build();
884+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
885+
Assertions.assertNotNull(preProcessedSpan);
886+
887+
// case 3: {spanTags: [http.path], processTags:tenant_id, rule: urlPath contains
888+
// health } matches -> drop span
889+
span =
890+
Span.newBuilder()
891+
.setProcess(process)
892+
.addTags(
893+
KeyValue.newBuilder().setKey("http.path").setVStr("/api/v1/health/check").build())
894+
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
895+
.build();
896+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
897+
Assertions.assertNull(preProcessedSpan);
898+
899+
// case 4: {spanTags: [http.target], processTags:tenant_id, rule: urlPath contains
900+
// health } matches -> drop span
901+
span =
902+
Span.newBuilder()
903+
.setProcess(process)
904+
.addTags(
905+
KeyValue.newBuilder().setKey("http.target").setVStr("/api/v1/health/check").build())
906+
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
907+
.build();
908+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
909+
Assertions.assertNull(preProcessedSpan);
910+
911+
// case 5: {spanTags: [http.request.path & tenant_id], processTags:tenant_id, rule - service
912+
// name is
913+
// testService } drop span
914+
when(excludeSpanRulesCache.get(any()))
915+
.thenReturn(
916+
List.of(
917+
ExcludeSpanRule.newBuilder()
918+
.setRuleInfo(
919+
ExcludeSpanRuleInfo.newBuilder()
920+
.setFilter(
921+
buildRelationalFilter(
922+
Field.FIELD_SERVICE_NAME,
923+
null,
924+
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
925+
"testService"))
926+
.build())
927+
.build()));
928+
process =
929+
Process.newBuilder()
930+
.setServiceName("testService")
931+
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
932+
.build();
933+
934+
span =
935+
Span.newBuilder()
936+
.setProcess(process)
937+
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
938+
.addTags(
939+
KeyValue.newBuilder().setKey("http.request.path").setVStr("/api/v1/check").build())
940+
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
941+
.build();
942+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
943+
Assertions.assertNull(preProcessedSpan);
944+
945+
// case 6: {spanTags: [http.request.path], processTags:tenant_id, url:
946+
// service name is testService and url contains health } drop span
947+
when(excludeSpanRulesCache.get(any()))
948+
.thenReturn(
949+
List.of(
950+
ExcludeSpanRule.newBuilder()
951+
.setRuleInfo(
952+
ExcludeSpanRuleInfo.newBuilder()
953+
.setFilter(
954+
buildLogicalFilterSpanProcessing(
955+
LogicalOperator.LOGICAL_OPERATOR_AND,
956+
List.of(
957+
buildRelationalFilter(
958+
Field.FIELD_SERVICE_NAME,
959+
null,
960+
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
961+
"testService"),
962+
buildRelationalFilter(
963+
Field.FIELD_URL_PATH,
964+
null,
965+
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
966+
"health"))))
967+
.build())
968+
.build()));
969+
span =
970+
Span.newBuilder()
971+
.setProcess(process)
972+
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
973+
.addTags(
974+
KeyValue.newBuilder().setKey("http.target").setVStr("/api/v1/health/check").build())
975+
.addTags(KeyValue.newBuilder().setKey("extra.tag").setVStr("extra-test-value").build())
976+
.build();
977+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
978+
Assertions.assertNull(preProcessedSpan);
979+
980+
// same as above but filter fails - should not drop span
981+
when(excludeSpanRulesCache.get(any()))
982+
.thenReturn(
983+
List.of(
984+
ExcludeSpanRule.newBuilder()
985+
.setRuleInfo(
986+
ExcludeSpanRuleInfo.newBuilder()
987+
.setFilter(
988+
buildLogicalFilterSpanProcessing(
989+
LogicalOperator.LOGICAL_OPERATOR_AND,
990+
List.of(
991+
buildRelationalFilter(
992+
Field.FIELD_SERVICE_NAME,
993+
null,
994+
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
995+
"testServiceAttribute"),
996+
buildRelationalFilter(
997+
Field.FIELD_URL_PATH,
998+
null,
999+
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
1000+
"health"))))
1001+
.build())
1002+
.build()));
1003+
1004+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
1005+
Assertions.assertNotNull(preProcessedSpan);
1006+
1007+
// case7 : {[http.request.path, deployment.environment], rule -> env equals env1 and url
1008+
// contains health}
1009+
// drop span
1010+
when(excludeSpanRulesCache.get(any()))
1011+
.thenReturn(
1012+
List.of(
1013+
ExcludeSpanRule.newBuilder()
1014+
.setRuleInfo(
1015+
ExcludeSpanRuleInfo.newBuilder()
1016+
.setFilter(
1017+
buildLogicalFilterSpanProcessing(
1018+
LogicalOperator.LOGICAL_OPERATOR_AND,
1019+
List.of(
1020+
buildRelationalFilter(
1021+
Field.FIELD_ENVIRONMENT_NAME,
1022+
null,
1023+
RelationalOperator.RELATIONAL_OPERATOR_EQUALS,
1024+
"env1"),
1025+
buildRelationalFilter(
1026+
Field.FIELD_URL_PATH,
1027+
null,
1028+
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
1029+
"health"))))
1030+
.build())
1031+
.build()));
1032+
span =
1033+
Span.newBuilder()
1034+
.setProcess(process)
1035+
.addTags(KeyValue.newBuilder().setKey("tenant-key").setVStr(tenantId).build())
1036+
.addTags(KeyValue.newBuilder().setKey("deployment.environment").setVStr("env1").build())
1037+
.addTags(
1038+
KeyValue.newBuilder()
1039+
.setKey("http.request.path")
1040+
.setVStr("/api/v1/health/check")
1041+
.build())
1042+
.build();
1043+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
1044+
Assertions.assertNull(preProcessedSpan);
1045+
1046+
// case8 : {[http.request.path, deployment.environment], rule -> env in [env,env1] and url
1047+
// contains
1048+
// health}
1049+
// drop span
1050+
when(excludeSpanRulesCache.get(any()))
1051+
.thenReturn(
1052+
List.of(
1053+
ExcludeSpanRule.newBuilder()
1054+
.setRuleInfo(
1055+
ExcludeSpanRuleInfo.newBuilder()
1056+
.setFilter(
1057+
buildLogicalFilterSpanProcessing(
1058+
LogicalOperator.LOGICAL_OPERATOR_AND,
1059+
List.of(
1060+
buildRelationalFilter(
1061+
null,
1062+
"deployment.environment",
1063+
RelationalOperator.RELATIONAL_OPERATOR_IN,
1064+
List.of("env", "env1")),
1065+
buildRelationalFilter(
1066+
Field.FIELD_URL_PATH,
1067+
null,
1068+
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
1069+
"health"))))
1070+
.build())
1071+
.build()));
1072+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
1073+
Assertions.assertNull(preProcessedSpan);
1074+
1075+
// case9 : {[http.request.path, deployment.environment], rule -> env in [env,env2] and url
1076+
// contains
1077+
// health}
1078+
// should not drop span
1079+
when(excludeSpanRulesCache.get(any()))
1080+
.thenReturn(
1081+
List.of(
1082+
ExcludeSpanRule.newBuilder()
1083+
.setRuleInfo(
1084+
ExcludeSpanRuleInfo.newBuilder()
1085+
.setFilter(
1086+
buildLogicalFilterSpanProcessing(
1087+
LogicalOperator.LOGICAL_OPERATOR_AND,
1088+
List.of(
1089+
buildRelationalFilter(
1090+
null,
1091+
"deployment.environment",
1092+
RelationalOperator.RELATIONAL_OPERATOR_IN,
1093+
List.of("env", "env2")),
1094+
buildRelationalFilter(
1095+
Field.FIELD_URL_PATH,
1096+
null,
1097+
RelationalOperator.RELATIONAL_OPERATOR_CONTAINS,
1098+
"health"))))
1099+
.build())
1100+
.build()));
1101+
preProcessedSpan = jaegerSpanPreProcessor.preProcessSpan(span);
1102+
Assertions.assertNotNull(preProcessedSpan);
1103+
}
1104+
8211105
@Test
8221106
public void testExcludeSpanRules() throws ExecutionException {
8231107
String tenantId = "tenant-" + random.nextLong();
8241108
Map<String, Object> configs = new HashMap<>(getCommonConfig());
825-
configs.putAll(
1109+
configs.put(
1110+
"processor",
8261111
Map.of(
827-
"processor",
828-
Map.of(
829-
"tenantIdTagKey",
830-
"tenant-key",
831-
"spanDropFilters",
832-
Collections.emptyList(),
833-
"late.arrival.threshold.duration",
834-
"1d")));
1112+
"tenantIdTagKey",
1113+
"tenant-key",
1114+
"spanDropFilters",
1115+
Collections.emptyList(),
1116+
"late.arrival.threshold.duration",
1117+
"1d"));
8351118

8361119
JaegerSpanPreProcessor jaegerSpanPreProcessor =
8371120
new JaegerSpanPreProcessor(

0 commit comments

Comments
 (0)