Skip to content

Commit 8be6661

Browse files
authored
fix(config): fix otlp trace agent to start when right configuration is set (#680)
# What? Ensures that OTLP agent is only enabled when the `otlp_config_receiver_protocols_http_endpoint` is set, and when `otlp_config_traces_enabled` is `true` # Motivation #678 # Notes OTEL agent should only spin up when receiver protocols endpoint is set, so this was a miss on my side.
1 parent f6fdfc1 commit 8be6661

4 files changed

Lines changed: 234 additions & 41 deletions

File tree

bottlecap/src/bin/bottlecap/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use bottlecap::{
2525
},
2626
logger,
2727
logs::{agent::LogsAgent, flusher::Flusher as LogsFlusher},
28-
otlp::agent::Agent as OtlpAgent,
28+
otlp::{agent::Agent as OtlpAgent, should_enable_otlp_agent},
2929
proxy::{interceptor, should_start_proxy},
3030
secrets::decrypt,
3131
tags::{
@@ -821,7 +821,7 @@ fn start_otlp_agent(
821821
trace_processor: Arc<dyn trace_processor::TraceProcessor + Send + Sync>,
822822
trace_tx: Sender<SendData>,
823823
) {
824-
if !config.otlp_config_traces_enabled {
824+
if !should_enable_otlp_agent(config) {
825825
return;
826826
}
827827

bottlecap/src/config/mod.rs

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,11 @@ fn fallback(config: &EnvConfig, yaml_config: &YamlConfig) -> Result<(), ConfigEr
8484
.is_some()
8585
|| config.otlp_config_logs_enabled;
8686

87-
let has_otlp_yaml_config = yaml_config.otlp_config.receiver.protocols.grpc.is_some()
87+
let has_otlp_yaml_config = yaml_config.otlp_config_receiver_protocols_grpc().is_some()
8888
|| yaml_config
89-
.otlp_config
90-
.traces
91-
.probabilistic_sampler
89+
.otlp_config_traces_probabilistic_sampler()
9290
.is_some()
93-
|| yaml_config.otlp_config.logs.is_some();
91+
|| yaml_config.otlp_config_logs().is_some();
9492

9593
if has_otlp_env_config || has_otlp_yaml_config {
9694
log_fallback_reason("otel");
@@ -208,54 +206,41 @@ fn merge_config(config: &mut EnvConfig, yaml_config: &YamlConfig) {
208206
// OTLP
209207
//
210208
// - Receiver / HTTP
209+
let yaml_otlp_config_receiver_protocols_http_endpoint =
210+
yaml_config.otlp_config_receiver_protocols_http_endpoint();
211211
if config
212212
.otlp_config_receiver_protocols_http_endpoint
213213
.is_none()
214-
&& !yaml_config
215-
.otlp_config
216-
.receiver
217-
.protocols
218-
.http
219-
.endpoint
220-
.is_empty()
214+
&& yaml_otlp_config_receiver_protocols_http_endpoint.is_some()
221215
{
222-
config.otlp_config_receiver_protocols_http_endpoint = Some(
223-
yaml_config
224-
.otlp_config
225-
.receiver
226-
.protocols
227-
.http
228-
.endpoint
229-
.clone(),
230-
);
231-
}
232-
233-
if !config.otlp_config_traces_enabled && yaml_config.otlp_config.traces.enabled {
216+
config.otlp_config_receiver_protocols_http_endpoint =
217+
yaml_otlp_config_receiver_protocols_http_endpoint.map(std::string::ToString::to_string);
218+
}
219+
220+
if !config.otlp_config_traces_enabled && yaml_config.otlp_config_traces_enabled() {
234221
config.otlp_config_traces_enabled = true;
235222
}
236223

237224
if !config.otlp_config_ignore_missing_datadog_fields
238-
&& yaml_config.otlp_config.traces.ignore_missing_datadog_fields
225+
&& yaml_config.otlp_config_traces_ignore_missing_datadog_fields()
239226
{
240227
config.otlp_config_ignore_missing_datadog_fields = true;
241228
}
242229

243230
if !config.otlp_config_traces_span_name_as_resource_name
244-
&& yaml_config.otlp_config.traces.span_name_as_resource_name
231+
&& yaml_config.otlp_config_traces_span_name_as_resource_name()
245232
{
246233
config.otlp_config_traces_span_name_as_resource_name = true;
247234
}
248235

236+
let yaml_otlp_config_traces_span_name_remappings =
237+
yaml_config.otlp_config_traces_span_name_remappings();
249238
if config.otlp_config_traces_span_name_remappings.is_empty()
250-
&& !yaml_config
251-
.otlp_config
252-
.traces
253-
.span_name_remappings
254-
.is_empty()
239+
&& !yaml_otlp_config_traces_span_name_remappings.is_empty()
255240
{
256241
config
257242
.otlp_config_traces_span_name_remappings
258-
.clone_from(&yaml_config.otlp_config.traces.span_name_remappings);
243+
.clone_from(&yaml_otlp_config_traces_span_name_remappings);
259244
}
260245
}
261246

bottlecap/src/config/yaml.rs

Lines changed: 134 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,89 @@ pub struct Config {
1616
pub logs_config: LogsConfig,
1717
pub apm_config: ApmConfig,
1818
pub proxy: ProxyConfig,
19-
pub otlp_config: OtlpConfig,
19+
pub otlp_config: Option<OtlpConfig>,
20+
}
21+
22+
impl Config {
23+
#[must_use]
24+
pub fn otlp_config_receiver_protocols_http_endpoint(&self) -> Option<&str> {
25+
self.otlp_config
26+
.as_ref()?
27+
.receiver
28+
.as_ref()?
29+
.protocols
30+
.as_ref()?
31+
.http
32+
.as_ref()?
33+
.endpoint
34+
.as_deref()
35+
}
36+
37+
#[must_use]
38+
pub fn otlp_config_receiver_protocols_grpc(&self) -> Option<&Value> {
39+
self.otlp_config
40+
.as_ref()?
41+
.receiver
42+
.as_ref()?
43+
.protocols
44+
.as_ref()?
45+
.grpc
46+
.as_ref()
47+
}
48+
49+
#[must_use]
50+
pub fn otlp_config_traces_enabled(&self) -> bool {
51+
self.otlp_config.as_ref().is_some_and(|otlp_config| {
52+
otlp_config
53+
.traces
54+
.as_ref()
55+
.is_some_and(|traces| traces.enabled)
56+
})
57+
}
58+
59+
#[must_use]
60+
pub fn otlp_config_traces_ignore_missing_datadog_fields(&self) -> bool {
61+
self.otlp_config.as_ref().is_some_and(|otlp_config| {
62+
otlp_config
63+
.traces
64+
.as_ref()
65+
.is_some_and(|traces| traces.ignore_missing_datadog_fields)
66+
})
67+
}
68+
69+
#[must_use]
70+
pub fn otlp_config_traces_span_name_as_resource_name(&self) -> bool {
71+
self.otlp_config.as_ref().is_some_and(|otlp_config| {
72+
otlp_config
73+
.traces
74+
.as_ref()
75+
.is_some_and(|traces| traces.span_name_as_resource_name)
76+
})
77+
}
78+
79+
#[must_use]
80+
pub fn otlp_config_traces_span_name_remappings(&self) -> HashMap<String, String> {
81+
self.otlp_config
82+
.as_ref()
83+
.and_then(|otlp_config| otlp_config.traces.as_ref())
84+
.map(|traces| traces.span_name_remappings.clone())
85+
.unwrap_or_default()
86+
}
87+
88+
#[must_use]
89+
pub fn otlp_config_traces_probabilistic_sampler(&self) -> Option<&Value> {
90+
self.otlp_config
91+
.as_ref()
92+
.and_then(|otlp_config| otlp_config.traces.as_ref())
93+
.and_then(|traces| traces.probabilistic_sampler.as_ref())
94+
}
95+
96+
#[must_use]
97+
pub fn otlp_config_logs(&self) -> Option<&Value> {
98+
self.otlp_config
99+
.as_ref()
100+
.and_then(|otlp_config| otlp_config.logs.as_ref())
101+
}
20102
}
21103

22104
/// Logs Config
@@ -77,8 +159,8 @@ pub struct ProxyConfig {
77159
#[serde(default)]
78160
#[allow(clippy::module_name_repetitions)]
79161
pub struct OtlpConfig {
80-
pub receiver: OtlpReceiverConfig,
81-
pub traces: OtlpTracesConfig,
162+
pub receiver: Option<OtlpReceiverConfig>,
163+
pub traces: Option<OtlpTracesConfig>,
82164

83165
// NOT SUPPORTED
84166
pub metrics: Option<Value>,
@@ -89,14 +171,14 @@ pub struct OtlpConfig {
89171
#[serde(default)]
90172
#[allow(clippy::module_name_repetitions)]
91173
pub struct OtlpReceiverConfig {
92-
pub protocols: OtlpReceiverProtocolsConfig,
174+
pub protocols: Option<OtlpReceiverProtocolsConfig>,
93175
}
94176

95177
#[derive(Debug, PartialEq, Deserialize, Clone, Default)]
96178
#[serde(default)]
97179
#[allow(clippy::module_name_repetitions)]
98180
pub struct OtlpReceiverProtocolsConfig {
99-
pub http: OtlpReceiverHttpConfig,
181+
pub http: Option<OtlpReceiverHttpConfig>,
100182

101183
// NOT SUPPORTED
102184
pub grpc: Option<Value>,
@@ -106,10 +188,22 @@ pub struct OtlpReceiverProtocolsConfig {
106188
#[serde(default)]
107189
#[allow(clippy::module_name_repetitions)]
108190
pub struct OtlpReceiverHttpConfig {
109-
pub endpoint: String,
191+
pub endpoint: Option<String>,
110192
}
111193

112-
#[derive(Debug, PartialEq, Deserialize, Clone, Default)]
194+
impl Default for OtlpTracesConfig {
195+
fn default() -> Self {
196+
Self {
197+
enabled: true, // Default this to true
198+
span_name_as_resource_name: false,
199+
span_name_remappings: HashMap::new(),
200+
ignore_missing_datadog_fields: false,
201+
probabilistic_sampler: None,
202+
}
203+
}
204+
}
205+
206+
#[derive(Debug, PartialEq, Deserialize, Clone)]
113207
#[serde(default)]
114208
#[allow(clippy::module_name_repetitions)]
115209
pub struct OtlpTracesConfig {
@@ -124,3 +218,36 @@ pub struct OtlpTracesConfig {
124218
// NOT SUPORTED
125219
pub probabilistic_sampler: Option<Value>,
126220
}
221+
222+
#[cfg(test)]
223+
mod tests {
224+
use std::path::Path;
225+
226+
use crate::config::get_config;
227+
228+
#[test]
229+
fn test_otlp_config_receiver_protocols_http_endpoint() {
230+
figment::Jail::expect_with(|jail| {
231+
jail.clear_env();
232+
jail.create_file(
233+
"datadog.yaml",
234+
r"
235+
otlp_config:
236+
receiver:
237+
protocols:
238+
http:
239+
endpoint: 0.0.0.0:4318
240+
",
241+
)?;
242+
243+
let config = get_config(Path::new("")).expect("should parse config");
244+
245+
assert_eq!(
246+
config.otlp_config_receiver_protocols_http_endpoint,
247+
Some("0.0.0.0:4318".to_string())
248+
);
249+
250+
Ok(())
251+
});
252+
}
253+
}

bottlecap/src/otlp/mod.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,84 @@
1+
use std::sync::Arc;
2+
3+
use crate::config::Config;
4+
15
pub mod agent;
26
pub mod processor;
37
pub mod transform;
8+
9+
#[must_use]
10+
pub fn should_enable_otlp_agent(config: &Arc<Config>) -> bool {
11+
config.otlp_config_traces_enabled
12+
&& config
13+
.otlp_config_receiver_protocols_http_endpoint
14+
.is_some()
15+
}
16+
17+
#[cfg(test)]
18+
mod tests {
19+
use super::*;
20+
21+
use std::path::Path;
22+
23+
use crate::config::get_config;
24+
25+
#[test]
26+
fn test_should_enable_otlp_agent_from_yaml() {
27+
figment::Jail::expect_with(|jail| {
28+
jail.clear_env();
29+
jail.create_file(
30+
"datadog.yaml",
31+
r"
32+
otlp_config:
33+
receiver:
34+
protocols:
35+
http:
36+
endpoint: 0.0.0.0:4318
37+
",
38+
)?;
39+
40+
let config = get_config(Path::new("")).expect("should parse config");
41+
42+
// Since the default for traces is `true`, we don't need to set it.
43+
assert_eq!(should_enable_otlp_agent(&Arc::new(config)), true);
44+
45+
Ok(())
46+
});
47+
}
48+
49+
#[test]
50+
fn test_should_enable_otlp_agent_from_env_vars() {
51+
figment::Jail::expect_with(|jail| {
52+
jail.clear_env();
53+
jail.set_env(
54+
"DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT",
55+
"0.0.0.0:4318",
56+
);
57+
58+
let config = get_config(Path::new("")).expect("should parse config");
59+
60+
// Since the default for traces is `true`, we don't need to set it.
61+
assert_eq!(should_enable_otlp_agent(&Arc::new(config)), true);
62+
63+
Ok(())
64+
});
65+
}
66+
67+
#[test]
68+
fn test_should_not_enable_otlp_agent_if_traces_are_disabled() {
69+
figment::Jail::expect_with(|jail| {
70+
jail.clear_env();
71+
jail.set_env("DD_OTLP_CONFIG_TRACES_ENABLED", "false");
72+
jail.set_env(
73+
"DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT",
74+
"0.0.0.0:4318",
75+
);
76+
77+
let config = get_config(Path::new("")).expect("should parse config");
78+
79+
assert_eq!(should_enable_otlp_agent(&Arc::new(config)), false);
80+
81+
Ok(())
82+
});
83+
}
84+
}

0 commit comments

Comments
 (0)