@@ -270,6 +270,15 @@ impl OtlpHttpClient {
270
270
}
271
271
}
272
272
273
+ fn build_endpoint_uri ( endpoint : & str , path : & str ) -> Result < Uri , crate :: Error > {
274
+ let path = if endpoint. ends_with ( '/' ) && path. starts_with ( '/' ) {
275
+ path. strip_prefix ( '/' ) . unwrap ( )
276
+ } else {
277
+ path
278
+ } ;
279
+ format ! ( "{endpoint}{path}" ) . parse ( ) . map_err ( From :: from)
280
+ }
281
+
273
282
// see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#endpoint-urls-for-otlphttp
274
283
fn resolve_endpoint (
275
284
signal_endpoint_var : & str ,
@@ -287,15 +296,13 @@ fn resolve_endpoint(
287
296
// if signal env var is not set, then we check if the OTEL_EXPORTER_OTLP_ENDPOINT is set
288
297
if let Some ( endpoint) = env:: var ( OTEL_EXPORTER_OTLP_ENDPOINT )
289
298
. ok ( )
290
- . and_then ( |s| format ! ( "{s}{ signal_endpoint_path}" ) . parse ( ) . ok ( ) )
299
+ . and_then ( |s| build_endpoint_uri ( & s , signal_endpoint_path) . ok ( ) )
291
300
{
292
301
return Ok ( endpoint) ;
293
302
}
294
303
295
- // if neither works, we use the one provided in pipeline. If user never provide one, we will use the default one
296
- format ! ( "{provided_or_default_endpoint}{signal_endpoint_path}" )
297
- . parse ( )
298
- . map_err ( From :: from)
304
+ // if neither works, we use the one provided in pipeline. If user never provides one, we will use the default one
305
+ build_endpoint_uri ( provided_or_default_endpoint, signal_endpoint_path)
299
306
}
300
307
301
308
#[ allow( clippy:: mutable_key_type) ] // http headers are not mutated
@@ -313,6 +320,8 @@ mod tests {
313
320
use crate :: exporter:: tests:: run_env_test;
314
321
use crate :: { OTEL_EXPORTER_OTLP_ENDPOINT , OTEL_EXPORTER_OTLP_TRACES_ENDPOINT } ;
315
322
323
+ use super :: build_endpoint_uri;
324
+
316
325
#[ test]
317
326
fn test_append_signal_path_to_generic_env ( ) {
318
327
run_env_test (
@@ -374,6 +383,20 @@ mod tests {
374
383
} ) ;
375
384
}
376
385
386
+ #[ test]
387
+ fn test_build_endpoint_uri ( ) {
388
+ let uri = build_endpoint_uri ( "https://example.com" , "/v1/traces" ) . unwrap ( ) ;
389
+ assert_eq ! ( uri, "https://example.com/v1/traces" ) ;
390
+
391
+ // Should be no duplicate slahes:
392
+ let uri = build_endpoint_uri ( "https://example.com/" , "/v1/traces" ) . unwrap ( ) ;
393
+ assert_eq ! ( uri, "https://example.com/v1/traces" ) ;
394
+
395
+ // Append paths properly:
396
+ let uri = build_endpoint_uri ( "https://example.com/additional/path/" , "/v1/traces" ) . unwrap ( ) ;
397
+ assert_eq ! ( uri, "https://example.com/additional/path/v1/traces" ) ;
398
+ }
399
+
377
400
#[ test]
378
401
fn test_invalid_uri_in_signal_env_falls_back_to_generic_env ( ) {
379
402
run_env_test (
0 commit comments