witchcraft_server_config/runtime/
mod.rs1use crate::ConfigError;
16use conjure_runtime_config::ServicesConfig;
17use serde::de::Error;
18use serde::{Deserialize, Deserializer};
19use staged_builder::{staged_builder, Validate};
20use std::collections::HashMap;
21use witchcraft_log::LevelFilter;
22
23mod de;
24
25#[derive(Clone, PartialEq, Debug)]
27#[staged_builder]
28pub struct RuntimeConfig {
29 diagnostics: DiagnosticsConfig,
30 health_checks: HealthChecksConfig,
31 #[builder(default)]
32 logging: LoggingConfig,
33 #[builder(default)]
34 service_discovery: ServicesConfig,
35}
36
37impl<'de> Deserialize<'de> for RuntimeConfig {
38 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
39 where
40 D: Deserializer<'de>,
41 {
42 let raw = de::RuntimeConfig::deserialize(deserializer)?;
43 let mut builder = RuntimeConfig::builder()
44 .diagnostics(raw.diagnostics)
45 .health_checks(raw.health_checks);
46 if let Some(logging) = raw.logging {
47 builder = builder.logging(logging);
48 }
49 if let Some(service_discovery) = raw.service_discovery {
50 builder = builder.service_discovery(service_discovery);
51 }
52
53 Ok(builder.build())
54 }
55}
56
57impl AsRef<RuntimeConfig> for RuntimeConfig {
58 #[inline]
59 fn as_ref(&self) -> &RuntimeConfig {
60 self
61 }
62}
63
64impl RuntimeConfig {
65 #[inline]
69 pub fn diagnostics(&self) -> &DiagnosticsConfig {
70 &self.diagnostics
71 }
72
73 #[inline]
77 pub fn health_checks(&self) -> &HealthChecksConfig {
78 &self.health_checks
79 }
80
81 #[inline]
83 pub fn logging(&self) -> &LoggingConfig {
84 &self.logging
85 }
86
87 #[inline]
89 pub fn service_discovery(&self) -> &ServicesConfig {
90 &self.service_discovery
91 }
92}
93
94#[derive(Clone, PartialEq, Debug)]
96#[staged_builder]
97pub struct DiagnosticsConfig {
98 #[builder(into)]
99 debug_shared_secret: String,
100 #[builder(default)]
101 jemalloc: JemallocConfig,
102}
103
104impl<'de> Deserialize<'de> for DiagnosticsConfig {
105 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
106 where
107 D: Deserializer<'de>,
108 {
109 let raw = de::DiagnosticsConfig::deserialize(deserializer)?;
110 let mut builder = DiagnosticsConfig::builder().debug_shared_secret(raw.debug_shared_secret);
111 if let Some(jemalloc) = raw.jemalloc {
112 builder = builder.jemalloc(jemalloc);
113 }
114
115 Ok(builder.build())
116 }
117}
118
119impl DiagnosticsConfig {
120 #[inline]
124 pub fn debug_shared_secret(&self) -> &str {
125 &self.debug_shared_secret
126 }
127
128 #[inline]
130 pub fn jemalloc(&self) -> &JemallocConfig {
131 &self.jemalloc
132 }
133}
134
135#[derive(Clone, PartialEq, Debug)]
137#[staged_builder]
138pub struct JemallocConfig {
139 #[builder(default = false)]
140 prof_active: bool,
141 #[builder(default = 19)]
142 lg_prof_sample: usize,
143}
144
145impl Default for JemallocConfig {
146 #[inline]
147 fn default() -> Self {
148 JemallocConfig::builder().build()
149 }
150}
151
152impl<'de> Deserialize<'de> for JemallocConfig {
153 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
154 where
155 D: Deserializer<'de>,
156 {
157 let raw = de::JemallocConfig::deserialize(deserializer)?;
158 let mut builder = JemallocConfig::builder();
159
160 if let Some(prof_active) = raw.prof_active {
161 builder = builder.prof_active(prof_active);
162 }
163 if let Some(lg_prof_sample) = raw.lg_prof_sample {
164 builder = builder.lg_prof_sample(lg_prof_sample);
165 }
166
167 Ok(builder.build())
168 }
169}
170
171impl JemallocConfig {
172 #[inline]
178 pub fn prof_active(&self) -> bool {
179 self.prof_active
180 }
181
182 #[inline]
189 pub fn lg_prof_sample(&self) -> usize {
190 self.lg_prof_sample
191 }
192}
193
194#[derive(Clone, PartialEq, Debug)]
196#[staged_builder]
197pub struct HealthChecksConfig {
198 #[builder(into)]
199 shared_secret: String,
200}
201
202impl<'de> Deserialize<'de> for HealthChecksConfig {
203 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
204 where
205 D: Deserializer<'de>,
206 {
207 let raw = de::HealthChecksConfig::deserialize(deserializer)?;
208 let builder = HealthChecksConfig::builder().shared_secret(raw.shared_secret);
209
210 Ok(builder.build())
211 }
212}
213
214impl HealthChecksConfig {
215 #[inline]
217 pub fn shared_secret(&self) -> &str {
218 &self.shared_secret
219 }
220}
221
222#[derive(Clone, PartialEq, Debug)]
224#[staged_builder]
225#[builder(validate)]
226pub struct LoggingConfig {
227 #[builder(default = LevelFilter::Info)]
228 level: LevelFilter,
229 #[builder(map(key(type = String, into), value(type = LevelFilter)))]
230 loggers: HashMap<String, LevelFilter>,
231 #[builder(default = 0.0005)]
232 trace_rate: f32,
233}
234
235impl Validate for LoggingConfig {
236 type Error = ConfigError;
237
238 fn validate(&self) -> Result<(), Self::Error> {
239 if !(0.0..=1.0).contains(&self.trace_rate()) {
240 return Err(ConfigError(
241 "trace-rate must be between 0 and 1, inclusive".to_string(),
242 ));
243 }
244
245 Ok(())
246 }
247}
248
249impl<'de> Deserialize<'de> for LoggingConfig {
250 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
251 where
252 D: Deserializer<'de>,
253 {
254 let raw = de::LoggingConfig::deserialize(deserializer)?;
255 let mut builder = LoggingConfig::builder();
256 if let Some(level) = raw.level {
257 builder = builder.level(level);
258 }
259 if let Some(loggers) = raw.loggers {
260 builder = builder.loggers(loggers);
261 }
262 if let Some(trace_rate) = raw.trace_rate {
263 builder = builder.trace_rate(trace_rate);
264 }
265
266 builder.build().map_err(Error::custom)
267 }
268}
269
270impl Default for LoggingConfig {
271 #[inline]
272 fn default() -> Self {
273 LoggingConfig::builder().build().unwrap()
274 }
275}
276
277impl LoggingConfig {
278 #[inline]
282 pub fn level(&self) -> LevelFilter {
283 self.level
284 }
285
286 #[inline]
288 pub fn loggers(&self) -> &HashMap<String, LevelFilter> {
289 &self.loggers
290 }
291
292 #[inline]
299 pub fn trace_rate(&self) -> f32 {
300 self.trace_rate
301 }
302}