use std::str::FromStr;
use std::time::Duration;
use anyhow::anyhow;
use mz_dyncfg::{Config, ConfigSet, ConfigUpdates};
use mz_tracing::params::TracingParameters;
use mz_tracing::{CloneableEnvFilter, SerializableDirective};
use tracing_subscriber::filter::Directive;
pub const SIGTERM_WAIT: Config<Duration> = Config::new(
"balancerd_sigterm_wait",
Duration::from_secs(60 * 10),
"Duration to wait after SIGTERM for outstanding connections to complete.",
);
pub const INJECT_PROXY_PROTOCOL_HEADER_HTTP: Config<bool> = Config::new(
"balancerd_inject_proxy_protocol_header_http",
false,
"Whether to inject tcp proxy protocol headers to downstream http servers.",
);
pub const LOGGING_FILTER: Config<&str> = Config::new(
"balancerd_log_filter",
"info",
"Sets the filter to apply to stderr logging.",
);
pub const OPENTELEMETRY_FILTER: Config<&str> = Config::new(
"balancerd_opentelemetry_filter",
"info",
"Sets the filter to apply to OpenTelemetry-backed distributed tracing.",
);
pub const LOGGING_FILTER_DEFAULTS: Config<fn() -> String> = Config::new(
"balancerd_log_filter_defaults",
|| mz_ore::tracing::LOGGING_DEFAULTS_STR.join(","),
"Sets additional default directives to apply to stderr logging. \
These apply to all variations of `log_filter`. Directives other than \
`module=off` are likely incorrect. Comma separated list.",
);
pub const OPENTELEMETRY_FILTER_DEFAULTS: Config<fn() -> String> = Config::new(
"balancerd_opentelemetry_filter_defaults",
|| mz_ore::tracing::OPENTELEMETRY_DEFAULTS_STR.join(","),
"Sets additional default directives to apply to OpenTelemetry-backed \
distributed tracing. \
These apply to all variations of `opentelemetry_filter`. Directives other than \
`module=off` are likely incorrect. Comma separated list.",
);
pub const SENTRY_FILTERS: Config<fn() -> String> = Config::new(
"balancerd_sentry_filters",
|| mz_ore::tracing::SENTRY_DEFAULTS_STR.join(","),
"Sets additional default directives to apply to sentry logging. \
These apply on top of a default `info` directive. Directives other than \
`module=off` are likely incorrect. Comma separated list.",
);
pub fn all_dyncfgs(configs: ConfigSet) -> ConfigSet {
configs
.add(&SIGTERM_WAIT)
.add(&INJECT_PROXY_PROTOCOL_HEADER_HTTP)
.add(&LOGGING_FILTER)
.add(&OPENTELEMETRY_FILTER)
.add(&LOGGING_FILTER_DEFAULTS)
.add(&OPENTELEMETRY_FILTER_DEFAULTS)
.add(&SENTRY_FILTERS)
}
pub(crate) fn set_defaults(
config_set: &ConfigSet,
default_config: Vec<(String, String)>,
) -> Result<(), anyhow::Error> {
let mut config_updates = ConfigUpdates::default();
for (k, v) in default_config.iter() {
if k.as_str() == INJECT_PROXY_PROTOCOL_HEADER_HTTP.name() {
config_updates.add_dynamic(
INJECT_PROXY_PROTOCOL_HEADER_HTTP.name(),
mz_dyncfg::ConfigVal::Bool(bool::from_str(v)?),
)
} else {
return Err(anyhow!("Invalid default config value {k}"));
}
}
config_updates.apply(config_set);
Ok(())
}
pub fn tracing_config(configs: &ConfigSet) -> Result<TracingParameters, String> {
fn to_serializable_directives(
config: &Config<fn() -> String>,
configs: &ConfigSet,
) -> Result<Vec<SerializableDirective>, String> {
let directives = config.get(configs);
let directives: Vec<_> = directives
.split(',')
.map(Directive::from_str)
.collect::<Result<_, _>>()
.map_err(|e| e.to_string())?;
Ok(directives.into_iter().map(|d| d.into()).collect())
}
let log_filter = LOGGING_FILTER.get(configs);
let log_filter = CloneableEnvFilter::from_str(&log_filter).map_err(|e| e.to_string())?;
let opentelemetry_filter = OPENTELEMETRY_FILTER.get(configs);
let opentelemetry_filter =
CloneableEnvFilter::from_str(&opentelemetry_filter).map_err(|e| e.to_string())?;
let log_filter_defaults = to_serializable_directives(&LOGGING_FILTER_DEFAULTS, configs)?;
let opentelemetry_filter_defaults =
to_serializable_directives(&OPENTELEMETRY_FILTER_DEFAULTS, configs)?;
let sentry_filters = to_serializable_directives(&SENTRY_FILTERS, configs)?;
Ok(TracingParameters {
log_filter: Some(log_filter),
opentelemetry_filter: Some(opentelemetry_filter),
log_filter_defaults,
opentelemetry_filter_defaults,
sentry_filters,
})
}
pub fn has_tracing_config_update(updates: &ConfigUpdates) -> bool {
[
LOGGING_FILTER.name(),
OPENTELEMETRY_FILTER.name(),
LOGGING_FILTER_DEFAULTS.name(),
OPENTELEMETRY_FILTER_DEFAULTS.name(),
SENTRY_FILTERS.name(),
]
.into_iter()
.any(|name| updates.updates.contains_key(name))
}