@@ -877,6 +877,173 @@ fn test_peer_tags_aggregation() {
877877 ) ;
878878}
879879
880+ /// Test that internal spans with _dd.base_service use it as their sole peer tag
881+ #[ test]
882+ fn test_base_service_peer_tag ( ) {
883+ let now = SystemTime :: now ( ) ;
884+ let mut spans = vec ! [
885+ // Regular internal span without base_service (no peer tags)
886+ get_test_span_with_meta(
887+ now,
888+ 1 ,
889+ 0 ,
890+ 100 ,
891+ 5 ,
892+ "A1" ,
893+ "internal.operation" ,
894+ 0 ,
895+ & [ ] ,
896+ & [ ( "_dd.measured" , 1.0 ) ] ,
897+ ) ,
898+ // Internal span with _dd.base_service (should have base_service as peer tag)
899+ get_test_span_with_meta(
900+ now,
901+ 2 ,
902+ 0 ,
903+ 75 ,
904+ 5 ,
905+ "A1" ,
906+ "internal.with.base.service" ,
907+ 0 ,
908+ & [ ( "_dd.base_service" , "original-service" ) ] ,
909+ & [ ( "_dd.measured" , 1.0 ) ] ,
910+ ) ,
911+ // Another internal span with same _dd.base_service (should aggregate together)
912+ get_test_span_with_meta(
913+ now,
914+ 3 ,
915+ 0 ,
916+ 50 ,
917+ 5 ,
918+ "A1" ,
919+ "internal.with.base.service" ,
920+ 0 ,
921+ & [ ( "_dd.base_service" , "original-service" ) ] ,
922+ & [ ( "_dd.measured" , 1.0 ) ] ,
923+ ) ,
924+ // Internal span with different _dd.base_service (should be separate group)
925+ get_test_span_with_meta(
926+ now,
927+ 4 ,
928+ 0 ,
929+ 60 ,
930+ 5 ,
931+ "A1" ,
932+ "internal.with.base.service" ,
933+ 0 ,
934+ & [ ( "_dd.base_service" , "other-service" ) ] ,
935+ & [ ( "_dd.measured" , 1.0 ) ] ,
936+ ) ,
937+ // Client span with _dd.base_service and other peer tags enabled
938+ // (should use configured peer tags, not base_service)
939+ get_test_span_with_meta(
940+ now,
941+ 5 ,
942+ 0 ,
943+ 80 ,
944+ 5 ,
945+ "A1" ,
946+ "SELECT * FROM users" ,
947+ 0 ,
948+ & [
949+ ( "span.kind" , "client" ) ,
950+ ( "_dd.base_service" , "ignored-for-client" ) ,
951+ ( "db.instance" , "i-1234" ) ,
952+ ( "db.system" , "postgres" ) ,
953+ ] ,
954+ & [ ( "_dd.measured" , 1.0 ) ] ,
955+ ) ,
956+ ] ;
957+ compute_top_level_span ( spans. as_mut_slice ( ) ) ;
958+
959+ let mut concentrator = SpanConcentrator :: new (
960+ Duration :: from_nanos ( BUCKET_SIZE ) ,
961+ now,
962+ get_span_kinds ( ) ,
963+ vec ! [ "db.instance" . to_string( ) , "db.system" . to_string( ) ] ,
964+ ) ;
965+
966+ for span in & spans {
967+ concentrator. add_span ( span) ;
968+ }
969+
970+ let flushtime =
971+ now + Duration :: from_nanos ( concentrator. bucket_size * concentrator. buffer_len as u64 ) ;
972+
973+ let expected = vec ! [
974+ // Internal span without base_service - no peer tags
975+ pb:: ClientGroupedStats {
976+ service: "A1" . to_string( ) ,
977+ resource: "internal.operation" . to_string( ) ,
978+ r#type: "db" . to_string( ) ,
979+ name: "query" . to_string( ) ,
980+ duration: 100 ,
981+ hits: 1 ,
982+ top_level_hits: 1 ,
983+ errors: 0 ,
984+ is_trace_root: pb:: Trilean :: True . into( ) ,
985+ ..Default :: default ( )
986+ } ,
987+ // Internal spans with _dd.base_service="original-service" - aggregated with base_service
988+ // peer tag
989+ pb:: ClientGroupedStats {
990+ service: "A1" . to_string( ) ,
991+ resource: "internal.with.base.service" . to_string( ) ,
992+ r#type: "db" . to_string( ) ,
993+ name: "query" . to_string( ) ,
994+ peer_tags: vec![ "_dd.base_service:original-service" . to_string( ) ] ,
995+ duration: 125 ,
996+ hits: 2 ,
997+ top_level_hits: 2 ,
998+ errors: 0 ,
999+ is_trace_root: pb:: Trilean :: True . into( ) ,
1000+ ..Default :: default ( )
1001+ } ,
1002+ // Internal span with _dd.base_service="other-service" - separate group
1003+ pb:: ClientGroupedStats {
1004+ service: "A1" . to_string( ) ,
1005+ resource: "internal.with.base.service" . to_string( ) ,
1006+ r#type: "db" . to_string( ) ,
1007+ name: "query" . to_string( ) ,
1008+ peer_tags: vec![ "_dd.base_service:other-service" . to_string( ) ] ,
1009+ duration: 60 ,
1010+ hits: 1 ,
1011+ top_level_hits: 1 ,
1012+ errors: 0 ,
1013+ is_trace_root: pb:: Trilean :: True . into( ) ,
1014+ ..Default :: default ( )
1015+ } ,
1016+ // Client span - uses configured peer tags, not base_service
1017+ pb:: ClientGroupedStats {
1018+ service: "A1" . to_string( ) ,
1019+ resource: "SELECT * FROM users" . to_string( ) ,
1020+ r#type: "db" . to_string( ) ,
1021+ name: "query" . to_string( ) ,
1022+ span_kind: "client" . to_string( ) ,
1023+ peer_tags: vec![
1024+ "db.instance:i-1234" . to_string( ) ,
1025+ "db.system:postgres" . to_string( ) ,
1026+ ] ,
1027+ duration: 80 ,
1028+ hits: 1 ,
1029+ top_level_hits: 1 ,
1030+ errors: 0 ,
1031+ is_trace_root: pb:: Trilean :: True . into( ) ,
1032+ ..Default :: default ( )
1033+ } ,
1034+ ] ;
1035+
1036+ let stats = concentrator. flush ( flushtime, false ) ;
1037+ assert_counts_equal (
1038+ expected,
1039+ stats
1040+ . first ( )
1041+ . expect ( "There should be at least one time bucket" )
1042+ . stats
1043+ . clone ( ) ,
1044+ ) ;
1045+ }
1046+
8801047#[ test]
8811048fn test_compute_stats_for_span_kind ( ) {
8821049 let test_cases: Vec < ( SpanSlice , bool ) > = vec ! [
0 commit comments