pub trait SettingsView: Send + Sync {
fn tracing_enabled(&self) -> bool;
fn service_name(&self) -> &str;
fn otlp_endpoint(&self) -> &str;
fn otlp_headers(&self) -> &str;
fn otlp_protocol(&self) -> &str;
fn span_processor(&self) -> &str;
fn traces_sampler(&self) -> &str;
fn traces_sampler_arg(&self) -> &str;
}
pub(crate) const DEFAULT_TRACING_ENABLED: bool = false;
pub(crate) const DEFAULT_SERVICE_NAME: &str = "cognee";
pub(crate) const DEFAULT_OTLP_ENDPOINT: &str = "";
pub(crate) const DEFAULT_OTLP_HEADERS: &str = "";
pub(crate) const DEFAULT_OTLP_PROTOCOL: &str = "grpc";
pub(crate) const DEFAULT_SPAN_PROCESSOR: &str = "batch";
pub(crate) const DEFAULT_TRACES_SAMPLER: &str = "";
pub(crate) const DEFAULT_TRACES_SAMPLER_ARG: &str = "";
#[derive(Debug, Clone)]
pub struct EnvSettingsView {
tracing_enabled: bool,
service_name: String,
otlp_endpoint: String,
otlp_headers: String,
otlp_protocol: String,
span_processor: String,
traces_sampler: String,
traces_sampler_arg: String,
}
impl Default for EnvSettingsView {
fn default() -> Self {
Self {
tracing_enabled: DEFAULT_TRACING_ENABLED,
service_name: DEFAULT_SERVICE_NAME.to_string(),
otlp_endpoint: DEFAULT_OTLP_ENDPOINT.to_string(),
otlp_headers: DEFAULT_OTLP_HEADERS.to_string(),
otlp_protocol: DEFAULT_OTLP_PROTOCOL.to_string(),
span_processor: DEFAULT_SPAN_PROCESSOR.to_string(),
traces_sampler: DEFAULT_TRACES_SAMPLER.to_string(),
traces_sampler_arg: DEFAULT_TRACES_SAMPLER_ARG.to_string(),
}
}
}
impl EnvSettingsView {
pub fn from_env() -> Self {
let mut view = Self::default();
if let Some(v) = read_env("COGNEE_TRACING_ENABLED") {
view.tracing_enabled = cognee_utils::parse_env_bool(&v);
}
if let Some(v) = read_env("OTEL_SERVICE_NAME") {
view.service_name = v;
}
if let Some(v) = read_env("OTEL_EXPORTER_OTLP_ENDPOINT") {
view.otlp_endpoint = v;
}
if let Some(v) = read_env("OTEL_EXPORTER_OTLP_HEADERS") {
view.otlp_headers = v;
}
if let Some(v) = read_env("OTEL_EXPORTER_OTLP_PROTOCOL") {
view.otlp_protocol = v;
}
if let Some(v) = read_env("OTEL_SPAN_PROCESSOR") {
view.span_processor = v;
}
if let Some(v) = read_env("OTEL_TRACES_SAMPLER") {
view.traces_sampler = v;
}
if let Some(v) = read_env("OTEL_TRACES_SAMPLER_ARG") {
view.traces_sampler_arg = v;
}
view
}
}
fn read_env(key: &str) -> Option<String> {
match std::env::var(key) {
Ok(v) if !v.is_empty() => Some(v),
_ => None,
}
}
impl SettingsView for EnvSettingsView {
fn tracing_enabled(&self) -> bool {
self.tracing_enabled
}
fn service_name(&self) -> &str {
&self.service_name
}
fn otlp_endpoint(&self) -> &str {
&self.otlp_endpoint
}
fn otlp_headers(&self) -> &str {
&self.otlp_headers
}
fn otlp_protocol(&self) -> &str {
&self.otlp_protocol
}
fn span_processor(&self) -> &str {
&self.span_processor
}
fn traces_sampler(&self) -> &str {
&self.traces_sampler
}
fn traces_sampler_arg(&self) -> &str {
&self.traces_sampler_arg
}
}
#[cfg(test)]
#[allow(
clippy::expect_used,
clippy::unwrap_used,
reason = "test code — panics are acceptable failures"
)]
mod tests {
use super::*;
use std::sync::Mutex;
static ENV_LOCK: Mutex<()> = Mutex::new(());
fn clear_otel_env() {
for key in [
"COGNEE_TRACING_ENABLED",
"OTEL_SERVICE_NAME",
"OTEL_EXPORTER_OTLP_ENDPOINT",
"OTEL_EXPORTER_OTLP_HEADERS",
"OTEL_EXPORTER_OTLP_PROTOCOL",
"OTEL_SPAN_PROCESSOR",
"OTEL_TRACES_SAMPLER",
"OTEL_TRACES_SAMPLER_ARG",
] {
unsafe { std::env::remove_var(key) };
}
}
#[test]
fn from_env_empty_matches_defaults() {
let _g = ENV_LOCK.lock().expect("env lock poisoned");
clear_otel_env();
let view = EnvSettingsView::from_env();
assert!(!view.tracing_enabled());
assert_eq!(view.service_name(), DEFAULT_SERVICE_NAME);
assert_eq!(view.otlp_endpoint(), DEFAULT_OTLP_ENDPOINT);
assert_eq!(view.otlp_headers(), DEFAULT_OTLP_HEADERS);
assert_eq!(view.otlp_protocol(), DEFAULT_OTLP_PROTOCOL);
assert_eq!(view.span_processor(), DEFAULT_SPAN_PROCESSOR);
assert_eq!(view.traces_sampler(), DEFAULT_TRACES_SAMPLER);
assert_eq!(view.traces_sampler_arg(), DEFAULT_TRACES_SAMPLER_ARG);
}
#[test]
fn tracing_enabled_truthy_values() {
let _g = ENV_LOCK.lock().expect("env lock poisoned");
for v in ["true", "TRUE", "1", "yes", "YES"] {
clear_otel_env();
unsafe { std::env::set_var("COGNEE_TRACING_ENABLED", v) };
let view = EnvSettingsView::from_env();
assert!(view.tracing_enabled(), "{v} should enable tracing");
}
}
#[test]
fn tracing_enabled_falsy_values() {
let _g = ENV_LOCK.lock().expect("env lock poisoned");
for v in ["false", "0", "no", "off", "anything-else"] {
clear_otel_env();
unsafe { std::env::set_var("COGNEE_TRACING_ENABLED", v) };
let view = EnvSettingsView::from_env();
assert!(!view.tracing_enabled(), "{v} should not enable tracing");
}
}
#[test]
fn from_env_reads_all_fields() {
let _g = ENV_LOCK.lock().expect("env lock poisoned");
clear_otel_env();
unsafe {
std::env::set_var("COGNEE_TRACING_ENABLED", "true");
std::env::set_var("OTEL_SERVICE_NAME", "my-svc");
std::env::set_var("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector:4317");
std::env::set_var("OTEL_EXPORTER_OTLP_HEADERS", "x-key=val");
std::env::set_var("OTEL_EXPORTER_OTLP_PROTOCOL", "http/protobuf");
std::env::set_var("OTEL_SPAN_PROCESSOR", "simple");
std::env::set_var("OTEL_TRACES_SAMPLER", "traceidratio");
std::env::set_var("OTEL_TRACES_SAMPLER_ARG", "0.5");
}
let view = EnvSettingsView::from_env();
assert!(view.tracing_enabled());
assert_eq!(view.service_name(), "my-svc");
assert_eq!(view.otlp_endpoint(), "http://collector:4317");
assert_eq!(view.otlp_headers(), "x-key=val");
assert_eq!(view.otlp_protocol(), "http/protobuf");
assert_eq!(view.span_processor(), "simple");
assert_eq!(view.traces_sampler(), "traceidratio");
assert_eq!(view.traces_sampler_arg(), "0.5");
clear_otel_env();
}
}