Skip to main content

mz_balancerd/
dyncfgs.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Dyncfgs used by the balancer.
11
12use std::str::FromStr;
13use std::time::Duration;
14
15use anyhow::anyhow;
16use mz_dyncfg::{Config, ConfigSet, ConfigUpdates, ParameterScope};
17use mz_tracing::params::TracingParameters;
18use mz_tracing::{CloneableEnvFilter, SerializableDirective};
19use tracing_subscriber::filter::Directive;
20
21// The defaults here must be set to an appropriate value in case LaunchDarkly is down because we
22// continue startup even in that case.
23//
24// All configuration names should be prefixed with "balancerd_" to avoid name collisions.
25/// Duration to wait after listeners closed via SIGTERM for outstanding connections to complete.
26pub const SIGTERM_CONNECTION_WAIT: Config<Duration> = Config::new(
27    "balancerd_sigterm_connection_wait",
28    Duration::from_secs(60 * 9),
29    "Duration to wait after listeners closed via SIGTERM for outstanding connections to complete.",
30    ParameterScope::Environment,
31);
32
33/// Duration to wait after SIGTERM to begin shutdown of servers.
34pub const SIGTERM_LISTEN_WAIT: Config<Duration> = Config::new(
35    "balancerd_sigterm_listen_wait",
36    Duration::from_secs(60),
37    "Duration to wait after SIGTERM to begin shutdown of servers.",
38    ParameterScope::Environment,
39);
40
41/// Whether to inject tcp proxy protocol headers to downstream http servers.
42pub const INJECT_PROXY_PROTOCOL_HEADER_HTTP: Config<bool> = Config::new(
43    "balancerd_inject_proxy_protocol_header_http",
44    false,
45    "Whether to inject tcp proxy protocol headers to downstream http servers.",
46    ParameterScope::Environment,
47);
48
49/// Sets the filter to apply to stderr logging.
50pub const LOGGING_FILTER: Config<&str> = Config::new(
51    "balancerd_log_filter",
52    "info",
53    "Sets the filter to apply to stderr logging.",
54    ParameterScope::Environment,
55);
56
57/// Sets the filter to apply to OpenTelemetry-backed distributed tracing.
58pub const OPENTELEMETRY_FILTER: Config<&str> = Config::new(
59    "balancerd_opentelemetry_filter",
60    "info",
61    "Sets the filter to apply to OpenTelemetry-backed distributed tracing.",
62    ParameterScope::Environment,
63);
64
65/// Sets additional default directives to apply to stderr logging.
66/// These apply to all variations of `log_filter`. Directives other than
67/// `module=off` are likely incorrect. Comma separated list.
68pub const LOGGING_FILTER_DEFAULTS: Config<fn() -> String> = Config::new(
69    "balancerd_log_filter_defaults",
70    || mz_ore::tracing::LOGGING_DEFAULTS_STR.join(","),
71    "Sets additional default directives to apply to stderr logging. \
72    These apply to all variations of `log_filter`. Directives other than \
73    `module=off` are likely incorrect. Comma separated list.",
74    ParameterScope::Environment,
75);
76
77/// Sets additional default directives to apply to OpenTelemetry-backed
78/// distributed tracing.
79/// These apply to all variations of `opentelemetry_filter`. Directives other than
80/// `module=off` are likely incorrect. Comma separated list.
81pub const OPENTELEMETRY_FILTER_DEFAULTS: Config<fn() -> String> = Config::new(
82    "balancerd_opentelemetry_filter_defaults",
83    || mz_ore::tracing::OPENTELEMETRY_DEFAULTS_STR.join(","),
84    "Sets additional default directives to apply to OpenTelemetry-backed \
85    distributed tracing. \
86    These apply to all variations of `opentelemetry_filter`. Directives other than \
87    `module=off` are likely incorrect. Comma separated list.",
88    ParameterScope::Environment,
89);
90
91/// Sets additional default directives to apply to sentry logging. \
92/// These apply on top of a default `info` directive. Directives other than \
93/// `module=off` are likely incorrect. Comma separated list.
94pub const SENTRY_FILTERS: Config<fn() -> String> = Config::new(
95    "balancerd_sentry_filters",
96    || mz_ore::tracing::SENTRY_DEFAULTS_STR.join(","),
97    "Sets additional default directives to apply to sentry logging. \
98    These apply on top of a default `info` directive. Directives other than \
99    `module=off` are likely incorrect. Comma separated list.",
100    ParameterScope::Environment,
101);
102
103/// Adds the full set of all balancer `Config`s.
104pub fn all_dyncfgs(configs: ConfigSet) -> ConfigSet {
105    configs
106        .add(&SIGTERM_CONNECTION_WAIT)
107        .add(&SIGTERM_LISTEN_WAIT)
108        .add(&INJECT_PROXY_PROTOCOL_HEADER_HTTP)
109        .add(&LOGGING_FILTER)
110        .add(&OPENTELEMETRY_FILTER)
111        .add(&LOGGING_FILTER_DEFAULTS)
112        .add(&OPENTELEMETRY_FILTER_DEFAULTS)
113        .add(&SENTRY_FILTERS)
114}
115
116/// Overrides default values for the Balancerd ConfigSet.
117///
118/// This is meant to be used in combination with clap cli flag
119/// `--default-config key=value`
120/// Not all ConfigSet values can be defaulted with this
121/// function. An error will be returned if a key does
122/// not accept default overrides, or if there is a value
123/// parsing error..
124pub(crate) fn set_defaults(
125    config_set: &ConfigSet,
126    default_config: Vec<(String, String)>,
127) -> Result<(), anyhow::Error> {
128    let mut config_updates = ConfigUpdates::default();
129    for (k, v) in default_config.iter() {
130        if k.as_str() == INJECT_PROXY_PROTOCOL_HEADER_HTTP.name() {
131            config_updates.add_dynamic(
132                INJECT_PROXY_PROTOCOL_HEADER_HTTP.name(),
133                mz_dyncfg::ConfigVal::Bool(bool::from_str(v)?),
134            )
135        } else {
136            return Err(anyhow!("Invalid default config value {k}"));
137        }
138    }
139    config_updates.apply(config_set);
140    Ok(())
141}
142
143/// Get all dynamic tracing config parameters from this [`ConfigSet`].
144pub fn tracing_config(configs: &ConfigSet) -> Result<TracingParameters, String> {
145    fn to_serializable_directives(
146        config: &Config<fn() -> String>,
147        configs: &ConfigSet,
148    ) -> Result<Vec<SerializableDirective>, String> {
149        let directives = config.get(configs);
150        let directives: Vec<_> = directives
151            .split(',')
152            .map(Directive::from_str)
153            .collect::<Result<_, _>>()
154            .map_err(|e| e.to_string())?;
155        Ok(directives.into_iter().map(|d| d.into()).collect())
156    }
157
158    let log_filter = LOGGING_FILTER.get(configs);
159    let log_filter = CloneableEnvFilter::from_str(&log_filter).map_err(|e| e.to_string())?;
160
161    let opentelemetry_filter = OPENTELEMETRY_FILTER.get(configs);
162    let opentelemetry_filter =
163        CloneableEnvFilter::from_str(&opentelemetry_filter).map_err(|e| e.to_string())?;
164
165    let log_filter_defaults = to_serializable_directives(&LOGGING_FILTER_DEFAULTS, configs)?;
166
167    let opentelemetry_filter_defaults =
168        to_serializable_directives(&OPENTELEMETRY_FILTER_DEFAULTS, configs)?;
169
170    let sentry_filters = to_serializable_directives(&SENTRY_FILTERS, configs)?;
171
172    Ok(TracingParameters {
173        log_filter: Some(log_filter),
174        opentelemetry_filter: Some(opentelemetry_filter),
175        log_filter_defaults,
176        opentelemetry_filter_defaults,
177        sentry_filters,
178    })
179}
180
181/// Returns true if `updates` contains an update to a tracing config, false otherwise.
182pub fn has_tracing_config_update(updates: &ConfigUpdates) -> bool {
183    [
184        LOGGING_FILTER.name(),
185        OPENTELEMETRY_FILTER.name(),
186        LOGGING_FILTER_DEFAULTS.name(),
187        OPENTELEMETRY_FILTER_DEFAULTS.name(),
188        SENTRY_FILTERS.name(),
189    ]
190    .into_iter()
191    .any(|name| updates.updates.contains_key(name))
192}