@@ -877,7 +877,172 @@ fn test_peer_tags_aggregation() {
877877 ) ;
878878}
879879
880+ /// Test that internal spans with _dd.base_service use it as their sole peer tag
880881#[ 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 = now
971+ + 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 peer tag
988+ pb:: ClientGroupedStats {
989+ service: "A1" . to_string( ) ,
990+ resource: "internal.with.base.service" . to_string( ) ,
991+ r#type: "db" . to_string( ) ,
992+ name: "query" . to_string( ) ,
993+ peer_tags: vec![ "_dd.base_service:original-service" . to_string( ) ] ,
994+ duration: 125 ,
995+ hits: 2 ,
996+ top_level_hits: 2 ,
997+ errors: 0 ,
998+ is_trace_root: pb:: Trilean :: True . into( ) ,
999+ ..Default :: default ( )
1000+ } ,
1001+ // Internal span with _dd.base_service="other-service" - separate group
1002+ pb:: ClientGroupedStats {
1003+ service: "A1" . to_string( ) ,
1004+ resource: "internal.with.base.service" . to_string( ) ,
1005+ r#type: "db" . to_string( ) ,
1006+ name: "query" . to_string( ) ,
1007+ peer_tags: vec![ "_dd.base_service:other-service" . to_string( ) ] ,
1008+ duration: 60 ,
1009+ hits: 1 ,
1010+ top_level_hits: 1 ,
1011+ errors: 0 ,
1012+ is_trace_root: pb:: Trilean :: True . into( ) ,
1013+ ..Default :: default ( )
1014+ } ,
1015+ // Client span - uses configured peer tags, not base_service
1016+ pb:: ClientGroupedStats {
1017+ service: "A1" . to_string( ) ,
1018+ resource: "SELECT * FROM users" . to_string( ) ,
1019+ r#type: "db" . to_string( ) ,
1020+ name: "query" . to_string( ) ,
1021+ span_kind: "client" . to_string( ) ,
1022+ peer_tags: vec![
1023+ "db.instance:i-1234" . to_string( ) ,
1024+ "db.system:postgres" . to_string( ) ,
1025+ ] ,
1026+ duration: 80 ,
1027+ hits: 1 ,
1028+ top_level_hits: 1 ,
1029+ errors: 0 ,
1030+ is_trace_root: pb:: Trilean :: True . into( ) ,
1031+ ..Default :: default ( )
1032+ } ,
1033+ ] ;
1034+
1035+ let stats = concentrator. flush ( flushtime, false ) ;
1036+ assert_counts_equal (
1037+ expected,
1038+ stats
1039+ . first ( )
1040+ . expect ( "There should be at least one time bucket" )
1041+ . stats
1042+ . clone ( ) ,
1043+ ) ;
1044+ }
1045+
8811046fn test_compute_stats_for_span_kind ( ) {
8821047 let test_cases: Vec < ( SpanSlice , bool ) > = vec ! [
8831048 (
0 commit comments