@@ -28,9 +28,12 @@ pub(super) struct AggregationKey<'a> {
28
28
is_synthetics_request : bool ,
29
29
peer_tags : Vec < ( Cow < ' a , str > , Cow < ' a , str > ) > ,
30
30
is_trace_root : bool ,
31
+ http_method : Cow < ' a , str > ,
32
+ http_endpoint : Cow < ' a , str > ,
31
33
}
32
34
33
35
/// Common representation of AggregationKey used to compare AggregationKey with different lifetimes
36
+ /// field order must be the same as in AggregationKey, o/wise hashes will be different
34
37
#[ derive( Clone , Hash , PartialEq , Eq ) ]
35
38
pub ( super ) struct BorrowedAggregationKey < ' a > {
36
39
resource_name : & ' a str ,
@@ -42,6 +45,8 @@ pub(super) struct BorrowedAggregationKey<'a> {
42
45
is_synthetics_request : bool ,
43
46
peer_tags : Vec < ( & ' a str , & ' a str ) > ,
44
47
is_trace_root : bool ,
48
+ http_method : & ' a str ,
49
+ http_endpoint : & ' a str ,
45
50
}
46
51
47
52
/// Trait used to define a common type (`dyn BorrowableAggregationKey`) for all AggregationKey
@@ -71,6 +76,8 @@ impl BorrowableAggregationKey for AggregationKey<'_> {
71
76
. map ( |( tag, value) | ( tag. borrow ( ) , value. borrow ( ) ) )
72
77
. collect ( ) ,
73
78
is_trace_root : self . is_trace_root ,
79
+ http_method : self . http_method . borrow ( ) ,
80
+ http_endpoint : self . http_endpoint . borrow ( ) ,
74
81
}
75
82
}
76
83
}
@@ -124,13 +131,29 @@ impl<'a> AggregationKey<'a> {
124
131
} else {
125
132
vec ! [ ]
126
133
} ;
134
+
135
+ let http_method = span
136
+ . meta
137
+ . get ( "http.method" )
138
+ . map ( |s| s. borrow ( ) )
139
+ . unwrap_or_default ( ) ;
140
+
141
+ let http_endpoint = span
142
+ . meta
143
+ . get ( "http.endpoint" )
144
+ . or_else ( || span. meta . get ( "http.route" ) )
145
+ . map ( |s| s. borrow ( ) )
146
+ . unwrap_or_default ( ) ;
147
+
127
148
Self {
128
149
resource_name : span. resource . borrow ( ) . into ( ) ,
129
150
service_name : span. service . borrow ( ) . into ( ) ,
130
151
operation_name : span. name . borrow ( ) . into ( ) ,
131
152
span_type : span. r#type . borrow ( ) . into ( ) ,
132
153
span_kind : span_kind. into ( ) ,
133
154
http_status_code : get_status_code ( span) ,
155
+ http_method : http_method. into ( ) ,
156
+ http_endpoint : http_endpoint. into ( ) ,
134
157
is_synthetics_request : span
135
158
. meta
136
159
. get ( TAG_ORIGIN )
@@ -153,6 +176,8 @@ impl<'a> AggregationKey<'a> {
153
176
span_type : Cow :: Owned ( self . span_type . into_owned ( ) ) ,
154
177
span_kind : Cow :: Owned ( self . span_kind . into_owned ( ) ) ,
155
178
http_status_code : self . http_status_code ,
179
+ http_method : Cow :: Owned ( self . http_method . into_owned ( ) ) ,
180
+ http_endpoint : Cow :: Owned ( self . http_endpoint . into_owned ( ) ) ,
156
181
is_synthetics_request : self . is_synthetics_request ,
157
182
is_trace_root : self . is_trace_root ,
158
183
peer_tags : self
@@ -183,6 +208,8 @@ impl From<pb::ClientGroupedStats> for AggregationKey<'static> {
183
208
} )
184
209
. collect ( ) ,
185
210
is_trace_root : value. is_trace_root == 1 ,
211
+ http_method : value. http_method . into ( ) ,
212
+ http_endpoint : value. http_endpoint . into ( ) ,
186
213
}
187
214
}
188
215
}
@@ -335,6 +362,9 @@ fn encode_grouped_stats(key: AggregationKey, group: GroupedStats) -> pb::ClientG
335
362
} else {
336
363
pb:: Trilean :: False . into ( )
337
364
} ,
365
+ http_method : key. http_method . into_owned ( ) ,
366
+ http_endpoint : key. http_endpoint . into_owned ( ) ,
367
+ grpc_status_code : String :: new ( ) , // currently not used
338
368
}
339
369
}
340
370
@@ -541,6 +571,57 @@ mod tests {
541
571
..Default :: default ( )
542
572
} ,
543
573
) ,
574
+ // Span with http.method and http.route
575
+ (
576
+ SpanBytes {
577
+ service: "service" . into( ) ,
578
+ name: "op" . into( ) ,
579
+ resource: "GET /api/v1/users" . into( ) ,
580
+ span_id: 1 ,
581
+ parent_id: 0 ,
582
+ meta: HashMap :: from( [
583
+ ( "http.method" . into( ) , "GET" . into( ) ) ,
584
+ ( "http.route" . into( ) , "/api/v1/users" . into( ) ) ,
585
+ ] ) ,
586
+ ..Default :: default ( )
587
+ } ,
588
+ AggregationKey {
589
+ service_name: "service" . into( ) ,
590
+ operation_name: "op" . into( ) ,
591
+ resource_name: "GET /api/v1/users" . into( ) ,
592
+ http_method: "GET" . into( ) ,
593
+ http_endpoint: "/api/v1/users" . into( ) ,
594
+ is_synthetics_request: false ,
595
+ is_trace_root: true ,
596
+ ..Default :: default ( )
597
+ } ,
598
+ ) ,
599
+ // Span with http.method and http.endpoint (http.endpoint takes precedence)
600
+ (
601
+ SpanBytes {
602
+ service: "service" . into( ) ,
603
+ name: "op" . into( ) ,
604
+ resource: "POST /users/create" . into( ) ,
605
+ span_id: 1 ,
606
+ parent_id: 0 ,
607
+ meta: HashMap :: from( [
608
+ ( "http.method" . into( ) , "POST" . into( ) ) ,
609
+ ( "http.route" . into( ) , "/users/create" . into( ) ) ,
610
+ ( "http.endpoint" . into( ) , "/users/create2" . into( ) ) ,
611
+ ] ) ,
612
+ ..Default :: default ( )
613
+ } ,
614
+ AggregationKey {
615
+ service_name: "service" . into( ) ,
616
+ operation_name: "op" . into( ) ,
617
+ resource_name: "POST /users/create" . into( ) ,
618
+ http_method: "POST" . into( ) ,
619
+ http_endpoint: "/users/create2" . into( ) ,
620
+ is_synthetics_request: false ,
621
+ is_trace_root: true ,
622
+ ..Default :: default ( )
623
+ } ,
624
+ ) ,
544
625
] ;
545
626
546
627
let test_peer_tags = vec ! [
0 commit comments