Establish config loading and logging infrastructure

First working milestone of the Rust rewrite. Implements the two
foundational systems every other component depends on:

- TOML-based layered config (beds.toml + env.toml override) replacing
  the PHP XML config system, fully deserialized into typed structs via
  serde — no runtime string key lookups, shape enforced at compile time
- Structured logging via tracing + tracing-journald, with optional
  console mirror, initialized from config before any services start

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-30 12:33:52 -07:00
parent bb6df8314c
commit 22c74b2671
8 changed files with 934 additions and 1 deletions

19
src/config/mod.rs Normal file
View File

@@ -0,0 +1,19 @@
mod structs;
pub use structs::BedsConfig;
use config::{Config, File, FileFormat};
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("Failed to load configuration: {0}")]
LoadError(#[from] config::ConfigError),
}
pub fn load() -> Result<BedsConfig, ConfigError> {
let cfg = Config::builder()
.add_source(File::new("config/beds.toml", FileFormat::Toml))
.add_source(File::new("config/env.toml", FileFormat::Toml).required(false))
.build()?;
Ok(cfg.try_deserialize()?)
}

50
src/config/structs.rs Normal file
View File

@@ -0,0 +1,50 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct BedsConfig {
pub id: IdConfig,
pub debug: bool,
pub syslog: bool,
pub syslog_mirror_console: bool,
pub audit_on: bool,
pub journal_on: bool,
pub broker_services: BrokerServicesConfig,
}
#[derive(Debug, Deserialize)]
pub struct IdConfig {
pub env_name: String,
pub version: String,
pub wbid: String,
}
#[derive(Debug, Deserialize)]
pub struct BrokerServicesConfig {
pub queue_tag : String,
pub vhost: String,
pub timer_violation: u32,
pub records_per_xfer: u32,
pub keepalive: bool,
pub heartbeat: u32,
pub use_ssl: bool,
pub cert_path: String,
pub app_server: BrokerNodeConfig,
}
#[derive(Debug, Deserialize)]
pub struct BrokerNodeConfig {
pub host: String,
pub port: u16,
pub api_port: Option<u16>,
pub user: String,
pub pass: String,
pub rpi: u32,
pub instances: BrokerInstancesConfig,
}
#[derive(Debug, Deserialize)]
pub struct BrokerInstancesConfig {
pub r_broker: u32,
pub w_broker: u32,
pub m_broker: u32,
}

26
src/logging.rs Normal file
View File

@@ -0,0 +1,26 @@
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
pub fn init_from_config(syslog: bool, mirror_console: bool) {
let registry = tracing_subscriber::registry()
.with(EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("info")));
let journald_layer = if syslog {
tracing_journald::layer().ok()
} else {
None
};
let console_layer = if !syslog || mirror_console {
Some(tracing_subscriber::fmt::layer()
.with_target(false)
.compact())
}else {
None
};
registry
.with(journald_layer)
.with(console_layer)
.init();
}

View File

@@ -1,3 +1,10 @@
mod config;
mod logging;
fn main() {
println!("Hello, world!");
let cfg = config::load().expect("Failed to load config");
logging::init_from_config(cfg.syslog, cfg.syslog_mirror_console);
tracing::info!("BEDS starting, env={}", cfg.id.env_name);
tracing::info!("Logging initialized");
}