Skip to content

Commit fa1cdb8

Browse files
committed
feat: make endpoint resolution responsibility more explicit
1 parent dbdc440 commit fa1cdb8

File tree

3 files changed

+73
-46
lines changed

3 files changed

+73
-46
lines changed

opentelemetry-otlp/src/exporter/http/mod.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ impl HttpExporterBuilder {
127127
let endpoint = resolve_http_endpoint(
128128
signal_endpoint_var,
129129
signal_endpoint_path,
130-
self.exporter_config.endpoint.as_str(),
130+
self.exporter_config.endpoint.clone(),
131131
)?;
132132

133133
let timeout = match env::var(signal_timeout_var)
@@ -340,7 +340,7 @@ fn build_endpoint_uri(endpoint: &str, path: &str) -> Result<Uri, crate::Error> {
340340
fn resolve_http_endpoint(
341341
signal_endpoint_var: &str,
342342
signal_endpoint_path: &str,
343-
provided_endpoint: &str,
343+
provided_endpoint: Option<String>,
344344
) -> Result<Uri, crate::Error> {
345345
// per signal env var is not modified
346346
if let Some(endpoint) = env::var(signal_endpoint_var)
@@ -358,14 +358,14 @@ fn resolve_http_endpoint(
358358
return Ok(endpoint);
359359
}
360360

361-
if provided_endpoint.is_empty() {
362-
build_endpoint_uri(
363-
OTEL_EXPORTER_OTLP_HTTP_ENDPOINT_DEFAULT,
364-
signal_endpoint_path,
365-
)
366-
} else {
367-
provided_endpoint.parse().map_err(From::from)
368-
}
361+
provided_endpoint
362+
.map(|e| e.parse().map_err(From::from))
363+
.unwrap_or_else(|| {
364+
build_endpoint_uri(
365+
OTEL_EXPORTER_OTLP_HTTP_ENDPOINT_DEFAULT,
366+
signal_endpoint_path,
367+
)
368+
})
369369
}
370370

371371
#[allow(clippy::mutable_key_type)] // http headers are not mutated
@@ -449,7 +449,7 @@ mod tests {
449449
let endpoint = resolve_http_endpoint(
450450
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
451451
"/v1/traces",
452-
"http://localhost:4317",
452+
Some("http://localhost:4317".to_string()),
453453
)
454454
.unwrap();
455455
assert_eq!(endpoint, "http://example.com/v1/traces");
@@ -465,7 +465,7 @@ mod tests {
465465
let endpoint = super::resolve_http_endpoint(
466466
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
467467
"/v1/traces",
468-
"http://localhost:4317",
468+
Some("http://localhost:4317".to_string()),
469469
)
470470
.unwrap();
471471
assert_eq!(endpoint, "http://example.com");
@@ -484,7 +484,7 @@ mod tests {
484484
let endpoint = super::resolve_http_endpoint(
485485
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
486486
"/v1/traces",
487-
"http://localhost:4317",
487+
Some("http://localhost:4317".to_string()),
488488
)
489489
.unwrap();
490490
assert_eq!(endpoint, "http://example.com");
@@ -498,7 +498,7 @@ mod tests {
498498
let endpoint = super::resolve_http_endpoint(
499499
"NON_EXISTENT_VAR",
500500
"/v1/traces",
501-
"http://localhost:4317",
501+
Some("http://localhost:4317".to_string()),
502502
)
503503
.unwrap();
504504
assert_eq!(endpoint, "http://localhost:4317/");
@@ -533,7 +533,7 @@ mod tests {
533533
let endpoint = super::resolve_http_endpoint(
534534
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
535535
"/v1/traces",
536-
"http://localhost:4317",
536+
Some("http://localhost:4317".to_string()),
537537
)
538538
.unwrap();
539539
assert_eq!(endpoint, "http://example.com/v1/traces");
@@ -547,7 +547,7 @@ mod tests {
547547
let result = super::resolve_http_endpoint(
548548
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
549549
"/v1/traces",
550-
"-*/*-/*-//-/-/yet-another-invalid-uri",
550+
Some("-*/*-/*-//-/-/yet-another-invalid-uri".to_string()),
551551
);
552552
assert!(result.is_err());
553553
// You may also want to assert on the specific error type if applicable
@@ -644,8 +644,8 @@ mod tests {
644644
fn test_http_exporter_builder_with_header() {
645645
use std::collections::HashMap;
646646
// Arrange
647-
let initial_headers = [("k1".to_string(), "v1".to_string())];
648-
let extra_headers = [("k2".to_string(), "v2".to_string())];
647+
let initial_headers = HashMap::from([("k1".to_string(), "v1".to_string())]);
648+
let extra_headers = HashMap::from([("k2".to_string(), "v2".to_string())]);
649649
let expected_headers = initial_headers.iter().chain(extra_headers.iter()).fold(
650650
HashMap::new(),
651651
|mut acc, (k, v)| {
@@ -656,13 +656,13 @@ mod tests {
656656
let builder = HttpExporterBuilder {
657657
http_config: HttpConfig {
658658
client: None,
659-
headers: Some(HashMap::from([("k1".to_string(), "v1".to_string())])),
659+
headers: Some(initial_headers),
660660
},
661661
exporter_config: crate::ExportConfig::default(),
662662
};
663663

664664
// Act
665-
let builder = builder.with_headers(HashMap::from([("k2".to_string(), "v2".to_string())]));
665+
let builder = builder.with_headers(extra_headers);
666666

667667
// Assert
668668
assert_eq!(
@@ -684,7 +684,7 @@ mod tests {
684684
let url = resolve_http_endpoint(
685685
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
686686
"/v1/traces",
687-
exporter.exporter_config.endpoint.as_str(),
687+
exporter.exporter_config.endpoint,
688688
)
689689
.unwrap();
690690

@@ -699,7 +699,7 @@ mod tests {
699699
let url = resolve_http_endpoint(
700700
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
701701
"/v1/traces",
702-
exporter.exporter_config.endpoint.as_str(),
702+
exporter.exporter_config.endpoint,
703703
)
704704
.unwrap();
705705

opentelemetry-otlp/src/exporter/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub(crate) mod tonic;
6969
pub struct ExportConfig {
7070
/// The address of the OTLP collector. If it's not provided via builder or environment variables.
7171
/// Default address will be used based on the protocol.
72-
pub endpoint: String,
72+
pub endpoint: Option<String>,
7373

7474
/// The protocol to use when communicating with the collector.
7575
pub protocol: Protocol,
@@ -83,7 +83,7 @@ impl Default for ExportConfig {
8383
let protocol = default_protocol();
8484

8585
ExportConfig {
86-
endpoint: "".to_string(),
86+
endpoint: None,
8787
// don't use default_endpoint(protocol) here otherwise we
8888
// won't know if user provided a value
8989
protocol,
@@ -199,7 +199,7 @@ pub trait WithExportConfig {
199199

200200
impl<B: HasExportConfig> WithExportConfig for B {
201201
fn with_endpoint<T: Into<String>>(mut self, endpoint: T) -> Self {
202-
self.export_config().endpoint = endpoint.into();
202+
self.export_config().endpoint = Some(endpoint.into());
203203
self
204204
}
205205

@@ -295,15 +295,15 @@ mod tests {
295295
fn test_default_http_endpoint() {
296296
let exporter_builder = crate::HttpExporterBuilder::default();
297297

298-
assert_eq!(exporter_builder.exporter_config.endpoint, "");
298+
assert_eq!(exporter_builder.exporter_config.endpoint, None);
299299
}
300300

301301
#[cfg(feature = "grpc-tonic")]
302302
#[test]
303303
fn test_default_tonic_endpoint() {
304304
let exporter_builder = crate::TonicExporterBuilder::default();
305305

306-
assert_eq!(exporter_builder.exporter_config.endpoint, "");
306+
assert_eq!(exporter_builder.exporter_config.endpoint, None);
307307
}
308308

309309
#[test]

opentelemetry-otlp/src/exporter/tonic/mod.rs

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -188,24 +188,7 @@ impl TonicExporterBuilder {
188188

189189
let config = self.exporter_config;
190190

191-
// resolving endpoint string
192-
// grpc doesn't have a "path" like http(See https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)
193-
// the path of grpc calls are based on the protobuf service definition
194-
// so we won't append one for default grpc endpoints
195-
// If users for some reason want to use a custom path, they can use env var or builder to pass it
196-
let endpoint = match env::var(signal_endpoint_var)
197-
.ok()
198-
.or(env::var(OTEL_EXPORTER_OTLP_ENDPOINT).ok())
199-
{
200-
Some(val) => val,
201-
None => {
202-
if config.endpoint.is_empty() {
203-
OTEL_EXPORTER_OTLP_GRPC_ENDPOINT_DEFAULT.to_string()
204-
} else {
205-
config.endpoint
206-
}
207-
}
208-
};
191+
let endpoint = Self::resolve_endpoint(signal_endpoint_var, config.endpoint);
209192

210193
let endpoint = Channel::from_shared(endpoint).map_err(crate::Error::from)?;
211194
let timeout = match env::var(signal_timeout_var)
@@ -235,6 +218,23 @@ impl TonicExporterBuilder {
235218
Ok((channel, interceptor, compression))
236219
}
237220

221+
fn resolve_endpoint(default_endpoint_var: &str, provided_endpoint: Option<String>) -> String {
222+
// resolving endpoint string
223+
// grpc doesn't have a "path" like http(See https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)
224+
// the path of grpc calls are based on the protobuf service definition
225+
// so we won't append one for default grpc endpoints
226+
// If users for some reason want to use a custom path, they can use env var or builder to pass it
227+
match env::var(default_endpoint_var)
228+
.ok()
229+
.or(env::var(OTEL_EXPORTER_OTLP_ENDPOINT).ok())
230+
{
231+
Some(val) => val,
232+
None => {
233+
provided_endpoint.unwrap_or(OTEL_EXPORTER_OTLP_GRPC_ENDPOINT_DEFAULT.to_string())
234+
}
235+
}
236+
}
237+
238238
fn resolve_compression(
239239
&self,
240240
env_override: &str,
@@ -441,7 +441,7 @@ mod tests {
441441
use crate::exporter::tonic::WithTonicConfig;
442442
#[cfg(feature = "grpc-tonic")]
443443
use crate::exporter::Compression;
444-
use crate::TonicExporterBuilder;
444+
use crate::{TonicExporterBuilder, WithExportConfig, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT};
445445
use crate::{OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS};
446446
use http::{HeaderMap, HeaderName, HeaderValue};
447447
use tonic::metadata::{MetadataMap, MetadataValue};
@@ -564,4 +564,31 @@ mod tests {
564564
},
565565
);
566566
}
567+
568+
#[test]
569+
fn test_tonic_exporter_endpoint() {
570+
// default endpoint for grpc should not add signal path.
571+
run_env_test(vec![], || {
572+
let exporter = TonicExporterBuilder::default();
573+
574+
let url = TonicExporterBuilder::resolve_endpoint(
575+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
576+
exporter.exporter_config.endpoint,
577+
);
578+
579+
assert_eq!(url, "http://localhost:4317");
580+
});
581+
582+
// if builder endpoint is set, it should not use default.
583+
run_env_test(vec![], || {
584+
let exporter = TonicExporterBuilder::default().with_endpoint("http://localhost:1234");
585+
586+
let url = TonicExporterBuilder::resolve_endpoint(
587+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
588+
exporter.exporter_config.endpoint,
589+
);
590+
591+
assert_eq!(url, "http://localhost:1234");
592+
});
593+
}
567594
}

0 commit comments

Comments
 (0)