@@ -9,6 +9,7 @@ use crate::{
9
9
health_metrics, health_metrics:: HealthMetric , span_concentrator:: SpanConcentrator ,
10
10
stats_exporter,
11
11
} ;
12
+ use anyhow:: Context ;
12
13
use arc_swap:: { ArcSwap , ArcSwapOption } ;
13
14
use bytes:: Bytes ;
14
15
use datadog_trace_utils:: msgpack_decoder:: { self , decode:: error:: DecodeError } ;
@@ -24,7 +25,6 @@ use dogstatsd_client::{new, Client, DogStatsDAction};
24
25
use either:: Either ;
25
26
use error:: BuilderErrorKind ;
26
27
use http_body_util:: BodyExt ;
27
- use hyper:: http:: uri:: PathAndQuery ;
28
28
use hyper:: { header:: CONTENT_TYPE , Method , Uri } ;
29
29
use log:: { error, info} ;
30
30
use std:: io;
@@ -66,15 +66,12 @@ pub enum TraceExporterOutputFormat {
66
66
}
67
67
68
68
impl TraceExporterOutputFormat {
69
- /// Add the agent trace endpoint path to the URL.
70
- fn add_path ( & self , url : & Uri ) -> Uri {
71
- add_path (
72
- url,
73
- match self {
74
- TraceExporterOutputFormat :: V04 => "/v0.4/traces" ,
75
- TraceExporterOutputFormat :: V05 => "/v0.5/traces" ,
76
- } ,
77
- )
69
+ /// Return the agent trace endpoint path.
70
+ fn as_path ( & self ) -> & str {
71
+ match self {
72
+ TraceExporterOutputFormat :: V04 => "/v0.4/traces" ,
73
+ TraceExporterOutputFormat :: V05 => "/v0.5/traces" ,
74
+ }
78
75
}
79
76
80
77
#[ cfg( feature = "test-utils" ) ]
@@ -90,35 +87,6 @@ impl TraceExporterOutputFormat {
90
87
}
91
88
}
92
89
93
- /// Add a path to the URL.
94
- ///
95
- /// # Arguments
96
- ///
97
- /// * `url` - The URL to which the path is to be added.
98
- /// * `path` - The path to be added to the URL.
99
- fn add_path ( url : & Uri , path : & str ) -> Uri {
100
- let p_and_q = url. path_and_query ( ) ;
101
-
102
- #[ allow( clippy:: unwrap_used) ]
103
- let new_p_and_q = match p_and_q {
104
- Some ( pq) => {
105
- let p = pq. path ( ) ;
106
- let mut p = p. strip_suffix ( '/' ) . unwrap_or ( p) . to_owned ( ) ;
107
- p. push_str ( path) ;
108
-
109
- PathAndQuery :: from_str ( p. as_str ( ) )
110
- }
111
- None => PathAndQuery :: from_str ( path) ,
112
- }
113
- // TODO: Properly handle non-OK states to prevent possible panics (APMSP-18190).
114
- . unwrap ( ) ;
115
- let mut parts = url. clone ( ) . into_parts ( ) ;
116
- parts. path_and_query = Some ( new_p_and_q) ;
117
- // TODO: Properly handle non-OK states to prevent possible panics (APMSP-18190).
118
- #[ allow( clippy:: unwrap_used) ]
119
- Uri :: from_parts ( parts) . unwrap ( )
120
- }
121
-
122
90
#[ derive( Clone , Default , Debug ) ]
123
91
pub struct TracerMetadata {
124
92
pub hostname : String ,
@@ -331,7 +299,9 @@ impl TraceExporter {
331
299
bucket_size,
332
300
stats_concentrator. clone ( ) ,
333
301
self . metadata . clone ( ) ,
334
- Endpoint :: from_url ( add_path ( & self . endpoint . url , STATS_ENDPOINT ) ) ,
302
+ self . endpoint
303
+ . try_clone_with_subpath ( STATS_ENDPOINT )
304
+ . context ( "failed to create Endpoint" ) ?,
335
305
cancellation_token. clone ( ) ,
336
306
) ;
337
307
@@ -442,23 +412,26 @@ impl TraceExporter {
442
412
self . send_data_to_url (
443
413
data,
444
414
trace_count,
445
- self . output_format . add_path ( & self . endpoint . url ) ,
415
+ self . endpoint
416
+ . try_clone_with_subpath ( self . output_format . as_path ( ) )
417
+ . map_err ( |e| {
418
+ TraceExporterError :: Builder ( BuilderErrorKind :: InvalidUri ( e. to_string ( ) ) )
419
+ } ) ?,
446
420
)
447
421
}
448
422
449
423
fn send_data_to_url (
450
424
& self ,
451
425
data : & [ u8 ] ,
452
426
trace_count : usize ,
453
- uri : Uri ,
427
+ endpoint : Endpoint ,
454
428
) -> Result < String , TraceExporterError > {
455
429
self . runtime . block_on ( async {
456
- let mut req_builder = hyper:: Request :: builder ( )
457
- . uri ( uri)
458
- . header (
459
- hyper:: header:: USER_AGENT ,
460
- concat ! ( "Tracer/" , env!( "CARGO_PKG_VERSION" ) ) ,
461
- )
430
+ // SAFETY: the user agent is a valid header value
431
+ #[ allow( clippy:: unwrap_used) ]
432
+ let mut req_builder = endpoint
433
+ . to_request_builder ( concat ! ( "Tracer/" , env!( "CARGO_PKG_VERSION" ) ) )
434
+ . unwrap ( )
462
435
. method ( Method :: POST ) ;
463
436
464
437
let headers: HashMap < & ' static str , String > = self . metadata . borrow ( ) . into ( ) ;
@@ -656,10 +629,7 @@ impl TraceExporter {
656
629
} ;
657
630
658
631
let chunks = payload. size ( ) ;
659
- let endpoint = Endpoint {
660
- url : self . get_agent_url ( ) ,
661
- ..self . endpoint . clone ( )
662
- } ;
632
+ let endpoint = self . get_agent_endpoint ( ) ;
663
633
let mut headers: HashMap < & str , String > = header_tags. into ( ) ;
664
634
headers. insert ( DATADOG_SEND_REAL_HTTP_STATUS_STR , "1" . to_string ( ) ) ;
665
635
headers. insert ( DATADOG_TRACE_COUNT_STR , chunks. to_string ( ) ) ;
@@ -760,16 +730,23 @@ impl TraceExporter {
760
730
} )
761
731
}
762
732
763
- fn get_agent_url ( & self ) -> Uri {
733
+ fn get_agent_endpoint ( & self ) -> Endpoint {
734
+ // Safety: Output format only contains valid path
735
+ #[ allow( clippy:: unwrap_used) ]
736
+ let endpoint = self
737
+ . endpoint
738
+ . try_clone_with_subpath ( self . output_format . as_path ( ) )
739
+ . unwrap ( ) ;
764
740
#[ cfg( feature = "test-utils" ) ]
765
741
{
766
742
if let Some ( query) = & self . query_params {
767
- let url = self . output_format . add_path ( & self . endpoint . url ) ;
768
- return self . output_format . add_query ( & url, query) ;
743
+ return Endpoint {
744
+ url : self . output_format . add_query ( & endpoint. url , query) ,
745
+ ..endpoint
746
+ } ;
769
747
}
770
748
}
771
-
772
- self . output_format . add_path ( & self . endpoint . url )
749
+ endpoint
773
750
}
774
751
}
775
752
@@ -992,11 +969,20 @@ impl TraceExporterBuilder {
992
969
TraceExporterError :: Builder ( BuilderErrorKind :: InvalidUri ( e. to_string ( ) ) )
993
970
} ) ?;
994
971
972
+ let endpoint = Endpoint {
973
+ url : agent_url,
974
+ ..Default :: default ( )
975
+ } ;
976
+
995
977
let libdatadog_version = tag ! ( "libdatadog_version" , env!( "CARGO_PKG_VERSION" ) ) ;
996
978
let mut stats = StatsComputationStatus :: Disabled ;
997
979
998
980
let info_fetcher = AgentInfoFetcher :: new (
999
- Endpoint :: from_url ( add_path ( & agent_url, INFO_ENDPOINT ) ) ,
981
+ endpoint
982
+ . try_clone_with_subpath ( INFO_ENDPOINT )
983
+ . map_err ( |e| {
984
+ TraceExporterError :: Builder ( BuilderErrorKind :: InvalidUri ( e. to_string ( ) ) )
985
+ } ) ?,
1000
986
Duration :: from_secs ( 5 * 60 ) ,
1001
987
) ;
1002
988
@@ -1038,7 +1024,7 @@ impl TraceExporterBuilder {
1038
1024
}
1039
1025
1040
1026
Ok ( TraceExporter {
1041
- endpoint : Endpoint :: from_url ( agent_url ) ,
1027
+ endpoint,
1042
1028
metadata : TracerMetadata {
1043
1029
tracer_version : self . tracer_version ,
1044
1030
language_version : self . language_version ,
@@ -1132,8 +1118,10 @@ mod tests {
1132
1118
1133
1119
assert_eq ! (
1134
1120
exporter
1135
- . output_format
1136
- . add_path( & exporter. endpoint. url)
1121
+ . endpoint
1122
+ . try_clone_with_subpath( exporter. output_format. as_path( ) )
1123
+ . unwrap( )
1124
+ . url
1137
1125
. to_string( ) ,
1138
1126
"http://192.168.1.1:8127/v0.4/traces"
1139
1127
) ;
@@ -1156,8 +1144,10 @@ mod tests {
1156
1144
1157
1145
assert_eq ! (
1158
1146
exporter
1159
- . output_format
1160
- . add_path( & exporter. endpoint. url)
1147
+ . endpoint
1148
+ . try_clone_with_subpath( exporter. output_format. as_path( ) )
1149
+ . unwrap( )
1150
+ . url
1161
1151
. to_string( ) ,
1162
1152
"http://127.0.0.1:8126/v0.4/traces"
1163
1153
) ;
0 commit comments