Add multi-destination logging: syslog and file support

Implement logging infrastructure for non-systemd platforms:

- Add src/logging.rs with syslog and file logging support
- New CLI flags: --syslog, --log-file, --log-file-daily
- Syslog uses libc directly with LOG_DAEMON facility
- File logging via tracing-appender with optional daily rotation

Update service scripts:
- OpenRC and FreeBSD rc.d now use --syslog by default
- Ensures logs are captured on platforms without journald

Default (stderr) behavior unchanged for systemd compatibility.
Log destination is selected at startup based on CLI flags.

Signed-off-by: Vladimir Krivopalov <argenet@yandex.ru>
This commit is contained in:
Vladimir Krivopalov
2026-03-20 22:26:42 +02:00
committed by Vladimir Krivopalov
parent 909714af31
commit 95685adba7
7 changed files with 359 additions and 12 deletions

View File

@@ -8,6 +8,7 @@ use tracing::{debug, error, info, warn};
use crate::cli;
use crate::config::ProxyConfig;
use crate::logging::LogDestination;
use crate::transport::middle_proxy::{
ProxyConfigData, fetch_proxy_config_with_raw, load_proxy_config_cache, save_proxy_config_cache,
};
@@ -31,6 +32,7 @@ pub(crate) struct CliArgs {
pub data_path: Option<PathBuf>,
pub silent: bool,
pub log_level: Option<String>,
pub log_destination: LogDestination,
}
pub(crate) fn parse_cli() -> CliArgs {
@@ -41,6 +43,9 @@ pub(crate) fn parse_cli() -> CliArgs {
let args: Vec<String> = std::env::args().skip(1).collect();
// Parse log destination
let log_destination = crate::logging::parse_log_destination(&args);
// Check for --init first (handled before tokio)
if let Some(init_opts) = cli::parse_init_args(&args) {
if let Err(e) = cli::run_init(init_opts) {
@@ -124,6 +129,7 @@ pub(crate) fn parse_cli() -> CliArgs {
data_path,
silent,
log_level,
log_destination,
}
}
@@ -147,6 +153,12 @@ fn print_help() {
eprintln!(" --help, -h Show this help");
eprintln!(" --version, -V Show version");
eprintln!();
eprintln!("Logging options:");
eprintln!(" --log-file <PATH> Log to file (default: stderr)");
eprintln!(" --log-file-daily <PATH> Log to file with daily rotation");
#[cfg(unix)]
eprintln!(" --syslog Log to syslog (Unix only)");
eprintln!();
#[cfg(unix)]
{
eprintln!("Daemon options (Unix only):");

View File

@@ -114,6 +114,7 @@ async fn run_inner(
let data_path = cli_args.data_path;
let cli_silent = cli_args.silent;
let cli_log_level = cli_args.log_level;
let log_destination = cli_args.log_destination;
let startup_cwd = match std::env::current_dir() {
Ok(cwd) => cwd,
Err(e) => {
@@ -213,17 +214,43 @@ async fn run_inner(
)
.await;
// Configure color output based on config
let fmt_layer = if config.general.disable_colors {
fmt::Layer::default().with_ansi(false)
} else {
fmt::Layer::default().with_ansi(true)
};
// Initialize logging based on destination
let _logging_guard: Option<crate::logging::LoggingGuard>;
match log_destination {
crate::logging::LogDestination::Stderr => {
// Default: log to stderr (works with systemd journald)
let fmt_layer = if config.general.disable_colors {
fmt::Layer::default().with_ansi(false)
} else {
fmt::Layer::default().with_ansi(true)
};
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.init();
_logging_guard = None;
}
#[cfg(unix)]
crate::logging::LogDestination::Syslog => {
// Syslog: for OpenRC/FreeBSD
let logging_opts = crate::logging::LoggingOptions {
destination: log_destination,
disable_colors: true,
};
let (_, guard) = crate::logging::init_logging(&logging_opts, "info");
_logging_guard = Some(guard);
}
crate::logging::LogDestination::File { .. } => {
// File logging with optional rotation
let logging_opts = crate::logging::LoggingOptions {
destination: log_destination,
disable_colors: true,
};
let (_, guard) = crate::logging::init_logging(&logging_opts, "info");
_logging_guard = Some(guard);
}
}
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.init();
startup_tracker
.complete_component(
COMPONENT_TRACING_INIT,