Skip to content

Commit 4dd54a2

Browse files
authored
Env over compling time config (#1323)
* feat: favor env vars in jaeger exporters * feat: collectors * fix unit tests * unit tests * unit tests * add change logs
1 parent e265d24 commit 4dd54a2

File tree

7 files changed

+335
-176
lines changed

7 files changed

+335
-176
lines changed

CONTRIBUTING.md

+8
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ The Opentelemetry Rust SDK comes with an error type `openetelemetry::Error`. For
111111

112112
For users that want to implement their own exporters. It's RECOMMENDED to wrap all errors from the exporter into a crate-level error type, and implement `ExporterError` trait.
113113

114+
### Priority of configurations
115+
OpenTelemetry supports multiple ways to configure the API, SDK and other components. The priority of configurations is as follows:
116+
117+
- Environment variables
118+
- Compiling time configurations provided in the source code
119+
120+
121+
114122
## Style Guide
115123

116124
* Run `cargo clippy --all` - this will catch common mistakes and improve

opentelemetry-jaeger/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- Bump MSRV to 1.65 [#1318](https://github.com/open-telemetry/opentelemetry-rust/pull/1318)
88
- Bump MSRV to 1.64 [#1203](https://github.com/open-telemetry/opentelemetry-rust/pull/1203)
9+
- Prioritize environment variables over compiling time variables [#1323](https://github.com/open-telemetry/opentelemetry-rust/pull/1323)
910

1011
## v0.19.0
1112

opentelemetry-jaeger/src/exporter/agent.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
//! # UDP Jaeger Agent Client
2-
use crate::exporter::addrs_and_family;
2+
use crate::exporter::address_family;
33
use crate::exporter::runtime::JaegerTraceRuntime;
44
use crate::exporter::thrift::{
55
agent::{self, TAgentSyncClient},
66
jaeger,
77
};
88
use crate::exporter::transport::{TBufferChannel, TNoopChannel};
99
use std::fmt;
10-
use std::net::{ToSocketAddrs, UdpSocket};
10+
use std::net::{SocketAddr, UdpSocket};
1111
use thrift::{
1212
protocol::{TCompactInputProtocol, TCompactOutputProtocol},
1313
transport::{ReadHalf, TIoChannel, WriteHalf},
@@ -43,20 +43,19 @@ pub(crate) struct AgentSyncClientUdp {
4343

4444
impl AgentSyncClientUdp {
4545
/// Create a new UDP agent client
46-
pub(crate) fn new<T: ToSocketAddrs>(
47-
agent_endpoint: T,
46+
pub(crate) fn new(
4847
max_packet_size: usize,
4948
auto_split: bool,
49+
agent_address: Vec<SocketAddr>,
5050
) -> thrift::Result<Self> {
5151
let (buffer, write) = TBufferChannel::with_capacity(max_packet_size).split()?;
5252
let client = agent::AgentSyncClient::new(
5353
TCompactInputProtocol::new(TNoopChannel),
5454
TCompactOutputProtocol::new(write),
5555
);
5656

57-
let (addrs, family) = addrs_and_family(&agent_endpoint)?;
58-
let conn = UdpSocket::bind(family)?;
59-
conn.connect(addrs.as_slice())?;
57+
let conn = UdpSocket::bind(address_family(agent_address.as_slice()))?;
58+
conn.connect(agent_address.as_slice())?;
6059

6160
Ok(AgentSyncClientUdp {
6261
conn,
@@ -102,19 +101,19 @@ pub(crate) struct AgentAsyncClientUdp<R: JaegerTraceRuntime> {
102101

103102
impl<R: JaegerTraceRuntime> AgentAsyncClientUdp<R> {
104103
/// Create a new UDP agent client
105-
pub(crate) fn new<T: ToSocketAddrs>(
106-
agent_endpoint: T,
104+
pub(crate) fn new(
107105
max_packet_size: usize,
108106
runtime: R,
109107
auto_split: bool,
108+
agent_address: Vec<SocketAddr>,
110109
) -> thrift::Result<Self> {
111110
let (buffer, write) = TBufferChannel::with_capacity(max_packet_size).split()?;
112111
let client = agent::AgentSyncClient::new(
113112
TCompactInputProtocol::new(TNoopChannel),
114113
TCompactOutputProtocol::new(write),
115114
);
116115

117-
let conn = runtime.create_socket(agent_endpoint)?;
116+
let conn = runtime.create_socket(agent_address.as_slice())?;
118117

119118
Ok(AgentAsyncClientUdp {
120119
runtime,

opentelemetry-jaeger/src/exporter/config/agent.rs

+50-41
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1+
use std::borrow::BorrowMut;
2+
use std::net::ToSocketAddrs;
3+
use std::sync::Arc;
4+
use std::{env, net};
5+
6+
use opentelemetry::trace::TraceError;
7+
use opentelemetry_sdk::trace::{BatchSpanProcessor, Tracer};
8+
use opentelemetry_sdk::{
9+
self,
10+
trace::{BatchConfig, Config, TracerProvider},
11+
};
12+
113
use crate::exporter::agent::{AgentAsyncClientUdp, AgentSyncClientUdp};
214
use crate::exporter::config::{
315
build_config_and_process, install_tracer_provider_and_get_tracer, HasRequiredConfig,
416
TransformationConfig,
517
};
618
use crate::exporter::uploader::{AsyncUploader, SyncUploader, Uploader};
719
use crate::{Error, Exporter, JaegerTraceRuntime};
8-
use opentelemetry::trace::TraceError;
9-
use opentelemetry_sdk::trace::{BatchSpanProcessor, Tracer};
10-
use opentelemetry_sdk::{
11-
self,
12-
trace::{BatchConfig, Config, TracerProvider},
13-
};
14-
use std::borrow::BorrowMut;
15-
use std::sync::Arc;
16-
use std::{env, net};
1720

1821
/// The max size of UDP packet we want to send, synced with jaeger-agent
1922
const UDP_PACKET_MAX_LENGTH: usize = 65_000;
@@ -78,38 +81,23 @@ pub struct AgentPipeline {
7881
transformation_config: TransformationConfig,
7982
trace_config: Option<Config>,
8083
batch_config: Option<BatchConfig>,
81-
agent_endpoint: Result<Vec<net::SocketAddr>, crate::Error>,
84+
agent_endpoint: Option<String>,
8285
max_packet_size: usize,
8386
auto_split_batch: bool,
8487
}
8588

8689
impl Default for AgentPipeline {
8790
fn default() -> Self {
88-
let mut pipeline = AgentPipeline {
91+
AgentPipeline {
8992
transformation_config: Default::default(),
9093
trace_config: Default::default(),
9194
batch_config: Some(Default::default()),
92-
agent_endpoint: Ok(vec![format!(
95+
agent_endpoint: Some(format!(
9396
"{DEFAULT_AGENT_ENDPOINT_HOST}:{DEFAULT_AGENT_ENDPOINT_PORT}"
94-
)
95-
.parse()
96-
.unwrap()]),
97+
)),
9798
max_packet_size: UDP_PACKET_MAX_LENGTH,
9899
auto_split_batch: false,
99-
};
100-
101-
let endpoint = match (env::var(ENV_AGENT_HOST), env::var(ENV_AGENT_PORT)) {
102-
(Ok(host), Ok(port)) => Some(format!("{}:{}", host.trim(), port.trim())),
103-
(Ok(host), _) => Some(format!("{}:{DEFAULT_AGENT_ENDPOINT_PORT}", host.trim())),
104-
(_, Ok(port)) => Some(format!("{DEFAULT_AGENT_ENDPOINT_HOST}:{}", port.trim())),
105-
(_, _) => None,
106-
};
107-
108-
if let Some(endpoint) = endpoint {
109-
pipeline = pipeline.with_endpoint(endpoint);
110100
}
111-
112-
pipeline
113101
}
114102
}
115103

@@ -147,16 +135,9 @@ impl AgentPipeline {
147135
/// Any valid socket address can be used.
148136
///
149137
/// Default to be `127.0.0.1:6831`.
150-
pub fn with_endpoint<T: net::ToSocketAddrs>(self, agent_endpoint: T) -> Self {
138+
pub fn with_endpoint<T: Into<String>>(self, agent_endpoint: T) -> Self {
151139
AgentPipeline {
152-
agent_endpoint: agent_endpoint
153-
.to_socket_addrs()
154-
.map(|addrs| addrs.collect())
155-
.map_err(|io_err| crate::Error::ConfigError {
156-
pipeline_name: "agent",
157-
config_name: "endpoint",
158-
reason: io_err.to_string(),
159-
}),
140+
agent_endpoint: Some(agent_endpoint.into()),
160141
..self
161142
}
162143
}
@@ -391,10 +372,10 @@ impl AgentPipeline {
391372
R: JaegerTraceRuntime,
392373
{
393374
let agent = AgentAsyncClientUdp::new(
394-
self.agent_endpoint?.as_slice(),
395375
self.max_packet_size,
396376
runtime,
397377
self.auto_split_batch,
378+
self.resolve_endpoint()?,
398379
)
399380
.map_err::<Error, _>(Into::into)?;
400381
Ok(Arc::new(AsyncUploader::Agent(
@@ -404,13 +385,38 @@ impl AgentPipeline {
404385

405386
fn build_sync_agent_uploader(self) -> Result<Arc<dyn Uploader>, TraceError> {
406387
let agent = AgentSyncClientUdp::new(
407-
self.agent_endpoint?.as_slice(),
408388
self.max_packet_size,
409389
self.auto_split_batch,
390+
self.resolve_endpoint()?,
410391
)
411392
.map_err::<Error, _>(Into::into)?;
412393
Ok(Arc::new(SyncUploader::Agent(std::sync::Mutex::new(agent))))
413394
}
395+
396+
// resolve the agent endpoint from the environment variables or the builder
397+
// if only one of the environment variables is set, the other one will be set to the default value
398+
// if no environment variable is set, the builder value will be used.
399+
fn resolve_endpoint(self) -> Result<Vec<net::SocketAddr>, TraceError> {
400+
let endpoint_str = match (env::var(ENV_AGENT_HOST), env::var(ENV_AGENT_PORT)) {
401+
(Ok(host), Ok(port)) => format!("{}:{}", host.trim(), port.trim()),
402+
(Ok(host), _) => format!("{}:{DEFAULT_AGENT_ENDPOINT_PORT}", host.trim()),
403+
(_, Ok(port)) => format!("{DEFAULT_AGENT_ENDPOINT_HOST}:{}", port.trim()),
404+
(_, _) => self.agent_endpoint.unwrap_or(format!(
405+
"{DEFAULT_AGENT_ENDPOINT_HOST}:{DEFAULT_AGENT_ENDPOINT_PORT}"
406+
)),
407+
};
408+
endpoint_str
409+
.to_socket_addrs()
410+
.map(|addrs| addrs.collect())
411+
.map_err(|io_err| {
412+
Error::ConfigError {
413+
pipeline_name: "agent",
414+
config_name: "endpoint",
415+
reason: io_err.to_string(),
416+
}
417+
.into()
418+
})
419+
}
414420
}
415421

416422
#[cfg(test)]
@@ -429,9 +435,12 @@ mod tests {
429435
("127.0.0.1:1001", true),
430436
];
431437
for (socket_str, is_ok) in test_cases.into_iter() {
432-
let pipeline = AgentPipeline::default().with_endpoint(socket_str);
438+
let resolved_endpoint = AgentPipeline::default()
439+
.with_endpoint(socket_str)
440+
.resolve_endpoint();
433441
assert_eq!(
434-
pipeline.agent_endpoint.is_ok(),
442+
resolved_endpoint.is_ok(),
443+
// if is_ok is true, use socket_str, otherwise use the default endpoint
435444
is_ok,
436445
"endpoint string {}",
437446
socket_str

0 commit comments

Comments
 (0)