use std::time::Duration;
#[derive(Debug, Clone)]
pub struct OpenLineageConfig {
pub producer: String,
pub job_namespace: String,
pub engine_name: String,
pub engine_version: String,
pub adapter_version: String,
pub request_timeout: Duration,
}
pub const DEFAULT_PRODUCER: &str =
"https://github.com/open-lakehouse/headwaters/openlineage-client";
pub const DEFAULT_NAMESPACE: &str = "default";
pub const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
impl OpenLineageConfig {
pub fn from_env() -> Self {
Self::with_env(
std::env::var("OPENLINEAGE_NAMESPACE").ok(),
std::env::var("OPENLINEAGE_TIMEOUT_MS").ok(),
)
}
pub fn with_env(namespace: Option<String>, timeout_ms: Option<String>) -> Self {
let request_timeout = timeout_ms
.as_deref()
.filter(|s| !s.is_empty())
.and_then(|s| s.parse::<u64>().ok())
.map(Duration::from_millis)
.unwrap_or(DEFAULT_REQUEST_TIMEOUT);
Self {
job_namespace: namespace
.filter(|ns| !ns.is_empty())
.unwrap_or_else(|| DEFAULT_NAMESPACE.to_string()),
request_timeout,
..Self::fixed()
}
}
fn fixed() -> Self {
Self {
producer: DEFAULT_PRODUCER.to_string(),
job_namespace: DEFAULT_NAMESPACE.to_string(),
engine_name: String::new(),
engine_version: String::new(),
adapter_version: env!("CARGO_PKG_VERSION").to_string(),
request_timeout: DEFAULT_REQUEST_TIMEOUT,
}
}
}
impl Default for OpenLineageConfig {
fn default() -> Self {
Self::from_env()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn namespace_falls_back_when_unset() {
let cfg = OpenLineageConfig::with_env(None, None);
assert_eq!(cfg.job_namespace, DEFAULT_NAMESPACE);
}
#[test]
fn empty_namespace_falls_back() {
let cfg = OpenLineageConfig::with_env(Some(String::new()), None);
assert_eq!(cfg.job_namespace, DEFAULT_NAMESPACE);
}
#[test]
fn namespace_is_taken_from_env() {
let cfg = OpenLineageConfig::with_env(Some("analytics".to_string()), None);
assert_eq!(cfg.job_namespace, "analytics");
}
#[test]
fn timeout_parses_from_env() {
let cfg = OpenLineageConfig::with_env(None, Some("5000".to_string()));
assert_eq!(cfg.request_timeout, Duration::from_millis(5000));
}
#[test]
fn timeout_falls_back_when_unparsable() {
let cfg = OpenLineageConfig::with_env(None, Some("not-a-number".to_string()));
assert_eq!(cfg.request_timeout, DEFAULT_REQUEST_TIMEOUT);
}
#[test]
fn fixed_identity_is_engine_neutral() {
let cfg = OpenLineageConfig::with_env(Some("x".to_string()), None);
assert_eq!(cfg.producer, DEFAULT_PRODUCER);
assert_eq!(cfg.adapter_version, env!("CARGO_PKG_VERSION"));
assert!(cfg.engine_name.is_empty());
assert!(cfg.engine_version.is_empty());
}
}