Skip to content

Commit 67af0b1

Browse files
committed
feat(databricks_zerobus sink): add user_agent config option
Add an optional `user_agent` config field whose value is appended to the `user-agent` header sent to Databricks via the Zerobus SDK's `application_name`. The header always identifies Vector (`Vector/<version>`), preserving the SDK's own `zerobus-sdk-rs/<version>` prefix; the configured value is appended after it when set. Co-authored-by: Isaac
1 parent 5072d8b commit 67af0b1

4 files changed

Lines changed: 73 additions & 1 deletion

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The `databricks_zerobus` sink now supports a `user_agent` option whose value is appended to the `user-agent` header sent to Databricks. The header always identifies Vector (`Vector/<version>`); when set, the configured value is appended after it.
2+
3+
authors: flaviocruz

src/sinks/databricks_zerobus/config.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ pub struct ZerobusSinkConfig {
109109
#[configurable(derived)]
110110
pub auth: DatabricksAuthentication,
111111

112+
/// Custom identifier appended to the `user-agent` header sent to Databricks.
113+
///
114+
/// The header always includes `Vector/<version>`; when set, this value is
115+
/// appended after it (e.g. `my-service/1.2`).
116+
#[serde(default)]
117+
#[configurable(metadata(docs::examples = "my-service/1.2"))]
118+
pub user_agent: Option<String>,
119+
112120
#[configurable(derived)]
113121
#[serde(default)]
114122
pub stream_options: ZerobusStreamOptions,
@@ -140,6 +148,7 @@ impl GenerateConfig for ZerobusSinkConfig {
140148
client_id: SensitiveString::from("${DATABRICKS_CLIENT_ID}".to_string()),
141149
client_secret: SensitiveString::from("${DATABRICKS_CLIENT_SECRET}".to_string()),
142150
},
151+
user_agent: None,
143152
stream_options: ZerobusStreamOptions::default(),
144153
batch: BatchConfig::default(),
145154
request: TowerRequestConfig::default(),
@@ -246,6 +255,17 @@ impl ZerobusSinkConfig {
246255

247256
Ok(())
248257
}
258+
259+
/// The user-agent suffix to hand the Zerobus SDK: `Vector/<version>`
260+
/// alone, or with the user's configured `user_agent` appended. The SDK
261+
/// prepends its own `zerobus-sdk-rs/<version>` prefix to this value.
262+
pub fn user_agent_suffix(&self) -> String {
263+
let vector = format!("Vector/{}", crate::vector_version());
264+
match self.user_agent.as_deref().filter(|s| !s.is_empty()) {
265+
Some(ua) => format!("{vector} {ua}"),
266+
None => vector,
267+
}
268+
}
249269
}
250270

251271
// Default value functions
@@ -271,6 +291,7 @@ mod tests {
271291
client_id: SensitiveString::from("test-client-id".to_string()),
272292
client_secret: SensitiveString::from("test-client-secret".to_string()),
273293
},
294+
user_agent: None,
274295
stream_options: ZerobusStreamOptions::default(),
275296
batch: Default::default(),
276297
request: Default::default(),
@@ -418,4 +439,40 @@ mod tests {
418439

419440
assert_eq!(settings.size_limit, 10_000_000);
420441
}
442+
443+
#[test]
444+
fn test_user_agent_suffix_without_user_value() {
445+
let config = create_test_config();
446+
let suffix = config.user_agent_suffix();
447+
assert!(
448+
suffix.starts_with("Vector/"),
449+
"expected Vector/<version> prefix, got {suffix:?}"
450+
);
451+
// No user value configured, so nothing is appended.
452+
assert!(!suffix.contains(' '), "unexpected appended value in {suffix:?}");
453+
}
454+
455+
#[test]
456+
fn test_user_agent_suffix_with_user_value() {
457+
let mut config = create_test_config();
458+
config.user_agent = Some("my-service/1.2".to_string());
459+
let suffix = config.user_agent_suffix();
460+
assert!(
461+
suffix.starts_with("Vector/"),
462+
"expected Vector/<version> prefix, got {suffix:?}"
463+
);
464+
assert!(
465+
suffix.ends_with(" my-service/1.2"),
466+
"expected user value appended, got {suffix:?}"
467+
);
468+
}
469+
470+
#[test]
471+
fn test_user_agent_suffix_empty_user_value_ignored() {
472+
let mut config = create_test_config();
473+
config.user_agent = Some(String::new());
474+
let suffix = config.user_agent_suffix();
475+
// An empty string is treated the same as no value: no trailing space.
476+
assert!(!suffix.contains(' '), "empty user_agent should be ignored, got {suffix:?}");
477+
}
421478
}

src/sinks/databricks_zerobus/service.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,8 @@ impl ZerobusService {
298298
) -> Result<Self, ZerobusSinkError> {
299299
let mut builder = ZerobusSdk::builder()
300300
.endpoint(&config.ingestion_endpoint)
301-
.unity_catalog_url(&config.unity_catalog_endpoint);
301+
.unity_catalog_url(&config.unity_catalog_endpoint)
302+
.application_name(config.user_agent_suffix());
302303
builder = builder.connector_factory(build_connector_factory(proxy)?);
303304
let sdk = builder.build().map_err(|e| ZerobusSinkError::ConfigError {
304305
message: format!("Failed to create Zerobus SDK: {}", e),
@@ -691,6 +692,7 @@ mod tests {
691692
client_id: SensitiveString::from("id".to_string()),
692693
client_secret: SensitiveString::from("secret".to_string()),
693694
},
695+
user_agent: None,
694696
stream_options: ZerobusStreamOptions::default(),
695697
batch: Default::default(),
696698
request: Default::default(),

website/cue/reference/components/sinks/generated/databricks_zerobus.cue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,4 +320,14 @@ generated: components: sinks: databricks_zerobus: configuration: {
320320
required: true
321321
type: string: examples: ["https://dbc-e2f0eb31-2b0e.staging.cloud.databricks.com", "https://your-workspace.cloud.databricks.com"]
322322
}
323+
user_agent: {
324+
description: """
325+
Custom identifier appended to the `user-agent` header sent to Databricks.
326+
327+
The header always includes `Vector/<version>`; when set, this value is
328+
appended after it (e.g. `my-service/1.2`).
329+
"""
330+
required: false
331+
type: string: examples: ["my-service/1.2"]
332+
}
323333
}

0 commit comments

Comments
 (0)